Lower and generate some C++

This commit is contained in:
Olivier Goffart 2020-05-05 18:22:16 +02:00
parent bfac827ec7
commit acccb33c8c
9 changed files with 250 additions and 27 deletions

View file

@ -0,0 +1,5 @@
mod cpp;
pub fn generate(component: &crate::lower::LoweredComponent) {
println!("{}", cpp::generate(component));
}

View 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
}

View file

@ -1,4 +1,6 @@
pub mod diagnostics;
pub mod generator;
pub mod lower;
pub mod object_tree;
pub mod parser;

View 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![],
}
}
}

View file

@ -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(())
}

View file

@ -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 {

View file

@ -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} })
}
"#
"#
*/

View file

@ -1,4 +1,6 @@
pub mod datastructures;
pub mod graphics;
pub mod primitives;
#[cfg(test)]
mod tests {

View 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,
};