Implement property declarations for the C++ backend

This commit is contained in:
Simon Hausmann 2020-05-25 19:13:52 +02:00
parent 5a7a95dbc8
commit 0932953ac8
4 changed files with 88 additions and 13 deletions

View file

@ -77,7 +77,8 @@ Hello := Rectangle {
color: black;
}
}
counter := Text { x: 100; y: 300; text: "0"; color: black; }
property<int32> counter;
counter_label := Text { x: 100; y: 300; text: "0"; color: black; }
ButtonRectangle {
color: 4289374890;
x: 50;

View file

@ -4,24 +4,24 @@
int main() {
static Hello component;
static int counter = 0;
component._foobar.set_handler([](auto...){
std::cout << "Hello from C++" << std::endl;
});
component._plus_clicked.set_handler([](auto...){
counter += 1;
auto &counter = component.property_0_counter;
counter.set(counter.get() + 1);
// FIXME: this _13 is an internal detail and should be private anyway. We muse use some
// alias or way to expose the property (same for the _ before signals)
component.counter_13.text.set(std::string_view(std::to_string(counter)));
std::cout << "PLUS: " << std::string_view(component.counter_13.text.get()) << std::endl;
component.counter_label_13.text.set(std::string_view(std::to_string(counter.get())));
std::cout << "PLUS: " << std::string_view(component.counter_label_13.text.get()) << std::endl;
});
component._minus_clicked.set_handler([](auto...){
counter -= 1;
component.counter_13.text.set(std::string_view(std::to_string(counter)));
std::cout << "MINUS: " << std::string_view(component.counter_13.text.get()) << std::endl;
auto &counter = component.property_0_counter;
counter.set(counter.get() - 1);
component.counter_label_13.text.set(std::string_view(std::to_string(counter.get())));
std::cout << "MINUS: " << std::string_view(component.counter_label_13.text.get()) << std::endl;
});
sixtyfps::run(&component);

View file

@ -121,12 +121,35 @@ mod cpp_ast {
writeln!(f, ";")
}
}
pub trait CppType {
fn cpp_type(&self) -> Option<&str>;
}
}
use crate::lower::{LoweredComponent, LoweredItem};
use crate::typeregister::Type;
use cpp_ast::*;
fn handle_item(item: &LoweredItem, main_struct: &mut Struct, init: &mut Vec<String>) {
impl CppType for Type {
fn cpp_type(&self) -> Option<&str> {
match self {
Type::Float32 => Some("float"),
Type::Int32 => Some("int"),
Type::String => Some("sixtyfps::SharedString"),
Type::Color => Some("uint32_t"),
Type::Bool => Some("bool"),
_ => None,
}
}
}
fn handle_item(
item: &LoweredItem,
global_properties: &Vec<String>,
main_struct: &mut Struct,
init: &mut Vec<String>,
) {
main_struct.members.push(Declaration::Var(Var {
ty: format!("sixtyfps::{}", item.native_type.class_name),
name: item.id.clone(),
@ -135,13 +158,19 @@ fn handle_item(item: &LoweredItem, main_struct: &mut Struct, init: &mut Vec<Stri
let id = &item.id;
init.extend(item.init_properties.iter().map(|(s, i)| {
let cpp_prop = item
.property_declarations
.get(s)
.map(|idx| global_properties[*idx].clone())
.unwrap_or_else(|| format!("{id}.{prop}", id = id, prop = s.clone()));
use crate::expression_tree::Expression::*;
let init = match &i {
StringLiteral(s) => format!(r#"sixtyfps::SharedString("{}")"#, s.escape_default()),
NumberLiteral(n) => n.to_string(),
_ => format!("\n#error: unsupported expression {:?}\n", i),
};
format!("{id}.{prop}.set({init});", id = id, prop = s, init = init)
format!("{cpp_prop}.set({init});", cpp_prop = cpp_prop, init = init)
}));
init.extend(item.connect_signals.iter().map(|(s, fwd)| {
format!(
@ -151,7 +180,7 @@ fn handle_item(item: &LoweredItem, main_struct: &mut Struct, init: &mut Vec<Stri
}));
for i in &item.children {
handle_item(i, main_struct, init)
handle_item(i, global_properties, main_struct, init)
}
}
@ -163,8 +192,31 @@ pub fn generate(component: &LoweredComponent) -> impl std::fmt::Display {
let mut main_struct = Struct { name: component.id.clone(), ..Default::default() };
let (declared_property_members, declared_property_vars): (Vec<String>, Vec<Declaration>) =
component
.property_declarations
.iter()
.enumerate()
.map(|(index, property)| {
let cpp_name: String = format!("property_{}_{}", index, property.name_hint).into();
(
cpp_name.clone(),
Declaration::Var(Var {
ty: format!(
"sixtyfps::Property<{}>",
property.property_type.cpp_type().expect("cannot convert type to C++")
),
name: cpp_name,
init: None,
}),
)
})
.unzip();
main_struct.members.extend(declared_property_vars);
let mut init = Vec::new();
handle_item(&component.root_item, &mut main_struct, &mut init);
handle_item(&component.root_item, &declared_property_members, &mut main_struct, &mut init);
main_struct.members.extend(component.signals_declarations.iter().map(|s| {
Declaration::Var(Var { ty: "sixtyfps::Signal".into(), name: s.clone(), init: None })

View file

@ -15,6 +15,8 @@ pub struct NativeItemType {
pub class_name: String,
}
pub type LoweredPropertyDeclarationIndex = usize;
#[derive(Default, Debug)]
pub struct LoweredItem {
pub id: String,
@ -22,6 +24,7 @@ pub struct LoweredItem {
pub init_properties: HashMap<String, Expression>,
/// Right now we only allow forwarding and this connect with the signal in the root
pub connect_signals: HashMap<String, String>,
pub property_declarations: HashMap<String, LoweredPropertyDeclarationIndex>,
pub children: Vec<LoweredItem>,
}
@ -31,6 +34,7 @@ pub struct LoweredComponent {
pub root_item: LoweredItem,
pub signals_declarations: Vec<String>,
pub property_declarations: Vec<LoweredPropertyDeclaration>,
}
impl LoweredComponent {
@ -40,6 +44,7 @@ impl LoweredComponent {
id: component.id.clone(),
root_item: LoweredComponent::lower_item(&*component.root_element.borrow(), &mut state),
signals_declarations: state.signals,
property_declarations: state.property_declarations,
}
}
@ -72,6 +77,16 @@ impl LoweredComponent {
let current_component_id = state.current_component_id.clone();
let format_signal = |name| format!("{}_{}", current_component_id, name);
state.signals.extend(element.signals_declaration.iter().map(format_signal));
for (prop_name, property_type) in element.property_declarations.iter() {
let component_global_index = state.property_declarations.len();
lowered.property_declarations.insert(prop_name.clone(), component_global_index);
state.property_declarations.push(LoweredPropertyDeclaration {
property_type: property_type.clone(),
name_hint: prop_name.clone(),
});
}
for (k, e) in element.bindings.iter() {
if let Expression::SignalReference { name, .. } = e {
lowered.connect_signals.insert(
@ -89,6 +104,12 @@ impl LoweredComponent {
}
}
#[derive(Debug)]
pub struct LoweredPropertyDeclaration {
pub property_type: Type,
pub name_hint: String,
}
#[derive(Default)]
struct LowererState {
/// The count of item to create the ids
@ -97,4 +118,5 @@ struct LowererState {
current_component_id: String,
signals: Vec<String>,
property_declarations: Vec<LoweredPropertyDeclaration>,
}