mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-03 15:14:35 +00:00
Lower and generate some C++
This commit is contained in:
parent
bfac827ec7
commit
acccb33c8c
9 changed files with 250 additions and 27 deletions
5
sixtyfps_compiler/generator.rs
Normal file
5
sixtyfps_compiler/generator.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod cpp;
|
||||
|
||||
pub fn generate(component: &crate::lower::LoweredComponent) {
|
||||
println!("{}", cpp::generate(component));
|
||||
}
|
134
sixtyfps_compiler/generator/cpp.rs
Normal file
134
sixtyfps_compiler/generator/cpp.rs
Normal file
|
@ -0,0 +1,134 @@
|
|||
mod cpp_ast {
|
||||
|
||||
use std::fmt::{Display, Error, Formatter};
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct File {
|
||||
pub includes: Vec<String>,
|
||||
pub declarations: Vec<Declaration>,
|
||||
}
|
||||
|
||||
impl Display for File {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||
for i in &self.includes {
|
||||
writeln!(f, "#include {}", i)?;
|
||||
}
|
||||
for d in &self.declarations {
|
||||
write!(f, "\n{}", d)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum Declaration {
|
||||
Struct(Struct),
|
||||
Function(Function),
|
||||
Var(Var),
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Struct {
|
||||
pub name: String,
|
||||
pub members: Vec<Declaration>,
|
||||
}
|
||||
|
||||
impl Display for Struct {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||
writeln!(f, "struct {} {{", self.name)?;
|
||||
for m in &self.members {
|
||||
// FIXME! identation
|
||||
write!(f, "{}", m)?;
|
||||
}
|
||||
writeln!(f, "}};")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Function {
|
||||
pub name: String,
|
||||
/// (...) -> ...
|
||||
pub signature: String,
|
||||
pub is_constructor: bool,
|
||||
pub statements: Vec<String>,
|
||||
}
|
||||
|
||||
impl Display for Function {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||
if !self.is_constructor {
|
||||
write!(f, "auto ")?;
|
||||
}
|
||||
writeln!(f, "{} {} {{", self.name, self.signature)?;
|
||||
for s in &self.statements {
|
||||
writeln!(f, " {}", s)?;
|
||||
}
|
||||
writeln!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Var {
|
||||
pub ty: String,
|
||||
pub name: String,
|
||||
pub init: Option<String>,
|
||||
}
|
||||
|
||||
impl Display for Var {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||
write!(f, "{} {}", self.ty, self.name)?;
|
||||
if let Some(i) = &self.init {
|
||||
write!(f, " = {}", i)?;
|
||||
}
|
||||
writeln!(f, ";")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate(component: &crate::lower::LoweredComponent) -> impl std::fmt::Display {
|
||||
use cpp_ast::*;
|
||||
let mut x = File::default();
|
||||
|
||||
x.includes.push("<sixtyfps.h>".into());
|
||||
|
||||
x.declarations.push(Declaration::Struct(Struct {
|
||||
name: component.id.clone(),
|
||||
members: vec![
|
||||
Declaration::Var(Var {
|
||||
ty: component.root_item.native_type.class_name.clone(),
|
||||
name: "root".to_owned(),
|
||||
..Default::default()
|
||||
}),
|
||||
Declaration::Function(Function {
|
||||
name: component.id.clone(),
|
||||
signature: "()".to_owned(),
|
||||
is_constructor: true,
|
||||
statements: component
|
||||
.root_item
|
||||
.init_properties
|
||||
.iter()
|
||||
.map(|(s, i)| format!("root.{} = \"{}\";", s, i))
|
||||
.collect(),
|
||||
}),
|
||||
],
|
||||
}));
|
||||
|
||||
x.declarations.push(Declaration::Var(Var {
|
||||
ty: "sixtyfps::ItemTreeNode".to_owned(),
|
||||
name: format!("{}_children[]", component.id),
|
||||
init: Some(format!(
|
||||
"{{ sixtyfps::ItemTreeNode{{0, &{}, 0, 0}} }}",
|
||||
component.root_item.native_type.vtable
|
||||
)),
|
||||
}));
|
||||
|
||||
x.declarations.push(Declaration::Function(Function {
|
||||
name: "main".into(),
|
||||
signature: "() -> int".to_owned(),
|
||||
is_constructor: false,
|
||||
statements: vec![
|
||||
format!("{} component;", component.id),
|
||||
format!("sixtyfps::run(&component, ComponentType{{ nullptr, nullptr, []{{return &{}_array }} }});", component.id),
|
||||
],
|
||||
}));
|
||||
x
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
pub mod diagnostics;
|
||||
pub mod generator;
|
||||
pub mod lower;
|
||||
pub mod object_tree;
|
||||
pub mod parser;
|
||||
|
||||
|
|
54
sixtyfps_compiler/lower.rs
Normal file
54
sixtyfps_compiler/lower.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
//! This module contains the code that lower the tree to the datastructure that that the runtime understand
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct NativeItemType {
|
||||
/*render_function: String,
|
||||
geometry_function: String,
|
||||
imput_function: String,*/
|
||||
/// The C symbol of the VTable
|
||||
pub vtable: String,
|
||||
|
||||
/// The class name
|
||||
pub class_name: String,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct LoweredItem {
|
||||
pub native_type: Rc<NativeItemType>,
|
||||
pub init_properties: HashMap<String, String>,
|
||||
pub children: Vec<LoweredItem>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct LoweredComponent {
|
||||
pub id: String,
|
||||
pub root_item: LoweredItem,
|
||||
}
|
||||
|
||||
impl LoweredComponent {
|
||||
pub fn lower(component: &crate::object_tree::Component) -> Self {
|
||||
LoweredComponent {
|
||||
id: component.id.clone(),
|
||||
root_item: LoweredComponent::lower_item(&*component.root_element),
|
||||
}
|
||||
}
|
||||
|
||||
fn lower_item(element: &crate::object_tree::Element) -> LoweredItem {
|
||||
// FIXME: lookup base instead of assuming
|
||||
let native_type = Rc::new(NativeItemType {
|
||||
vtable: format!("{}VTable", element.base),
|
||||
class_name: element.base.clone(),
|
||||
});
|
||||
LoweredItem {
|
||||
native_type,
|
||||
init_properties: element
|
||||
.bindings
|
||||
.iter()
|
||||
.map(|(s, c)| (s.clone(), c.value.clone()))
|
||||
.collect(),
|
||||
children: vec![],
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
use structopt::StructOpt;
|
||||
|
||||
mod diagnostics;
|
||||
mod generator;
|
||||
mod lower;
|
||||
mod object_tree;
|
||||
mod parser;
|
||||
|
||||
|
@ -14,9 +16,10 @@ struct Cli {
|
|||
fn main() -> std::io::Result<()> {
|
||||
let args = Cli::from_args();
|
||||
let source = std::fs::read_to_string(&args.path)?;
|
||||
let (res, mut diag) = parser::parse(&source);
|
||||
println!("{:#?}", res);
|
||||
println!("{:#?}", object_tree::Document::from_node(res, &mut diag));
|
||||
let (syntax_node, mut diag) = parser::parse(&source);
|
||||
//println!("{:#?}", syntax_node);
|
||||
let tree = object_tree::Document::from_node(syntax_node, &mut diag);
|
||||
//println!("{:#?}", tree);
|
||||
if !diag.inner.is_empty() {
|
||||
let mut codemap = codemap::CodeMap::new();
|
||||
let file = codemap.add_file(args.path.to_string_lossy().into_owned(), source);
|
||||
|
@ -45,6 +48,10 @@ fn main() -> std::io::Result<()> {
|
|||
Some(&codemap),
|
||||
);
|
||||
emitter.emit(&diags);
|
||||
std::process::exit(-1);
|
||||
}
|
||||
|
||||
let l = lower::LoweredComponent::lower(&*tree.root_component);
|
||||
generator::generate(&l);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::rc::Rc;
|
|||
#[derive(Default, Debug)]
|
||||
pub struct Document {
|
||||
// node: SyntaxNode,
|
||||
root_component: Rc<Component>,
|
||||
pub root_component: Rc<Component>,
|
||||
}
|
||||
|
||||
impl Document {
|
||||
|
@ -24,8 +24,8 @@ impl Document {
|
|||
#[derive(Default, Debug)]
|
||||
pub struct Component {
|
||||
// node: SyntaxNode,
|
||||
id: String,
|
||||
root_element: Rc<Element>,
|
||||
pub id: String,
|
||||
pub root_element: Rc<Element>,
|
||||
}
|
||||
|
||||
impl Component {
|
||||
|
@ -44,8 +44,8 @@ impl Component {
|
|||
#[derive(Default, Debug)]
|
||||
pub struct Element {
|
||||
// node: SyntaxNode,
|
||||
base: String,
|
||||
bindings: HashMap<String, CodeStatement>,
|
||||
pub base: String,
|
||||
pub bindings: HashMap<String, CodeStatement>,
|
||||
}
|
||||
|
||||
impl Element {
|
||||
|
@ -77,7 +77,7 @@ impl Element {
|
|||
#[derive(Default, Debug)]
|
||||
pub struct CodeStatement {
|
||||
// node: SyntaxNode,
|
||||
value: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
impl CodeStatement {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
type ComponentImpl = ();
|
||||
|
||||
#[repr(C)]
|
||||
struct ComponentType {
|
||||
pub struct ComponentType {
|
||||
/// Allocate an instance of this component
|
||||
create: fn(*const ComponentType) -> *mut ComponentImpl,
|
||||
|
||||
|
@ -25,15 +25,15 @@ type ItemImpl = ();
|
|||
// 64 | RenderNode | render node index
|
||||
|
||||
#[repr(C)]
|
||||
struct RenderNode {
|
||||
pub struct RenderNode {
|
||||
/// Used and modified by the backend, should be initialized to 0 by the user code
|
||||
cache_index: Cell<usize>,
|
||||
cache_index: core::cell::Cell<usize>,
|
||||
/// Set to true by the user code, and reset to false by the backend
|
||||
dirty_bit: Cell<bool>,
|
||||
dirty_bit: core::cell::Cell<bool>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct ItemTreeNode {
|
||||
pub struct ItemTreeNode {
|
||||
/// byte offset where we can find the item (from the *ComponentImpl)
|
||||
offset: isize,
|
||||
/// virtual table of the item
|
||||
|
@ -47,23 +47,23 @@ struct ItemTreeNode {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct ItemVTable {
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ItemVTable {
|
||||
// Rectangle: x/y/width/height ==> (path -> vertices/indicies(triangle))
|
||||
geometry: fn(*const ItemImpl) -> PrimitiveRectangle, // like kurbo::Rect
|
||||
pub geometry: Option<fn(*const ItemImpl) -> ()>, // like kurbo::Rect
|
||||
|
||||
// offset in bytes fromthe *const ItemImpl
|
||||
renderNodeIndexOffset: usize,
|
||||
pub render_node_index_offset: Option<usize>,
|
||||
// fn(*const ItemImpl) -> usize,
|
||||
|
||||
// ???
|
||||
rendering_info: Option<fn(*const ItemImpl) -> RenderingInfo>,
|
||||
pub rendering_info: Option<fn(*const ItemImpl) -> RenderingInfo>,
|
||||
|
||||
/// We would need max/min/preferred size, and all layout info
|
||||
layouting_info: Option<fn(*const ItemImpl) -> LayoutInfo>,
|
||||
pub layouting_info: Option<fn(*const ItemImpl) -> LayoutInfo>,
|
||||
|
||||
/// input event
|
||||
input_event: Option<fn(*const ItemImpl, MouseEvent)>,
|
||||
pub input_event: Option<fn(*const ItemImpl, MouseEvent)>,
|
||||
}
|
||||
|
||||
// given an ItemImpl & ItemVTable
|
||||
|
@ -71,20 +71,22 @@ struct ItemVTable {
|
|||
// (2) change the width
|
||||
|
||||
#[repr(C)]
|
||||
struct LayoutInfo {
|
||||
pub struct LayoutInfo {
|
||||
min_size: f32,
|
||||
//...
|
||||
width_offset: isize,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
enum RenderingInfo {
|
||||
pub enum RenderingInfo {
|
||||
NoContents,
|
||||
Path(Vec<PathElement>),
|
||||
/*Path(Vec<PathElement>),
|
||||
Image(OpaqueImageHandle, AspectRatio),
|
||||
Text(String)
|
||||
Text(String)*/
|
||||
}
|
||||
|
||||
type MouseEvent = ();
|
||||
/*
|
||||
|
||||
/*
|
||||
Button { visible: false; text: "foo"}
|
||||
|
@ -177,7 +179,7 @@ pub static RECTANGLE_VTABLE: ItemVTable = ItemVTable {
|
|||
//#[derive(SixtyFpsItem)]
|
||||
struct QtButton {
|
||||
text: String,
|
||||
is_pressed: bool,
|
||||
is_pressed: bool,
|
||||
}
|
||||
|
||||
|
||||
|
@ -210,4 +212,5 @@ main() {
|
|||
sixtyfps_runtime::run(&foo, ComponentType{ nullptr, nullptr, []{return array} })
|
||||
}
|
||||
|
||||
"#
|
||||
"#
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
pub mod datastructures;
|
||||
pub mod graphics;
|
||||
pub mod primitives;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
16
sixtyfps_runtime/corelib/primitives.rs
Normal file
16
sixtyfps_runtime/corelib/primitives.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
// FIXME: more properties
|
||||
#[repr(C)]
|
||||
pub struct Rectangle {
|
||||
// FIXME! this is not suppàosed to be a String
|
||||
color: &'static str,
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
// FIXME
|
||||
pub static RectangleVTable: crate::datastructures::ItemVTable = crate::datastructures::ItemVTable {
|
||||
geometry: None,
|
||||
render_node_index_offset: None,
|
||||
rendering_info: None,
|
||||
layouting_info: None,
|
||||
input_event: None,
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue