Normalize identifiers to - instead of _

As a result
 - The error messages will now show the error with `-` instead of `_`
 - The LSP will auto-complete with -
 - The interpreter's list of properties will list the property with '-'
   (but we made the change so that set_property, get_property, and so on
   work also if passed a '-')
This commit is contained in:
Olivier Goffart 2021-08-10 18:03:59 +02:00 committed by Olivier Goffart
parent 9c95da8a7c
commit c25538c982
49 changed files with 327 additions and 272 deletions

View file

@ -77,18 +77,18 @@ interface Callback {
require.extensions['.60'] = require.extensions['.60'] =
function (module, filename) { function (module, filename) {
var c = native.load(filename); var c = native.load(filename);
module.exports[c.name()] = function (init_properties: any) { module.exports[c.name().replaceAll('-', '_')] = function (init_properties: any) {
let comp = c.create(init_properties); let comp = c.create(init_properties);
let ret = new Component(comp); let ret = new Component(comp);
c.properties().forEach((x: string) => { c.properties().forEach((x: string) => {
Object.defineProperty(ret, x, { Object.defineProperty(ret, x.replaceAll('-', '_'), {
get() { return comp.get_property(x); }, get() { return comp.get_property(x); },
set(newValue) { comp.set_property(x, newValue); }, set(newValue) { comp.set_property(x, newValue); },
enumerable: true, enumerable: true,
}) })
}); });
c.callbacks().forEach((x: string) => { c.callbacks().forEach((x: string) => {
Object.defineProperty(ret, x, { Object.defineProperty(ret, x.replaceAll('-', '_'), {
get() { get() {
let callback = function () { return comp.invoke_callback(x, [...arguments]); } as Callback; let callback = function () { return comp.invoke_callback(x, [...arguments]); } as Callback;
callback.setHandler = function (callback) { comp.connect_callback(x, callback) }; callback.setHandler = function (callback) { comp.connect_callback(x, callback) };

View file

@ -119,7 +119,7 @@ fn create<'cx>(
let properties = let properties =
component_type.properties_and_callbacks().collect::<std::collections::HashMap<_, _>>(); component_type.properties_and_callbacks().collect::<std::collections::HashMap<_, _>>();
for x in args.get_own_property_names(cx)?.to_vec(cx)? { for x in args.get_own_property_names(cx)?.to_vec(cx)? {
let prop_name = x.to_string(cx)?.value(); let prop_name = x.to_string(cx)?.value().replace('_', "-");
let value = args.get(cx, x)?; let value = args.get(cx, x)?;
let ty = properties let ty = properties
.get(&prop_name) .get(&prop_name)
@ -212,7 +212,7 @@ fn to_eval_value<'cx>(
Ok(( Ok((
pro_name.clone(), pro_name.clone(),
to_eval_value( to_eval_value(
obj.get(cx, pro_name.as_str())?, obj.get(cx, pro_name.replace('-', "_").as_str())?,
pro_ty.clone(), pro_ty.clone(),
cx, cx,
persistent_context, persistent_context,
@ -271,7 +271,7 @@ fn to_js_value<'cx>(
let js_object = JsObject::new(cx); let js_object = JsObject::new(cx);
for (k, e) in o.iter() { for (k, e) in o.iter() {
let v = to_js_value(e.clone(), cx)?; let v = to_js_value(e.clone(), cx)?;
js_object.set(cx, k, v)?; js_object.set(cx, k.replace('-', "_").as_str(), v)?;
} }
js_object.as_value(cx) js_object.as_value(cx)
} }

View file

@ -229,9 +229,18 @@ use crate::object_tree::{
}; };
use cpp_ast::*; use cpp_ast::*;
use itertools::Itertools; use itertools::Itertools;
use std::borrow::Cow;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::rc::Rc; use std::rc::Rc;
fn ident(ident: &str) -> Cow<'_, str> {
if ident.contains('-') {
ident.replace('-', "_").into()
} else {
ident.into()
}
}
impl CppType for Type { impl CppType for Type {
fn cpp_type(&self) -> Option<String> { fn cpp_type(&self) -> Option<String> {
match self { match self {
@ -246,9 +255,9 @@ impl CppType for Type {
Type::LogicalLength => Some("float".to_owned()), Type::LogicalLength => Some("float".to_owned()),
Type::Percent => Some("float".to_owned()), Type::Percent => Some("float".to_owned()),
Type::Bool => Some("bool".to_owned()), Type::Bool => Some("bool".to_owned()),
Type::Struct { name: Some(name), node: Some(_), .. } => Some(name.clone()), Type::Struct { name: Some(name), node: Some(_), .. } => Some(ident(name).into_owned()),
Type::Struct { name: Some(name), node: None, .. } => { Type::Struct { name: Some(name), node: None, .. } => {
Some(format!("sixtyfps::cbindgen_private::{}", name)) Some(format!("sixtyfps::cbindgen_private::{}", ident(name)))
} }
Type::Struct { fields, .. } => { Type::Struct { fields, .. } => {
let elem = fields.values().map(|v| v.cpp_type()).collect::<Option<Vec<_>>>()?; let elem = fields.values().map(|v| v.cpp_type()).collect::<Option<Vec<_>>>()?;
@ -260,7 +269,7 @@ impl CppType for Type {
Type::Image => Some("sixtyfps::Image".to_owned()), Type::Image => Some("sixtyfps::Image".to_owned()),
Type::Builtin(elem) => elem.native_class.cpp_type.clone(), Type::Builtin(elem) => elem.native_class.cpp_type.clone(),
Type::Enumeration(enumeration) => { Type::Enumeration(enumeration) => {
Some(format!("sixtyfps::cbindgen_private::{}", enumeration.name)) Some(format!("sixtyfps::cbindgen_private::{}", ident(&enumeration.name)))
} }
Type::Brush => Some("sixtyfps::Brush".to_owned()), Type::Brush => Some("sixtyfps::Brush".to_owned()),
Type::LayoutCache => Some("sixtyfps::SharedVector<float>".into()), Type::LayoutCache => Some("sixtyfps::SharedVector<float>".into()),
@ -301,7 +310,7 @@ fn new_struct_with_bindings(
.iter() .iter()
.map(|(prop, initializer)| { .map(|(prop, initializer)| {
let initializer = compile_expression(initializer, component); let initializer = compile_expression(initializer, component);
format!("var.{} = {};", prop, initializer) format!("var.{} = {};", ident(prop), initializer)
}) })
.collect(); .collect();
@ -358,10 +367,10 @@ fn handle_property_binding(
} else if item.is_flickable_viewport { } else if item.is_flickable_viewport {
format!( format!(
"{id}.viewport.", "{id}.viewport.",
id = crate::object_tree::find_parent_element(elem).unwrap().borrow().id id = ident(&crate::object_tree::find_parent_element(elem).unwrap().borrow().id)
) )
} else { } else {
format!("{id}.", id = item.id) format!("{id}.", id = ident(&item.id))
}; };
let prop_type = item.lookup_property(prop_name).property_type; let prop_type = item.lookup_property(prop_name).property_type;
if let Type::Callback { args, .. } = &prop_type { if let Type::Callback { args, .. } = &prop_type {
@ -376,7 +385,7 @@ fn handle_property_binding(
return {code}; return {code};
}});", }});",
accessor_prefix = accessor_prefix, accessor_prefix = accessor_prefix,
prop = prop_name, prop = ident(prop_name),
params = params.join(", "), params = params.join(", "),
code = compile_expression_wrap_return(binding_expression, &component) code = compile_expression_wrap_return(binding_expression, &component)
)); ));
@ -401,7 +410,7 @@ fn handle_property_binding(
let component = &item.enclosing_component.upgrade().unwrap(); let component = &item.enclosing_component.upgrade().unwrap();
let init_expr = compile_expression_wrap_return(binding_expression, component); let init_expr = compile_expression_wrap_return(binding_expression, component);
let cpp_prop = format!("{}{}", accessor_prefix, prop_name); let cpp_prop = format!("{}{}", accessor_prefix, ident(prop_name));
init.push(if is_constant { init.push(if is_constant {
format!("{}.set({});", cpp_prop, init_expr) format!("{}.set({});", cpp_prop, init_expr)
@ -466,8 +475,11 @@ fn handle_item(elem: &ElementRc, main_struct: &mut Struct) {
main_struct.members.push(( main_struct.members.push((
Access::Private, Access::Private,
Declaration::Var(Var { Declaration::Var(Var {
ty: format!("sixtyfps::cbindgen_private::{}", item.base_type.as_native().class_name), ty: format!(
name: item.id.clone(), "sixtyfps::cbindgen_private::{}",
ident(&item.base_type.as_native().class_name)
),
name: ident(&item.id).into_owned(),
init: Some("{}".to_owned()), init: Some("{}".to_owned()),
}), }),
)); ));
@ -486,7 +498,7 @@ fn handle_repeater(
diag: &mut BuildDiagnostics, diag: &mut BuildDiagnostics,
) { ) {
let parent_element = base_component.parent_element.upgrade().unwrap(); let parent_element = base_component.parent_element.upgrade().unwrap();
let repeater_id = format!("repeater_{}", parent_element.borrow().id); let repeater_id = format!("repeater_{}", ident(&parent_element.borrow().id));
let mut model = compile_expression(&repeated.model, parent_component); let mut model = compile_expression(&repeated.model, parent_component);
if repeated.is_conditional_element { if repeated.is_conditional_element {
@ -609,7 +621,7 @@ fn generate_struct(
.iter() .iter()
.map(|(name, t)| { .map(|(name, t)| {
use std::fmt::Write; use std::fmt::Write;
write!(operator_eq, " && a.{0} == b.{0}", name).unwrap(); write!(operator_eq, " && a.{0} == b.{0}", ident(name)).unwrap();
( (
Access::Public, Access::Public,
Declaration::Var(Var { Declaration::Var(Var {
@ -620,7 +632,7 @@ fn generate_struct(
); );
Default::default() Default::default()
}), }),
name: name.clone(), name: ident(name).into_owned(),
..Default::default() ..Default::default()
}), }),
) )
@ -681,7 +693,8 @@ fn generate_component(
let is_root = component.parent_element.upgrade().is_none(); let is_root = component.parent_element.upgrade().is_none();
let mut init = vec!["[[maybe_unused]] auto self = this;".into()]; let mut init = vec!["[[maybe_unused]] auto self = this;".into()];
for (cpp_name, property_decl) in component.root_element.borrow().property_declarations.iter() { for (prop_name, property_decl) in component.root_element.borrow().property_declarations.iter() {
let cpp_name = ident(&prop_name);
let access = if let Some(alias) = &property_decl.is_alias { let access = if let Some(alias) = &property_decl.is_alias {
access_named_reference(alias, component, "this") access_named_reference(alias, component, "this")
} else { } else {
@ -750,7 +763,7 @@ fn generate_component(
let set_value = if let Some(alias) = &property_decl.is_alias { let set_value = if let Some(alias) = &property_decl.is_alias {
property_set_value_code(component, &alias.element(), alias.name(), "value") property_set_value_code(component, &alias.element(), alias.name(), "value")
} else { } else {
property_set_value_code(component, &component.root_element, cpp_name, "value") property_set_value_code(component, &component.root_element, prop_name, "value")
}; };
let prop_setter: Vec<String> = vec![ let prop_setter: Vec<String> = vec![
@ -773,7 +786,7 @@ fn generate_component(
if property_decl.is_alias.is_none() { if property_decl.is_alias.is_none() {
component_struct.members.push(( component_struct.members.push((
if component.is_global() { Access::Public } else { Access::Private }, if component.is_global() { Access::Public } else { Access::Private },
Declaration::Var(Var { ty, name: cpp_name.clone(), init: None }), Declaration::Var(Var { ty, name: cpp_name.into_owned(), init: None }),
)); ));
} }
} }
@ -1057,7 +1070,7 @@ fn generate_component(
tree_array.push(format!( tree_array.push(format!(
"sixtyfps::private_api::make_item_node(offsetof({}, {}) + offsetof(sixtyfps::cbindgen_private::Flickable, viewport), SIXTYFPS_GET_ITEM_VTABLE(RectangleVTable), {}, {}, {})", "sixtyfps::private_api::make_item_node(offsetof({}, {}) + offsetof(sixtyfps::cbindgen_private::Flickable, viewport), SIXTYFPS_GET_ITEM_VTABLE(RectangleVTable), {}, {}, {})",
&component_id, &component_id,
crate::object_tree::find_parent_element(item_rc).unwrap().borrow().id, ident(&crate::object_tree::find_parent_element(item_rc).unwrap().borrow().id),
item.children.len(), item.children.len(),
children_offset, children_offset,
parent_index, parent_index,
@ -1066,7 +1079,7 @@ fn generate_component(
tree_array.push(format!( tree_array.push(format!(
"sixtyfps::private_api::make_item_node(offsetof({}, {}), {}, {}, {}, {})", "sixtyfps::private_api::make_item_node(offsetof({}, {}), {}, {}, {}, {})",
component_id, component_id,
item.id, ident(&item.id),
item.base_type.as_native().cpp_vtable_getter, item.base_type.as_native().cpp_vtable_getter,
item.children.len(), item.children.len(),
children_offset, children_offset,
@ -1074,8 +1087,10 @@ fn generate_component(
)); ));
} }
handle_item(item_rc, &mut component_struct); handle_item(item_rc, &mut component_struct);
item_names_and_vt_symbols item_names_and_vt_symbols.push((
.push((item.id.clone(), item.base_type.as_native().cpp_vtable_getter.clone())); ident(&item.id).into_owned(),
item.base_type.as_native().cpp_vtable_getter.clone(),
));
} }
}); });
@ -1261,7 +1276,7 @@ fn generate_component(
statements: Some(vec![format!( statements: Some(vec![format!(
"return {{ {vt}, const_cast<decltype(this->{id})*>(&this->{id}) }};", "return {{ {vt}, const_cast<decltype(this->{id})*>(&this->{id}) }};",
vt = root_elem.base_type.as_native().cpp_vtable_getter, vt = root_elem.base_type.as_native().cpp_vtable_getter,
id = root_elem.id id = ident(&root_elem.id)
)]), )]),
..Default::default() ..Default::default()
}), }),
@ -1303,11 +1318,11 @@ fn generate_component(
fn component_id(component: &Rc<Component>) -> String { fn component_id(component: &Rc<Component>) -> String {
if component.is_global() { if component.is_global() {
component.root_element.borrow().id.clone() ident(&component.root_element.borrow().id).into_owned()
} else if component.id.is_empty() { } else if component.id.is_empty() {
format!("Component_{}", component.root_element.borrow().id) format!("Component_{}", ident(&component.root_element.borrow().id))
} else { } else {
component.id.clone() ident(&component.id).into_owned()
} }
} }
@ -1351,16 +1366,16 @@ fn access_member(
let enclosing_component = e.enclosing_component.upgrade().unwrap(); let enclosing_component = e.enclosing_component.upgrade().unwrap();
if Rc::ptr_eq(component, &enclosing_component) { if Rc::ptr_eq(component, &enclosing_component) {
if e.property_declarations.contains_key(name) || name.is_empty() || component.is_global() { if e.property_declarations.contains_key(name) || name.is_empty() || component.is_global() {
format!("{}->{}", component_cpp, name) format!("{}->{}", component_cpp, ident(name))
} else if e.is_flickable_viewport { } else if e.is_flickable_viewport {
format!( format!(
"{}->{}.viewport.{}", "{}->{}.viewport.{}",
component_cpp, component_cpp,
crate::object_tree::find_parent_element(element).unwrap().borrow().id, ident(&crate::object_tree::find_parent_element(element).unwrap().borrow().id),
name ident(name)
) )
} else { } else {
format!("{}->{}.{}", component_cpp, e.id.as_str(), name) format!("{}->{}.{}", component_cpp, ident(&e.id), ident(name))
} }
} else if enclosing_component.is_global() { } else if enclosing_component.is_global() {
let mut root_component = component.clone(); let mut root_component = component.clone();
@ -1506,9 +1521,9 @@ fn compile_expression(
} }
Expression::FunctionParameterReference { index, .. } => format!("arg_{}", index), Expression::FunctionParameterReference { index, .. } => format!("arg_{}", index),
Expression::StoreLocalVariable { name, value } => { Expression::StoreLocalVariable { name, value } => {
format!("auto {} = {};", name, compile_expression(value, component)) format!("auto {} = {};", ident(name), compile_expression(value, component))
} }
Expression::ReadLocalVariable { name, .. } => name.clone(), Expression::ReadLocalVariable { name, .. } => ident(name).into_owned(),
Expression::StructFieldAccess { base, name } => match base.ty() { Expression::StructFieldAccess { base, name } => match base.ty() {
Type::Struct { fields, name : None, .. } => { Type::Struct { fields, name : None, .. } => {
let index = fields let index = fields
@ -1518,7 +1533,7 @@ fn compile_expression(
format!("std::get<{}>({})", index, compile_expression(base, component)) format!("std::get<{}>({})", index, compile_expression(base, component))
} }
Type::Struct{..} => { Type::Struct{..} => {
format!("{}.{}", compile_expression(base, component), name) format!("{}.{}", compile_expression(base, component), ident(name))
} }
_ => panic!("Expression::ObjectAccess's base expression is not an Object type"), _ => panic!("Expression::ObjectAccess's base expression is not an Object type"),
}, },
@ -1611,7 +1626,7 @@ fn compile_expression(
format!("{vt}->layouting_info({{{vt}, const_cast<sixtyfps::cbindgen_private::{ty}*>(&self->{id})}}, {o}, &m_window.window_handle())", format!("{vt}->layouting_info({{{vt}, const_cast<sixtyfps::cbindgen_private::{ty}*>(&self->{id})}}, {o}, &m_window.window_handle())",
vt = native_item.cpp_vtable_getter, vt = native_item.cpp_vtable_getter,
ty = native_item.class_name, ty = native_item.class_name,
id = item.id, id = ident(&item.id),
o = to_cpp_orientation(*orientation), o = to_cpp_orientation(*orientation),
) )
} else { } else {
@ -1706,7 +1721,7 @@ fn compile_expression(
.unwrap_or_else(|| "(Error: missing member in object)".to_owned()) .unwrap_or_else(|| "(Error: missing member in object)".to_owned())
}); });
if let Some(name) = name { if let Some(name) = name {
format!("{}{{{}}}", name, elem.join(", ")) format!("{}{{{}}}", ident(name), elem.join(", "))
} else { } else {
format!("std::make_tuple({})", elem.join(", ")) format!("std::make_tuple({})", elem.join(", "))
} }
@ -1733,7 +1748,7 @@ fn compile_expression(
) )
} }
Expression::EnumerationValue(value) => { Expression::EnumerationValue(value) => {
format!("sixtyfps::cbindgen_private::{}::{}", value.enumeration.name, value.to_string()) format!("sixtyfps::cbindgen_private::{}::{}", value.enumeration.name, ident(&value.to_string()))
} }
Expression::ReturnStatement(Some(expr)) => format!( Expression::ReturnStatement(Some(expr)) => format!(
"throw sixtyfps::private_api::ReturnWrapper<{}>({})", "throw sixtyfps::private_api::ReturnWrapper<{}>({})",
@ -1870,7 +1885,7 @@ fn compile_assignment(
.expect("Expression::ObjectAccess: Cannot find a key in an object"); .expect("Expression::ObjectAccess: Cannot find a key in an object");
format!("std::get<{}>({})", index, tmpobj) format!("std::get<{}>({})", index, tmpobj)
} }
Type::Struct { .. } => format!("{}.{}", tmpobj, name), Type::Struct { .. } => format!("{}.{}", tmpobj, ident(name)),
_ => panic!("Expression::ObjectAccess's base expression is not an Object type"), _ => panic!("Expression::ObjectAccess's base expression is not an Object type"),
}; };
let op = if op == '=' { ' ' } else { op }; let op = if op == '=' { ' ' } else { op };
@ -1902,7 +1917,7 @@ fn compile_assignment(
"self", "self",
); );
let index_access = access_member(&parent_component.root_element, "", component, "self"); let index_access = access_member(&parent_component.root_element, "", component, "self");
let repeater_id = format!("repeater_{}", element.borrow().id); let repeater_id = format!("repeater_{}", ident(&element.borrow().id));
if op == '=' { if op == '=' {
format!( format!(
"{}{}.model_set_row_data({}index.get(), {})", "{}{}.model_set_row_data({}index.get(), {})",
@ -1983,14 +1998,16 @@ fn box_layout_data(
let mut repeater_idx = 0usize; let mut repeater_idx = 0usize;
for item in &layout.elems { for item in &layout.elems {
if item.element.borrow().repeated.is_some() { if item.element.borrow().repeated.is_some() {
push_code += push_code += &format!(
&format!("self->repeater_{}.ensure_updated(self);", item.element.borrow().id); "self->repeater_{}.ensure_updated(self);",
ident(&item.element.borrow().id)
);
if repeated_indices.is_some() { if repeated_indices.is_some() {
push_code += &format!("repeater_indices[{}] = cells.size();", repeater_idx * 2); push_code += &format!("repeater_indices[{}] = cells.size();", repeater_idx * 2);
push_code += &format!( push_code += &format!(
"repeater_indices[{c}] = self->repeater_{id}.inner ? self->repeater_{id}.inner->data.size() : 0;", "repeater_indices[{c}] = self->repeater_{id}.inner ? self->repeater_{id}.inner->data.size() : 0;",
c = repeater_idx * 2 + 1, c = repeater_idx * 2 + 1,
id = item.element.borrow().id id = ident(&item.element.borrow().id)
); );
} }
repeater_idx += 1; repeater_idx += 1;
@ -1998,7 +2015,7 @@ fn box_layout_data(
"if (self->repeater_{id}.inner) \ "if (self->repeater_{id}.inner) \
for (auto &&sub_comp : self->repeater_{id}.inner->data) \ for (auto &&sub_comp : self->repeater_{id}.inner->data) \
cells.push_back((*sub_comp.ptr)->box_layout_data({o}));", cells.push_back((*sub_comp.ptr)->box_layout_data({o}));",
id = item.element.borrow().id, id = ident(&item.element.borrow().id),
o = to_cpp_orientation(orientation), o = to_cpp_orientation(orientation),
); );
} else { } else {
@ -2056,7 +2073,7 @@ fn get_layout_info(
"{vt}->layouting_info({{{vt}, const_cast<sixtyfps::cbindgen_private::{ty}*>(&self->{id})}}, {o}, &self->m_window.window_handle())", "{vt}->layouting_info({{{vt}, const_cast<sixtyfps::cbindgen_private::{ty}*>(&self->{id})}}, {o}, &self->m_window.window_handle())",
vt = elem.borrow().base_type.as_native().cpp_vtable_getter, vt = elem.borrow().base_type.as_native().cpp_vtable_getter,
ty = elem.borrow().base_type.as_native().class_name, ty = elem.borrow().base_type.as_native().class_name,
id = elem.borrow().id, id = ident(&elem.borrow().id),
o = to_cpp_orientation(orientation), o = to_cpp_orientation(orientation),
) )
}; };

View file

@ -27,6 +27,14 @@ use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use std::{collections::BTreeMap, rc::Rc}; use std::{collections::BTreeMap, rc::Rc};
fn ident(ident: &str) -> proc_macro2::Ident {
if ident.contains('-') {
format_ident!("r#{}", ident.replace('-', "_"))
} else {
format_ident!("r#{}", ident)
}
}
impl quote::ToTokens for Orientation { impl quote::ToTokens for Orientation {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let tks = match self { let tks = match self {
@ -61,7 +69,7 @@ fn rust_type(ty: &Type) -> Option<proc_macro2::TokenStream> {
Some(quote!(sixtyfps::re_exports::ModelHandle<#inner>)) Some(quote!(sixtyfps::re_exports::ModelHandle<#inner>))
} }
Type::Enumeration(e) => { Type::Enumeration(e) => {
let e = format_ident!("r#{}", e.name); let e = ident(&e.name);
Some(quote!(sixtyfps::re_exports::#e)) Some(quote!(sixtyfps::re_exports::#e))
} }
Type::Brush => Some(quote!(sixtyfps::Brush)), Type::Brush => Some(quote!(sixtyfps::Brush)),
@ -98,7 +106,7 @@ pub fn generate(doc: &Document, diag: &mut BuildDiagnostics) -> Option<TokenStre
.iter() .iter()
.filter_map(|ty| { .filter_map(|ty| {
if let Type::Struct { fields, name: Some(name), node: Some(_) } = ty { if let Type::Struct { fields, name: Some(name), node: Some(_) } = ty {
Some((format_ident!("r#{}", name), generate_struct(name, fields, diag))) Some((ident(name), generate_struct(name, fields, diag)))
} else { } else {
None None
} }
@ -147,10 +155,7 @@ fn generate_struct(
let (declared_property_vars, declared_property_types): (Vec<_>, Vec<_>) = fields let (declared_property_vars, declared_property_types): (Vec<_>, Vec<_>) = fields
.iter() .iter()
.map(|(name, ty)| { .map(|(name, ty)| {
( (ident(name), get_rust_type(ty, &crate::diagnostics::SourceLocation::default(), diag))
format_ident!("r#{}", name),
get_rust_type(ty, &crate::diagnostics::SourceLocation::default(), diag),
)
}) })
.unzip(); .unzip();
@ -309,7 +314,7 @@ fn generate_component(
let mut declared_callbacks_ret = vec![]; let mut declared_callbacks_ret = vec![];
let mut property_and_callback_accessors: Vec<TokenStream> = vec![]; let mut property_and_callback_accessors: Vec<TokenStream> = vec![];
for (prop_name, property_decl) in component.root_element.borrow().property_declarations.iter() { for (prop_name, property_decl) in component.root_element.borrow().property_declarations.iter() {
let prop_ident = format_ident!("r#{}", prop_name); let prop_ident = ident(prop_name);
let prop = if let Some(alias) = &property_decl.is_alias { let prop = if let Some(alias) = &property_decl.is_alias {
access_named_reference(alias, component, quote!(_self)) access_named_reference(alias, component, quote!(_self))
} else { } else {
@ -330,7 +335,7 @@ fn generate_component(
let args_name = (0..callback_args.len()) let args_name = (0..callback_args.len())
.map(|i| format_ident!("arg_{}", i)) .map(|i| format_ident!("arg_{}", i))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let caller_ident = format_ident!("invoke_{}", prop_name); let caller_ident = format_ident!("invoke_{}", prop_ident);
property_and_callback_accessors.push(quote!( property_and_callback_accessors.push(quote!(
#[allow(dead_code)] #[allow(dead_code)]
pub fn #caller_ident(&self, #(#args_name : #callback_args,)*) -> #return_type { pub fn #caller_ident(&self, #(#args_name : #callback_args,)*) -> #return_type {
@ -339,7 +344,7 @@ fn generate_component(
} }
)); ));
let on_ident = format_ident!("on_{}", prop_name); let on_ident = format_ident!("on_{}", prop_ident);
let args_index = let args_index =
(0..callback_args.len()).map(proc_macro2::Literal::usize_unsuffixed); (0..callback_args.len()).map(proc_macro2::Literal::usize_unsuffixed);
property_and_callback_accessors.push( property_and_callback_accessors.push(
@ -366,8 +371,8 @@ fn generate_component(
let rust_property_type = let rust_property_type =
get_rust_type(&property_decl.property_type, &property_decl.type_node(), diag); get_rust_type(&property_decl.property_type, &property_decl.type_node(), diag);
if property_decl.expose_in_public_api { if property_decl.expose_in_public_api {
let getter_ident = format_ident!("get_{}", prop_name); let getter_ident = format_ident!("get_{}", prop_ident);
let setter_ident = format_ident!("set_{}", prop_name); let setter_ident = format_ident!("set_{}", prop_ident);
property_and_callback_accessors.push(quote!( property_and_callback_accessors.push(quote!(
#[allow(dead_code)] #[allow(dead_code)]
@ -435,7 +440,7 @@ fn generate_component(
} else if let Some(repeated) = &item.repeated { } else if let Some(repeated) = &item.repeated {
let base_component = item.base_type.as_component(); let base_component = item.base_type.as_component();
let repeater_index = repeated_element_names.len(); let repeater_index = repeated_element_names.len();
let repeater_id = format_ident!("repeater_{}", item.id); let repeater_id = format_ident!("repeater_{}", ident(&item.id));
let rep_inner_component_id = self::inner_component_id(&*base_component); let rep_inner_component_id = self::inner_component_id(&*base_component);
extra_components.push(generate_component(&*base_component, diag).unwrap_or_else( extra_components.push(generate_component(&*base_component, diag).unwrap_or_else(
@ -593,10 +598,8 @@ fn generate_component(
repeated_element_names.push(repeater_id); repeated_element_names.push(repeater_id);
repeated_element_components.push(rep_inner_component_id); repeated_element_components.push(rep_inner_component_id);
} else if item.is_flickable_viewport { } else if item.is_flickable_viewport {
let field_name = format_ident!( let field_name =
"r#{}", ident(&crate::object_tree::find_parent_element(item_rc).unwrap().borrow().id);
crate::object_tree::find_parent_element(item_rc).unwrap().borrow().id
);
let children_count = item.children.len() as u32; let children_count = item.children.len() as u32;
let field = access_component_field_offset(&inner_component_id, &field_name); let field = access_component_field_offset(&inner_component_id, &field_name);
@ -609,7 +612,7 @@ fn generate_component(
} }
)); ));
} else { } else {
let field_name = format_ident!("r#{}", item.id); let field_name = ident(&item.id);
let children_count = item.children.len() as u32; let children_count = item.children.len() as u32;
let field = access_component_field_offset(&inner_component_id, &field_name); let field = access_component_field_offset(&inner_component_id, &field_name);
@ -622,7 +625,7 @@ fn generate_component(
} }
)); ));
item_names.push(field_name); item_names.push(field_name);
item_types.push(format_ident!("r#{}", item.base_type.as_native().class_name)); item_types.push(ident(&item.base_type.as_native().class_name));
} }
}); });
@ -955,16 +958,16 @@ fn inner_component_id(component: &Component) -> proc_macro2::Ident {
/// Return an identifier suitable for this component for the developer facing API /// Return an identifier suitable for this component for the developer facing API
fn public_component_id(component: &Component) -> proc_macro2::Ident { fn public_component_id(component: &Component) -> proc_macro2::Ident {
if component.is_global() { if component.is_global() {
format_ident!("r#{}", component.root_element.borrow().id) ident(&component.root_element.borrow().id)
} else if component.id.is_empty() { } else if component.id.is_empty() {
let s = &component.root_element.borrow().id; let s = &component.root_element.borrow().id;
// Capitalize first letter: // Capitalize first letter:
let mut it = s.chars(); let mut it = s.chars();
let id = let id =
it.next().map(|c| c.to_ascii_uppercase()).into_iter().chain(it).collect::<String>(); it.next().map(|c| c.to_ascii_uppercase()).into_iter().chain(it).collect::<String>();
format_ident!("r#{}", id) ident(&id)
} else { } else {
format_ident!("r#{}", component.id) ident(&component.id)
} }
} }
@ -974,7 +977,7 @@ fn property_animation_tokens(
) -> Option<TokenStream> { ) -> Option<TokenStream> {
let animation = animation.borrow(); let animation = animation.borrow();
let bindings = animation.bindings.iter().map(|(prop, initializer)| { let bindings = animation.bindings.iter().map(|(prop, initializer)| {
let prop_ident = format_ident!("r#{}", prop); let prop_ident = ident(prop);
let initializer = compile_expression(initializer, component); let initializer = compile_expression(initializer, component);
quote!(#prop_ident: #initializer as _) quote!(#prop_ident: #initializer as _)
}); });
@ -1019,15 +1022,13 @@ fn access_member(
let enclosing_component = e.enclosing_component.upgrade().unwrap(); let enclosing_component = e.enclosing_component.upgrade().unwrap();
if Rc::ptr_eq(component, &enclosing_component) { if Rc::ptr_eq(component, &enclosing_component) {
let inner_component_id = inner_component_id(&enclosing_component); let inner_component_id = inner_component_id(&enclosing_component);
let name_ident = format_ident!("r#{}", name); let name_ident = ident(name);
if e.property_declarations.contains_key(name) || is_special || component.is_global() { if e.property_declarations.contains_key(name) || is_special || component.is_global() {
let field = access_component_field_offset(&inner_component_id, &name_ident); let field = access_component_field_offset(&inner_component_id, &name_ident);
quote!(#field.apply_pin(#component_rust)) quote!(#field.apply_pin(#component_rust))
} else if e.is_flickable_viewport { } else if e.is_flickable_viewport {
let elem_ident = format_ident!( let elem_ident =
"r#{}", ident(&crate::object_tree::find_parent_element(element).unwrap().borrow().id);
crate::object_tree::find_parent_element(element).unwrap().borrow().id
);
let element_field = access_component_field_offset(&inner_component_id, &elem_ident); let element_field = access_component_field_offset(&inner_component_id, &elem_ident);
quote!((#element_field quote!((#element_field
@ -1036,8 +1037,8 @@ fn access_member(
.apply_pin(#component_rust) .apply_pin(#component_rust)
) )
} else { } else {
let elem_ident = format_ident!("r#{}", e.id); let elem_ident = ident(&e.id);
let elem_ty = format_ident!("r#{}", e.base_type.as_native().class_name); let elem_ty = ident(&e.base_type.as_native().class_name);
let element_field = access_component_field_offset(&inner_component_id, &elem_ident); let element_field = access_component_field_offset(&inner_component_id, &elem_ident);
quote!((#element_field + #elem_ty::FIELD_OFFSETS.#name_ident) quote!((#element_field + #elem_ty::FIELD_OFFSETS.#name_ident)
@ -1110,7 +1111,7 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
(Type::Struct { ref fields, .. }, Type::Component(c)) => { (Type::Struct { ref fields, .. }, Type::Component(c)) => {
let fields = fields.iter().enumerate().map(|(index, (name, _))| { let fields = fields.iter().enumerate().map(|(index, (name, _))| {
let index = proc_macro2::Literal::usize_unsuffixed(index); let index = proc_macro2::Literal::usize_unsuffixed(index);
let name = format_ident!("r#{}", name); let name = ident(name);
quote!(#name: obj.#index as _) quote!(#name: obj.#index as _)
}); });
let id : TokenStream = c.id.parse().unwrap(); let id : TokenStream = c.id.parse().unwrap();
@ -1119,7 +1120,7 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
(Type::Struct { ref fields, .. }, Type::Struct{ name: Some(n), .. }) => { (Type::Struct { ref fields, .. }, Type::Struct{ name: Some(n), .. }) => {
let fields = fields.iter().enumerate().map(|(index, (name, _))| { let fields = fields.iter().enumerate().map(|(index, (name, _))| {
let index = proc_macro2::Literal::usize_unsuffixed(index); let index = proc_macro2::Literal::usize_unsuffixed(index);
let name = format_ident!("r#{}", name); let name = ident(name);
quote!(#name: obj.#index as _) quote!(#name: obj.#index as _)
}); });
let id = struct_name_to_tokens(n); let id = struct_name_to_tokens(n);
@ -1222,7 +1223,7 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
quote!((#base_e).#index ) quote!((#base_e).#index )
} }
Type::Struct { .. } => { Type::Struct { .. } => {
let name = format_ident!("r#{}", name); let name = ident(name);
let base_e = compile_expression(base, component); let base_e = compile_expression(base, component);
quote!((#base_e).#name) quote!((#base_e).#name)
} }
@ -1284,7 +1285,7 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
if let Expression::ElementReference(item) = &arguments[0] { if let Expression::ElementReference(item) = &arguments[0] {
let item = item.upgrade().unwrap(); let item = item.upgrade().unwrap();
let item = item.borrow(); let item = item.borrow();
let item_id = format_ident!("r#{}", item.id); let item_id = ident(&item.id);
let item_field = access_component_field_offset(&format_ident!("Self"), &item_id); let item_field = access_component_field_offset(&format_ident!("Self"), &item_id);
quote!( quote!(
#item_field.apply_pin(_self).layouting_info(#orient, &_self.window.window_handle()) #item_field.apply_pin(_self).layouting_info(#orient, &_self.window.window_handle())
@ -1450,7 +1451,7 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
}); });
if let Some(name) = name { if let Some(name) = name {
let name : TokenStream = struct_name_to_tokens(name.as_str()); let name : TokenStream = struct_name_to_tokens(name.as_str());
let keys = fields.keys().map(|k| k.parse::<TokenStream>().unwrap()); let keys = fields.keys().map(|k| ident(&k));
quote!(#name { #(#keys: #elem,)* }) quote!(#name { #(#keys: #elem,)* })
} else { } else {
// This will produce a tuple // This will produce a tuple
@ -1463,11 +1464,11 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
Expression::PathElements { elements } => compile_path(elements, component), Expression::PathElements { elements } => compile_path(elements, component),
Expression::StoreLocalVariable { name, value } => { Expression::StoreLocalVariable { name, value } => {
let value = compile_expression(value, component); let value = compile_expression(value, component);
let name = format_ident!("r#{}", name); let name = ident(name);
quote!(let #name = #value;) quote!(let #name = #value;)
} }
Expression::ReadLocalVariable { name, .. } => { Expression::ReadLocalVariable { name, .. } => {
let name = format_ident!("r#{}", name); let name = ident(name);
quote!(#name) quote!(#name)
} }
Expression::EasingCurve(EasingCurve::Linear) => { Expression::EasingCurve(EasingCurve::Linear) => {
@ -1488,8 +1489,8 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
)) ))
} }
Expression::EnumerationValue(value) => { Expression::EnumerationValue(value) => {
let base_ident = format_ident!("r#{}", value.enumeration.name); let base_ident = ident(&value.enumeration.name);
let value_ident = format_ident!("r#{}", value.to_string()); let value_ident = ident(&value.to_string());
quote!(sixtyfps::re_exports::#base_ident::#value_ident) quote!(sixtyfps::re_exports::#base_ident::#value_ident)
} }
Expression::ReturnStatement(expr) => { Expression::ReturnStatement(expr) => {
@ -1590,7 +1591,7 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
/// Return a TokenStream for a name (as in [`Type::Struct::name`]) /// Return a TokenStream for a name (as in [`Type::Struct::name`])
fn struct_name_to_tokens(name: &str) -> TokenStream { fn struct_name_to_tokens(name: &str) -> TokenStream {
// the name match the C++ signature so we need to change that to the rust namespace // the name match the C++ signature so we need to change that to the rust namespace
let mut name = name.replace("::private_api::", "::re_exports::"); let mut name = name.replace("::private_api::", "::re_exports::").replace('-', "_");
if !name.contains("::") { if !name.contains("::") {
name.insert_str(0, "r#") name.insert_str(0, "r#")
} }
@ -1631,7 +1632,7 @@ fn compile_assignment(
(quote!(#index), fields[name].clone()) (quote!(#index), fields[name].clone())
} }
Type::Struct { fields, name: Some(_), .. } => { Type::Struct { fields, name: Some(_), .. } => {
let n = format_ident!("r#{}", name); let n = ident(name);
(quote!(#n), fields[name].clone()) (quote!(#n), fields[name].clone())
} }
_ => panic!("Expression::ObjectAccess's base expression is not an Object type"), _ => panic!("Expression::ObjectAccess's base expression is not an Object type"),
@ -1762,7 +1763,7 @@ fn box_layout_data(
let mut repeater_idx = 0usize; let mut repeater_idx = 0usize;
for item in &layout.elems { for item in &layout.elems {
if item.element.borrow().repeated.is_some() { if item.element.borrow().repeated.is_some() {
let repeater_id = format_ident!("repeater_{}", item.element.borrow().id); let repeater_id = format_ident!("repeater_{}", ident(&item.element.borrow().id));
let rep_inner_component_id = let rep_inner_component_id =
self::inner_component_id(item.element.borrow().base_type.as_component()); self::inner_component_id(item.element.borrow().base_type.as_component());
repeated_count = quote!(#repeated_count + _self.#repeater_id.len()); repeated_count = quote!(#repeated_count + _self.#repeater_id.len());
@ -1869,7 +1870,7 @@ fn get_layout_info(
let li = access_named_reference(layout_info_prop, component, quote!(_self)); let li = access_named_reference(layout_info_prop, component, quote!(_self));
quote! {#li.get()} quote! {#li.get()}
} else { } else {
let elem_id = format_ident!("r#{}", elem.borrow().id); let elem_id = ident(&elem.borrow().id);
let inner_component_id = inner_component_id(component); let inner_component_id = inner_component_id(component);
quote!(#inner_component_id::FIELD_OFFSETS.#elem_id.apply_pin(_self).layouting_info(#orientation, &_self.window.window_handle())) quote!(#inner_component_id::FIELD_OFFSETS.#elem_id.apply_pin(_self).layouting_info(#orientation, &_self.window.window_handle()))
}; };
@ -1877,9 +1878,7 @@ fn get_layout_info(
if constraints.has_explicit_restrictions() { if constraints.has_explicit_restrictions() {
let (name, expr): (Vec<_>, Vec<_>) = constraints let (name, expr): (Vec<_>, Vec<_>) = constraints
.for_each_restrictions(orientation) .for_each_restrictions(orientation)
.map(|(e, s)| { .map(|(e, s)| (ident(s), access_named_reference(e, component, quote!(_self))))
(format_ident!("r#{}", s), access_named_reference(e, component, quote!(_self)))
})
.unzip(); .unzip();
quote!({ quote!({
let mut layout_info = #layout_info; let mut layout_info = #layout_info;
@ -1954,7 +1953,7 @@ fn compile_path(path: &Path, component: &Rc<Component>) -> TokenStream {
.bindings .bindings
.iter() .iter()
.map(|(property, expr)| { .map(|(property, expr)| {
let prop_ident = format_ident!("r#{}", property); let prop_ident = ident(property);
let binding_expr = compile_expression(expr, component); let binding_expr = compile_expression(expr, component);
quote!(#prop_ident: #binding_expr as _).to_string() quote!(#prop_ident: #binding_expr as _).to_string()

View file

@ -163,7 +163,7 @@ impl Display for Type {
Type::String => write!(f, "string"), Type::String => write!(f, "string"),
Type::Duration => write!(f, "duration"), Type::Duration => write!(f, "duration"),
Type::Angle => write!(f, "angle"), Type::Angle => write!(f, "angle"),
Type::PhysicalLength => write!(f, "physical_length"), Type::PhysicalLength => write!(f, "physical-length"),
Type::LogicalLength => write!(f, "length"), Type::LogicalLength => write!(f, "length"),
Type::Percent => write!(f, "percent"), Type::Percent => write!(f, "percent"),
Type::Color => write!(f, "color"), Type::Color => write!(f, "color"),

View file

@ -143,14 +143,14 @@ pub struct LayoutConstraints {
impl LayoutConstraints { impl LayoutConstraints {
pub fn new(element: &ElementRc, diag: &mut BuildDiagnostics) -> Self { pub fn new(element: &ElementRc, diag: &mut BuildDiagnostics) -> Self {
let mut constraints = Self { let mut constraints = Self {
min_width: binding_reference(element, "min_width"), min_width: binding_reference(element, "min-width"),
max_width: binding_reference(element, "max_width"), max_width: binding_reference(element, "max-width"),
min_height: binding_reference(element, "min_height"), min_height: binding_reference(element, "min-height"),
max_height: binding_reference(element, "max_height"), max_height: binding_reference(element, "max-height"),
preferred_width: binding_reference(element, "preferred_width"), preferred_width: binding_reference(element, "preferred-width"),
preferred_height: binding_reference(element, "preferred_height"), preferred_height: binding_reference(element, "preferred-height"),
horizontal_stretch: binding_reference(element, "horizontal_stretch"), horizontal_stretch: binding_reference(element, "horizontal-stretch"),
vertical_stretch: binding_reference(element, "vertical_stretch"), vertical_stretch: binding_reference(element, "vertical-stretch"),
fixed_width: false, fixed_width: false,
fixed_height: false, fixed_height: false,
}; };
@ -368,16 +368,16 @@ impl LayoutGeometry {
let alignment = binding_reference(layout_element, "alignment"); let alignment = binding_reference(layout_element, "alignment");
let padding = || binding_reference(layout_element, "padding"); let padding = || binding_reference(layout_element, "padding");
init_fake_property(layout_element, "padding_left", padding); init_fake_property(layout_element, "padding-left", padding);
init_fake_property(layout_element, "padding_right", padding); init_fake_property(layout_element, "padding-right", padding);
init_fake_property(layout_element, "padding_top", padding); init_fake_property(layout_element, "padding-top", padding);
init_fake_property(layout_element, "padding_bottom", padding); init_fake_property(layout_element, "padding-bottom", padding);
let padding = Padding { let padding = Padding {
left: binding_reference(layout_element, "padding_left").or_else(padding), left: binding_reference(layout_element, "padding-left").or_else(padding),
right: binding_reference(layout_element, "padding_right").or_else(padding), right: binding_reference(layout_element, "padding-right").or_else(padding),
top: binding_reference(layout_element, "padding_top").or_else(padding), top: binding_reference(layout_element, "padding-top").or_else(padding),
bottom: binding_reference(layout_element, "padding_bottom").or_else(padding), bottom: binding_reference(layout_element, "padding-bottom").or_else(padding),
}; };
let rect = LayoutRect::install_on_element(layout_element); let rect = LayoutRect::install_on_element(layout_element);

View file

@ -132,7 +132,7 @@ pub fn load_builtins(register: &mut TypeRegister) {
n.rust_type_constructor = parse_annotation("rust_type_constructor", &e).map(|x| x.unwrap()); n.rust_type_constructor = parse_annotation("rust_type_constructor", &e).map(|x| x.unwrap());
let global = if let Some(base) = e.QualifiedName() { let global = if let Some(base) = e.QualifiedName() {
let base = QualifiedTypeName::from_node(base).to_string(); let base = QualifiedTypeName::from_node(base).to_string();
if base != "_" { if base != "-" {
n.parent = Some(natives.get(&base).unwrap().native_class.clone()) n.parent = Some(natives.get(&base).unwrap().native_class.clone())
}; };
false false

View file

@ -409,14 +409,14 @@ impl LookupObject for EasingSpecific {
use EasingCurve::CubicBezier; use EasingCurve::CubicBezier;
None.or_else(|| f("linear", Expression::EasingCurve(EasingCurve::Linear))) None.or_else(|| f("linear", Expression::EasingCurve(EasingCurve::Linear)))
.or_else(|| f("ease", Expression::EasingCurve(CubicBezier(0.25, 0.1, 0.25, 1.0)))) .or_else(|| f("ease", Expression::EasingCurve(CubicBezier(0.25, 0.1, 0.25, 1.0))))
.or_else(|| f("ease_in", Expression::EasingCurve(CubicBezier(0.42, 0.0, 1.0, 1.0)))) .or_else(|| f("ease-in", Expression::EasingCurve(CubicBezier(0.42, 0.0, 1.0, 1.0))))
.or_else(|| { .or_else(|| {
f("ease_in_out", Expression::EasingCurve(CubicBezier(0.42, 0.0, 0.58, 1.0))) f("ease-in-out", Expression::EasingCurve(CubicBezier(0.42, 0.0, 0.58, 1.0)))
}) })
.or_else(|| f("ease_out", Expression::EasingCurve(CubicBezier(0.0, 0.0, 0.58, 1.0)))) .or_else(|| f("ease-out", Expression::EasingCurve(CubicBezier(0.0, 0.0, 0.58, 1.0))))
.or_else(|| { .or_else(|| {
f( f(
"cubic_bezier", "cubic-bezier",
Expression::BuiltinMacroReference( Expression::BuiltinMacroReference(
BuiltinMacroFunction::CubicBezier, BuiltinMacroFunction::CubicBezier,
ctx.current_token.clone(), ctx.current_token.clone(),
@ -568,8 +568,8 @@ impl<'a> LookupObject for StringExpression<'a> {
ctx.current_token.as_ref().map(|t| t.to_source_location()), ctx.current_token.as_ref().map(|t| t.to_source_location()),
)), )),
}; };
None.or_else(|| f("is_float", member_function(BuiltinFunction::StringIsFloat))) None.or_else(|| f("is-float", member_function(BuiltinFunction::StringIsFloat)))
.or_else(|| f("to_float", member_function(BuiltinFunction::StringToFloat))) .or_else(|| f("to-float", member_function(BuiltinFunction::StringToFloat)))
} }
} }
struct ColorExpression<'a>(&'a Expression); struct ColorExpression<'a>(&'a Expression);

View file

@ -305,7 +305,7 @@ impl TransitionPropertyAnimation {
Expression::BinaryExpression { Expression::BinaryExpression {
lhs: Box::new(Expression::StructFieldAccess { lhs: Box::new(Expression::StructFieldAccess {
base: Box::new(state), base: Box::new(state),
name: (if self.is_out { "previous_state" } else { "current_state" }).into(), name: (if self.is_out { "previous-state" } else { "current-state" }).into(),
}), }),
rhs: Box::new(Expression::NumberLiteral(self.state_id as _, Unit::None)), rhs: Box::new(Expression::NumberLiteral(self.state_id as _, Unit::None)),
op: '=', op: '=',
@ -972,11 +972,11 @@ impl Element {
) -> ElementRc { ) -> ElementRc {
let is_listview = if parent.borrow().base_type.to_string() == "ListView" { let is_listview = if parent.borrow().base_type.to_string() == "ListView" {
Some(ListViewInfo { Some(ListViewInfo {
viewport_y: NamedReference::new(parent, "viewport_y"), viewport_y: NamedReference::new(parent, "viewport-y"),
viewport_height: NamedReference::new(parent, "viewport_height"), viewport_height: NamedReference::new(parent, "viewport-height"),
viewport_width: NamedReference::new(parent, "viewport_width"), viewport_width: NamedReference::new(parent, "viewport-width"),
listview_height: NamedReference::new(parent, "visible_height"), listview_height: NamedReference::new(parent, "visible-height"),
listview_width: NamedReference::new(parent, "visible_width"), listview_width: NamedReference::new(parent, "visible-width"),
}) })
} else { } else {
None None

View file

@ -846,7 +846,7 @@ pub fn identifier_text(node: &SyntaxNode) -> Option<String> {
} }
pub fn normalize_identifier(ident: &str) -> String { pub fn normalize_identifier(ident: &str) -> String {
ident.replace('-', "_") ident.replace('_', "-")
} }
// Actual parser // Actual parser

View file

@ -37,10 +37,10 @@ pub async fn apply_default_properties_from_style(
let mut elem = elem.borrow_mut(); let mut elem = elem.borrow_mut();
match elem.base_type.to_string().as_str() { match elem.base_type.to_string().as_str() {
"TextInput" => { "TextInput" => {
elem.bindings.set_binding_if_not_set("text_cursor_width".into(), || { elem.bindings.set_binding_if_not_set("text-cursor-width".into(), || {
Expression::PropertyReference(NamedReference::new( Expression::PropertyReference(NamedReference::new(
&style_metrics.root_element, &style_metrics.root_element,
"text_cursor_width", "text-cursor-width",
)) ))
.into() .into()
}); });
@ -49,7 +49,7 @@ pub async fn apply_default_properties_from_style(
elem.bindings.set_binding_if_not_set("background".into(), || { elem.bindings.set_binding_if_not_set("background".into(), || {
Expression::PropertyReference(NamedReference::new( Expression::PropertyReference(NamedReference::new(
&style_metrics.root_element, &style_metrics.root_element,
"window_background", "window-background",
)) ))
.into() .into()
}); });

View file

@ -210,10 +210,10 @@ fn visit_implicit_layout_info_dependencies(
} }
"Text" => { "Text" => {
vis(&NamedReference::new(item, "text")); vis(&NamedReference::new(item, "text"));
vis(&NamedReference::new(item, "font_family")); vis(&NamedReference::new(item, "font-family"));
vis(&NamedReference::new(item, "font_size")); vis(&NamedReference::new(item, "font-size"));
vis(&NamedReference::new(item, "font_weight")); vis(&NamedReference::new(item, "font-weight"));
vis(&NamedReference::new(item, "letter_spacing")); vis(&NamedReference::new(item, "letter-spacing"));
vis(&NamedReference::new(item, "wrap")); vis(&NamedReference::new(item, "wrap"));
vis(&NamedReference::new(item, "overflow")); vis(&NamedReference::new(item, "overflow"));
if orientation == Orientation::Vertical { if orientation == Orientation::Vertical {

View file

@ -60,7 +60,7 @@ pub fn handle_clip(
fn create_clip_element(parent_elem: &ElementRc, native_clip: &Rc<NativeClass>) { fn create_clip_element(parent_elem: &ElementRc, native_clip: &Rc<NativeClass>) {
let mut parent = parent_elem.borrow_mut(); let mut parent = parent_elem.borrow_mut();
let clip = Rc::new(RefCell::new(Element { let clip = Rc::new(RefCell::new(Element {
id: format!("{}_clip", parent.id), id: format!("{}-clip", parent.id),
base_type: Type::Native(native_clip.clone()), base_type: Type::Native(native_clip.clone()),
children: std::mem::take(&mut parent.children), children: std::mem::take(&mut parent.children),
enclosing_component: parent.enclosing_component.clone(), enclosing_component: parent.enclosing_component.clone(),
@ -78,7 +78,7 @@ fn create_clip_element(parent_elem: &ElementRc, native_clip: &Rc<NativeClass>) {
) )
}) })
.collect(); .collect();
for optional_binding in ["border_radius", "border_width"].iter() { for optional_binding in ["border-radius", "border-width"].iter() {
if parent_elem.borrow().bindings.contains_key(*optional_binding) { if parent_elem.borrow().bindings.contains_key(*optional_binding) {
clip.borrow_mut().bindings.insert( clip.borrow_mut().bindings.insert(
optional_binding.to_string(), optional_binding.to_string(),

View file

@ -90,7 +90,7 @@ pub fn default_geometry(root_component: &Rc<Component>, diag: &mut BuildDiagnost
let PropertyLookupResult { let PropertyLookupResult {
resolved_name: image_fit_prop_name, resolved_name: image_fit_prop_name,
property_type: image_fit_prop_type, property_type: image_fit_prop_type,
} = elem.borrow().lookup_property("image_fit"); } = elem.borrow().lookup_property("image-fit");
elem.borrow_mut().bindings.set_binding_if_not_set( elem.borrow_mut().bindings.set_binding_if_not_set(
image_fit_prop_name.into(), image_fit_prop_name.into(),
@ -137,12 +137,12 @@ fn gen_layout_info_prop(elem: &ElementRc) {
let li_v = super::lower_layout::create_new_prop( let li_v = super::lower_layout::create_new_prop(
elem, elem,
"layoutinfo_v", "layoutinfo-v",
crate::layout::layout_info_type(), crate::layout::layout_info_type(),
); );
let li_h = super::lower_layout::create_new_prop( let li_h = super::lower_layout::create_new_prop(
elem, elem,
"layoutinfo_h", "layoutinfo-h",
crate::layout::layout_info_type(), crate::layout::layout_info_type(),
); );
elem.borrow_mut().layout_info_prop = Some((li_h.clone(), li_v.clone())); elem.borrow_mut().layout_info_prop = Some((li_h.clone(), li_v.clone()));

View file

@ -51,7 +51,7 @@ fn create_viewport_element(flickable_elem: &ElementRc, native_rect: &Rc<NativeCl
let mut flickable = flickable_elem.borrow_mut(); let mut flickable = flickable_elem.borrow_mut();
let flickable = &mut *flickable; let flickable = &mut *flickable;
let viewport = Rc::new(RefCell::new(Element { let viewport = Rc::new(RefCell::new(Element {
id: format!("{}_viewport", flickable.id), id: format!("{}-viewport", flickable.id),
base_type: Type::Native(native_rect.clone()), base_type: Type::Native(native_rect.clone()),
children: std::mem::take(&mut flickable.children), children: std::mem::take(&mut flickable.children),
enclosing_component: flickable.enclosing_component.clone(), enclosing_component: flickable.enclosing_component.clone(),
@ -59,7 +59,7 @@ fn create_viewport_element(flickable_elem: &ElementRc, native_rect: &Rc<NativeCl
..Element::default() ..Element::default()
})); }));
for (prop, info) in &flickable.base_type.as_builtin().properties { for (prop, info) in &flickable.base_type.as_builtin().properties {
if let Some(vp_prop) = prop.strip_prefix("viewport_") { if let Some(vp_prop) = prop.strip_prefix("viewport-") {
let nr = NamedReference::new(&viewport, vp_prop); let nr = NamedReference::new(&viewport, vp_prop);
flickable.property_declarations.insert(prop.to_owned(), info.ty.clone().into()); flickable.property_declarations.insert(prop.to_owned(), info.ty.clone().into());
match flickable.bindings.entry(prop.to_owned()) { match flickable.bindings.entry(prop.to_owned()) {
@ -93,35 +93,35 @@ fn fixup_geometry(flickable_elem: &ElementRc) {
}; };
if !flickable_elem.borrow().bindings.contains_key("height") { if !flickable_elem.borrow().bindings.contains_key("height") {
forward_minmax_of("max_height", '<'); forward_minmax_of("max-height", '<');
forward_minmax_of("preferred_height", '<'); forward_minmax_of("preferred-height", '<');
} }
if !flickable_elem.borrow().bindings.contains_key("width") { if !flickable_elem.borrow().bindings.contains_key("width") {
forward_minmax_of("max_width", '<'); forward_minmax_of("max-width", '<');
forward_minmax_of("preferred_width", '<'); forward_minmax_of("preferred-width", '<');
} }
set_binding_if_not_explicit(flickable_elem, "viewport_width", || { set_binding_if_not_explicit(flickable_elem, "viewport-width", || {
Some( Some(
flickable_elem flickable_elem
.borrow() .borrow()
.children .children
.iter() .iter()
.filter(|x| is_layout(&x.borrow().base_type)) .filter(|x| is_layout(&x.borrow().base_type))
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min_width"))) .map(|x| Expression::PropertyReference(NamedReference::new(x, "min-width")))
.fold( .fold(
Expression::PropertyReference(NamedReference::new(flickable_elem, "width")), Expression::PropertyReference(NamedReference::new(flickable_elem, "width")),
|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'), |lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'),
), ),
) )
}); });
set_binding_if_not_explicit(flickable_elem, "viewport_height", || { set_binding_if_not_explicit(flickable_elem, "viewport-height", || {
Some( Some(
flickable_elem flickable_elem
.borrow() .borrow()
.children .children
.iter() .iter()
.filter(|x| is_layout(&x.borrow().base_type)) .filter(|x| is_layout(&x.borrow().base_type))
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min_height"))) .map(|x| Expression::PropertyReference(NamedReference::new(x, "min-height")))
.fold( .fold(
Expression::PropertyReference(NamedReference::new(flickable_elem, "height")), Expression::PropertyReference(NamedReference::new(flickable_elem, "height")),
|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'), |lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'),

View file

@ -24,14 +24,14 @@ enum FocusCheckResult {
} }
fn element_focus_check(element: &ElementRc) -> FocusCheckResult { fn element_focus_check(element: &ElementRc) -> FocusCheckResult {
if let Some(forwarded_focus_binding) = element.borrow().bindings.get("forward_focus") { if let Some(forwarded_focus_binding) = element.borrow().bindings.get("forward-focus") {
if let Expression::ElementReference(target) = &forwarded_focus_binding.expression { if let Expression::ElementReference(target) = &forwarded_focus_binding.expression {
return FocusCheckResult::FocusForwarded( return FocusCheckResult::FocusForwarded(
target.upgrade().unwrap(), target.upgrade().unwrap(),
forwarded_focus_binding.to_source_location(), forwarded_focus_binding.to_source_location(),
); );
} else { } else {
panic!("internal error: forward_focus property is of type ElementReference but received non-element-reference binding"); panic!("internal error: forward-focus property is of type ElementReference but received non-element-reference binding");
} }
} }
@ -117,10 +117,10 @@ pub fn determine_initial_focus_item(component: &Rc<Component>, diag: &mut BuildD
} }
} }
/// The `forward_focus` property is not a real property that can be generated, so remove any bindings to it /// The `forward-focus` property is not a real property that can be generated, so remove any bindings to it
/// to avoid them being materialized. /// to avoid them being materialized.
pub fn erase_forward_focus_properties(component: &Rc<Component>) { pub fn erase_forward_focus_properties(component: &Rc<Component>) {
recurse_elem_no_borrow(&component.root_element, &(), &mut |elem, _| { recurse_elem_no_borrow(&component.root_element, &(), &mut |elem, _| {
elem.borrow_mut().bindings.remove("forward_focus"); elem.borrow_mut().bindings.remove("forward-focus");
}) })
} }

View file

@ -84,13 +84,13 @@ fn lower_grid_layout(
}; };
let layout_cache_prop_h = let layout_cache_prop_h =
create_new_prop(grid_layout_element, "layout_cache_h", Type::LayoutCache); create_new_prop(grid_layout_element, "layout-cache-h", Type::LayoutCache);
let layout_cache_prop_v = let layout_cache_prop_v =
create_new_prop(grid_layout_element, "layout_cache_v", Type::LayoutCache); create_new_prop(grid_layout_element, "layout-cache-v", Type::LayoutCache);
let layout_info_prop_h = let layout_info_prop_h =
create_new_prop(grid_layout_element, "layoutinfo_h", layout_info_type()); create_new_prop(grid_layout_element, "layoutinfo-h", layout_info_type());
let layout_info_prop_v = let layout_info_prop_v =
create_new_prop(grid_layout_element, "layoutinfo_v", layout_info_type()); create_new_prop(grid_layout_element, "layoutinfo-v", layout_info_type());
let mut row = 0; let mut row = 0;
let mut col = 0; let mut col = 0;
@ -244,9 +244,9 @@ fn lower_box_layout(
geometry: LayoutGeometry::new(layout_element), geometry: LayoutGeometry::new(layout_element),
}; };
let layout_cache_prop = create_new_prop(layout_element, "layout_cache", Type::LayoutCache); let layout_cache_prop = create_new_prop(layout_element, "layout-cache", Type::LayoutCache);
let layout_info_prop_v = create_new_prop(layout_element, "layoutinfo_v", layout_info_type()); let layout_info_prop_v = create_new_prop(layout_element, "layoutinfo-v", layout_info_type());
let layout_info_prop_h = create_new_prop(layout_element, "layoutinfo_h", layout_info_type()); let layout_info_prop_h = create_new_prop(layout_element, "layoutinfo-h", layout_info_type());
let layout_children = std::mem::take(&mut layout_element.borrow_mut().children); let layout_children = std::mem::take(&mut layout_element.borrow_mut().children);
@ -342,7 +342,7 @@ fn lower_path_layout(
layout_element: &ElementRc, layout_element: &ElementRc,
diag: &mut BuildDiagnostics, diag: &mut BuildDiagnostics,
) { ) {
let layout_cache_prop = create_new_prop(layout_element, "layout_cache", Type::LayoutCache); let layout_cache_prop = create_new_prop(layout_element, "layout-cache", Type::LayoutCache);
let path_elements_expr = match layout_element.borrow_mut().bindings.remove("elements") { let path_elements_expr = match layout_element.borrow_mut().bindings.remove("elements") {
Some(BindingExpression { expression: Expression::PathElements { elements }, .. }) => { Some(BindingExpression { expression: Expression::PathElements { elements }, .. }) => {
@ -426,14 +426,14 @@ fn create_layout_item(
} }
let mut item = item.borrow_mut(); let mut item = item.borrow_mut();
let b = item.bindings.remove(prop).unwrap(); let b = item.bindings.remove(prop).unwrap();
item.bindings.insert(format!("min_{}", prop), b.clone()); item.bindings.insert(format!("min-{}", prop), b.clone());
item.bindings.insert(format!("max_{}", prop), b); item.bindings.insert(format!("max-{}", prop), b);
item.property_declarations.insert( item.property_declarations.insert(
format!("min_{}", prop), format!("min-{}", prop),
PropertyDeclaration { property_type: Type::Percent, ..PropertyDeclaration::default() }, PropertyDeclaration { property_type: Type::Percent, ..PropertyDeclaration::default() },
); );
item.property_declarations.insert( item.property_declarations.insert(
format!("max_{}", prop), format!("max-{}", prop),
PropertyDeclaration { property_type: Type::Percent, ..PropertyDeclaration::default() }, PropertyDeclaration { property_type: Type::Percent, ..PropertyDeclaration::default() },
); );
}; };

View file

@ -123,7 +123,7 @@ fn create_coordinate(
}; };
} }
let parent_element = parent_stack.last().unwrap(); let parent_element = parent_stack.last().unwrap();
let property_name = format!("{}_popup_{}", popup_comp.root_element.borrow().id, coord); let property_name = format!("{}-popup-{}", popup_comp.root_element.borrow().id, coord);
parent_element parent_element
.borrow_mut() .borrow_mut()
.property_declarations .property_declarations

View file

@ -43,23 +43,23 @@ fn create_box_shadow_element(
} }
let mut element = Element { let mut element = Element {
id: format!("{}_shadow", sibling_element.borrow().id), id: format!("{}-shadow", sibling_element.borrow().id),
base_type: type_register.lookup_element("BoxShadow").unwrap(), base_type: type_register.lookup_element("BoxShadow").unwrap(),
enclosing_component: sibling_element.borrow().enclosing_component.clone(), enclosing_component: sibling_element.borrow().enclosing_component.clone(),
bindings: shadow_property_bindings bindings: shadow_property_bindings
.into_iter() .into_iter()
.map(|(shadow_prop_name, expr)| { .map(|(shadow_prop_name, expr)| {
(shadow_prop_name.strip_prefix("drop_shadow_").unwrap().to_string(), expr) (shadow_prop_name.strip_prefix("drop-shadow-").unwrap().to_string(), expr)
}) })
.collect(), .collect(),
..Default::default() ..Default::default()
}; };
// FIXME: remove the border_radius manual mapping. // FIXME: remove the border-radius manual mapping.
if sibling_element.borrow().bindings.contains_key("border_radius") { if sibling_element.borrow().bindings.contains_key("border-radius") {
element.bindings.insert( element.bindings.insert(
"border_radius".to_string(), "border-radius".to_string(),
Expression::PropertyReference(NamedReference::new(sibling_element, "border_radius")) Expression::PropertyReference(NamedReference::new(sibling_element, "border-radius"))
.into(), .into(),
); );
} }

View file

@ -44,7 +44,7 @@ fn lower_state_in_element(
let state_property_ref = if has_transitions { let state_property_ref = if has_transitions {
Expression::StructFieldAccess { Expression::StructFieldAccess {
base: Box::new(state_property.clone()), base: Box::new(state_property.clone()),
name: "current_state".into(), name: "current-state".into(),
} }
} else { } else {
state_property.clone() state_property.clone()
@ -172,7 +172,7 @@ fn compute_state_property_name(root_element: &ElementRc) -> String {
while root_element.borrow().lookup_property(property_name.as_ref()).property_type while root_element.borrow().lookup_property(property_name.as_ref()).property_type
!= Type::Invalid != Type::Invalid
{ {
property_name += "_"; property_name += "-";
} }
property_name property_name
} }

View file

@ -88,7 +88,7 @@ fn process_tabwidget(
set_geometry_prop(elem, child, "width", diag); set_geometry_prop(elem, child, "width", diag);
set_geometry_prop(elem, child, "height", diag); set_geometry_prop(elem, child, "height", diag);
let condition = Expression::BinaryExpression { let condition = Expression::BinaryExpression {
lhs: Expression::PropertyReference(NamedReference::new(elem, "current_index")).into(), lhs: Expression::PropertyReference(NamedReference::new(elem, "current-index")).into(),
rhs: Expression::NumberLiteral(index as _, Unit::None).into(), rhs: Expression::NumberLiteral(index as _, Unit::None).into(),
op: '=', op: '=',
}; };
@ -101,7 +101,7 @@ fn process_tabwidget(
} }
let mut tab = Element { let mut tab = Element {
id: format!("{}_tab{}", elem.borrow().id, index), id: format!("{}-tab{}", elem.borrow().id, index),
base_type: tab_impl.clone(), base_type: tab_impl.clone(),
enclosing_component: elem.borrow().enclosing_component.clone(), enclosing_component: elem.borrow().enclosing_component.clone(),
..Default::default() ..Default::default()
@ -112,21 +112,21 @@ fn process_tabwidget(
); );
tab.bindings.insert( tab.bindings.insert(
"current".to_owned(), "current".to_owned(),
Expression::TwoWayBinding(NamedReference::new(elem, "current_index"), None).into(), Expression::TwoWayBinding(NamedReference::new(elem, "current-index"), None).into(),
); );
tab.bindings.insert( tab.bindings.insert(
"tab_index".to_owned(), "tab-index".to_owned(),
Expression::NumberLiteral(index as _, Unit::None).into(), Expression::NumberLiteral(index as _, Unit::None).into(),
); );
tab.bindings.insert( tab.bindings.insert(
"num_tabs".to_owned(), "num-tabs".to_owned(),
Expression::NumberLiteral(num_tabs as _, Unit::None).into(), Expression::NumberLiteral(num_tabs as _, Unit::None).into(),
); );
tabs.push(Rc::new(RefCell::new(tab))); tabs.push(Rc::new(RefCell::new(tab)));
} }
let tabbar = Element { let tabbar = Element {
id: format!("{}_tabbar", elem.borrow().id), id: format!("{}-tabbar", elem.borrow().id),
base_type: tabbar_impl.clone(), base_type: tabbar_impl.clone(),
enclosing_component: elem.borrow().enclosing_component.clone(), enclosing_component: elem.borrow().enclosing_component.clone(),
children: tabs, children: tabs,
@ -138,27 +138,27 @@ fn process_tabwidget(
set_tabbar_geometry_prop(elem, &tabbar, "width"); set_tabbar_geometry_prop(elem, &tabbar, "width");
set_tabbar_geometry_prop(elem, &tabbar, "height"); set_tabbar_geometry_prop(elem, &tabbar, "height");
elem.borrow_mut().bindings.insert( elem.borrow_mut().bindings.insert(
"tabbar_preferred_width".to_owned(), "tabbar-preferred-width".to_owned(),
Expression::TwoWayBinding(NamedReference::new(&tabbar, "preferred_width"), None).into(), Expression::TwoWayBinding(NamedReference::new(&tabbar, "preferred-width"), None).into(),
); );
elem.borrow_mut().bindings.insert( elem.borrow_mut().bindings.insert(
"tabbar_preferred_height".to_owned(), "tabbar-preferred-height".to_owned(),
Expression::TwoWayBinding(NamedReference::new(&tabbar, "preferred_height"), None).into(), Expression::TwoWayBinding(NamedReference::new(&tabbar, "preferred-height"), None).into(),
); );
if let Some(expr) = children if let Some(expr) = children
.iter() .iter()
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min_width"))) .map(|x| Expression::PropertyReference(NamedReference::new(x, "min-width")))
.fold1(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>')) .fold1(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'))
{ {
elem.borrow_mut().bindings.insert("content_min_width".into(), expr.into()); elem.borrow_mut().bindings.insert("content-min-width".into(), expr.into());
}; };
if let Some(expr) = children if let Some(expr) = children
.iter() .iter()
.map(|x| Expression::PropertyReference(NamedReference::new(x, "min_height"))) .map(|x| Expression::PropertyReference(NamedReference::new(x, "min-height")))
.fold1(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>')) .fold1(|lhs, rhs| crate::builtin_macros::min_max_expression(lhs, rhs, '>'))
{ {
elem.borrow_mut().bindings.insert("content_min_height".into(), expr.into()); elem.borrow_mut().bindings.insert("content-min-height".into(), expr.into());
}; };
children.push(tabbar); children.push(tabbar);
@ -175,7 +175,7 @@ fn set_geometry_prop(
prop.into(), prop.into(),
Expression::PropertyReference(NamedReference::new( Expression::PropertyReference(NamedReference::new(
tab_widget, tab_widget,
&format!("content_{}", prop), &format!("content-{}", prop),
)) ))
.into(), .into(),
); );
@ -190,7 +190,7 @@ fn set_geometry_prop(
fn set_tabbar_geometry_prop(tab_widget: &ElementRc, tabbar: &ElementRc, prop: &str) { fn set_tabbar_geometry_prop(tab_widget: &ElementRc, tabbar: &ElementRc, prop: &str) {
tabbar.borrow_mut().bindings.insert( tabbar.borrow_mut().bindings.insert(
prop.into(), prop.into(),
Expression::PropertyReference(NamedReference::new(tab_widget, &format!("tabbar_{}", prop))) Expression::PropertyReference(NamedReference::new(tab_widget, &format!("tabbar-{}", prop)))
.into(), .into(),
); );
} }

View file

@ -132,14 +132,14 @@ fn has_declared_property(elem: &Element, prop: &str) -> bool {
/// Initialize a sensible default binding for the now materialized property /// Initialize a sensible default binding for the now materialized property
fn initialize(elem: &ElementRc, name: &str) -> Option<Expression> { fn initialize(elem: &ElementRc, name: &str) -> Option<Expression> {
let expr = match name { let expr = match name {
"min_height" => layout_constraint_prop(elem, "min", Orientation::Vertical), "min-height" => layout_constraint_prop(elem, "min", Orientation::Vertical),
"min_width" => layout_constraint_prop(elem, "min", Orientation::Horizontal), "min-width" => layout_constraint_prop(elem, "min", Orientation::Horizontal),
"max_height" => layout_constraint_prop(elem, "max", Orientation::Vertical), "max-height" => layout_constraint_prop(elem, "max", Orientation::Vertical),
"max_width" => layout_constraint_prop(elem, "max", Orientation::Horizontal), "max-width" => layout_constraint_prop(elem, "max", Orientation::Horizontal),
"preferred_height" => layout_constraint_prop(elem, "preferred", Orientation::Vertical), "preferred-height" => layout_constraint_prop(elem, "preferred", Orientation::Vertical),
"preferred_width" => layout_constraint_prop(elem, "preferred", Orientation::Horizontal), "preferred-width" => layout_constraint_prop(elem, "preferred", Orientation::Horizontal),
"horizontal_stretch" => layout_constraint_prop(elem, "stretch", Orientation::Horizontal), "horizontal-stretch" => layout_constraint_prop(elem, "stretch", Orientation::Horizontal),
"vertical_stretch" => layout_constraint_prop(elem, "stretch", Orientation::Vertical), "vertical-stretch" => layout_constraint_prop(elem, "stretch", Orientation::Vertical),
"opacity" => Expression::NumberLiteral(1., Unit::None), "opacity" => Expression::NumberLiteral(1., Unit::None),
"visible" => Expression::BoolLiteral(true), "visible" => Expression::BoolLiteral(true),
_ => return None, _ => return None,

View file

@ -124,7 +124,7 @@ fn fixup_reference(nr: &mut NamedReference) {
} }
fn map_name(e: &ElementRc, s: &str) -> String { fn map_name(e: &ElementRc, s: &str) -> String {
format!("{}_{}", e.borrow().id, s) format!("{}-{}", e.borrow().id, s)
} }
/// Optimized item are not used for the fact that they are items, but their properties /// Optimized item are not used for the fact that they are items, but their properties

View file

@ -57,7 +57,7 @@ fn create_repeater_components(component: &Rc<Component>) {
if is_listview && !comp.root_element.borrow().bindings.contains_key("height") { if is_listview && !comp.root_element.borrow().bindings.contains_key("height") {
let preferred = Expression::PropertyReference(NamedReference::new( let preferred = Expression::PropertyReference(NamedReference::new(
&comp.root_element, &comp.root_element,
"preferred_height", "preferred-height",
)); ));
comp.root_element.borrow_mut().bindings.insert("height".into(), preferred.into()); comp.root_element.borrow_mut().bindings.insert("height".into(), preferred.into());
} }

View file

@ -142,7 +142,7 @@ fn select_minimal_class() {
assert_eq!( assert_eq!(
select_minimal_class_based_on_property_usage( select_minimal_class_based_on_property_usage(
&rect.native_class, &rect.native_class,
["border_width".to_owned()].iter() ["border-width".to_owned()].iter()
) )
.class_name, .class_name,
"BorderRectangle", "BorderRectangle",
@ -150,7 +150,7 @@ fn select_minimal_class() {
assert_eq!( assert_eq!(
select_minimal_class_based_on_property_usage( select_minimal_class_based_on_property_usage(
&rect.native_class, &rect.native_class,
["border_width".to_owned(), "x".to_owned()].iter() ["border-width".to_owned(), "x".to_owned()].iter()
) )
.class_name, .class_name,
"BorderRectangle", "BorderRectangle",

View file

@ -502,9 +502,12 @@ impl Expression {
let result = match global_lookup.lookup(ctx, &first_str) { let result = match global_lookup.lookup(ctx, &first_str) {
None => { None => {
if let Some(minus_pos) = first.text().find('-') { if let Some(minus_pos) = first.text().find('-') {
// Attempt to recover if the user wanted to write "-" // Attempt to recover if the user wanted to write "-" for minus
let first_str = &first.text()[0..minus_pos]; let first_str = &first.text()[0..minus_pos];
if global_lookup.lookup(ctx, first_str).is_some() { if global_lookup
.lookup(ctx, &crate::parser::normalize_identifier(first_str))
.is_some()
{
ctx.diag.push_error(format!("Unknown unqualified identifier '{}'. Use space before the '-' if you meant a subtraction", first.text()), &node); ctx.diag.push_error(format!("Unknown unqualified identifier '{}'. Use space before the '-' if you meant a subtraction", first.text()), &node);
return Expression::Invalid; return Expression::Invalid;
} }
@ -993,7 +996,10 @@ fn continue_lookup_within_element(
}; };
if let Some(minus_pos) = second.text().find('-') { if let Some(minus_pos) = second.text().find('-') {
// Attempt to recover if the user wanted to write "-" // Attempt to recover if the user wanted to write "-"
if elem.borrow().lookup_property(&second.text()[0..minus_pos]).property_type if elem
.borrow()
.lookup_property(&crate::parser::normalize_identifier(&second.text()[0..minus_pos]))
.property_type
!= Type::Invalid != Type::Invalid
{ {
err(". Use space before the '-' if you meant a subtraction"); err(". Use space before the '-' if you meant a subtraction");

View file

@ -75,7 +75,7 @@ pub(crate) fn handle_transform_and_opacity(
fn create_opacity_element(child: &ElementRc, type_register: &TypeRegister) -> ElementRc { fn create_opacity_element(child: &ElementRc, type_register: &TypeRegister) -> ElementRc {
let element = Element { let element = Element {
id: format!("{}_opacity", child.borrow().id), id: format!("{}-opacity", child.borrow().id),
base_type: type_register.lookup_element("Opacity").unwrap(), base_type: type_register.lookup_element("Opacity").unwrap(),
enclosing_component: child.borrow().enclosing_component.clone(), enclosing_component: child.borrow().enclosing_component.clone(),
bindings: std::iter::once(( bindings: std::iter::once((

View file

@ -27,7 +27,7 @@ pub fn assign_unique_id(component: &Rc<Component>) {
} else { } else {
elem_mut.base_type.to_string().to_ascii_lowercase() elem_mut.base_type.to_string().to_ascii_lowercase()
}; };
elem_mut.id = format!("{}_{}", old_id, count); elem_mut.id = format!("{}-{}", old_id, count);
}); });
rename_globals(component, count); rename_globals(component, count);
@ -42,7 +42,7 @@ fn rename_globals(component: &Rc<Component>, mut count: u32) {
// builtin global keeps its name // builtin global keeps its name
root.id = g.id.clone(); root.id = g.id.clone();
} else { } else {
root.id = format!("{}_{}", g.id, count); root.id = format!("{}-{}", g.id, count);
} }
} }
} }

View file

@ -26,7 +26,7 @@ pub fn handle_visible(component: &Rc<Component>, type_register: &TypeRegister) {
&mut |elem: &ElementRc, _| { &mut |elem: &ElementRc, _| {
let is_lowered_from_visible_property = let is_lowered_from_visible_property =
elem.borrow().native_class().map_or(false, |n| { elem.borrow().native_class().map_or(false, |n| {
Rc::ptr_eq(&n, &native_clip) && elem.borrow().id.ends_with("_visibility") Rc::ptr_eq(&n, &native_clip) && elem.borrow().id.ends_with("-visibility")
}); });
if is_lowered_from_visible_property { if is_lowered_from_visible_property {
// This is the element we just created. Skip it. // This is the element we just created. Skip it.
@ -72,7 +72,7 @@ pub fn handle_visible(component: &Rc<Component>, type_register: &TypeRegister) {
fn create_visibility_element(child: &ElementRc, native_clip: &Rc<NativeClass>) -> ElementRc { fn create_visibility_element(child: &ElementRc, native_clip: &Rc<NativeClass>) -> ElementRc {
let element = Element { let element = Element {
id: format!("{}_visibility", child.borrow().id), id: format!("{}-visibility", child.borrow().id),
base_type: Type::Native(native_clip.clone()), base_type: Type::Native(native_clip.clone()),
enclosing_component: child.borrow().enclosing_component.clone(), enclosing_component: child.borrow().enclosing_component.clone(),
bindings: std::iter::once(( bindings: std::iter::once((

View file

@ -47,7 +47,7 @@ Test := Rectangle {
WithStates { WithStates {
extra_background: background; extra_background: background;
// ^error{The binding for the property 'extra_background' is part of a binding loop} // ^error{The binding for the property 'extra-background' is part of a binding loop}
} }
} }

View file

@ -11,10 +11,10 @@ LICENSE END */
TC := Rectangle { TC := Rectangle {
outer := VerticalLayout { outer := VerticalLayout {
// ^error{The binding for the property 'width' is part of a binding loop} // ^error{The binding for the property 'width' is part of a binding loop}
// ^^error{The binding for the property 'layoutinfo_h' is part of a binding loop} // ^^error{The binding for the property 'layoutinfo-h' is part of a binding loop}
inner := HorizontalLayout { inner := HorizontalLayout {
// ^error{The binding for the property 'width' is part of a binding loop} // ^error{The binding for the property 'width' is part of a binding loop}
// ^^error{The binding for the property 'layoutinfo_h' is part of a binding loop} // ^^error{The binding for the property 'layoutinfo-h' is part of a binding loop}
inner_inner := VerticalLayout { inner_inner := VerticalLayout {
width: parent.width; width: parent.width;
// ^error{The binding for the property 'width' is part of a binding loop} // ^error{The binding for the property 'width' is part of a binding loop}
@ -27,8 +27,8 @@ TC := Rectangle {
Test := Rectangle { Test := Rectangle {
VerticalLayout { VerticalLayout {
// ^error{The binding for the property 'layoutinfo_h' is part of a binding loop} // FIXME: That's an internal property, but people might understand // ^error{The binding for the property 'layoutinfo-h' is part of a binding loop} // FIXME: That's an internal property, but people might understand
// ^^error{The binding for the property 'min_width' is part of a binding loop} // ^^error{The binding for the property 'min-width' is part of a binding loop}
Rectangle { Rectangle {
width: parent.min_width; width: parent.min_width;
// ^error{The binding for the property 'width' is part of a binding loop} // ^error{The binding for the property 'width' is part of a binding loop}
@ -37,8 +37,8 @@ Test := Rectangle {
l := HorizontalLayout { l := HorizontalLayout {
// ^error{The binding for the property 'layoutinfo_h' is part of a binding loop} // FIXME: That's an internal property, but people might understand // ^error{The binding for the property 'layoutinfo-h' is part of a binding loop} // FIXME: That's an internal property, but people might understand
// ^^error{The binding for the property 'preferred_width' is part of a binding loop} // ^^error{The binding for the property 'preferred-width' is part of a binding loop}
Text { Text {
text: "hello \{l.preferred-width/1px}x\{l.preferred-height/1px}"; text: "hello \{l.preferred-width/1px}x\{l.preferred-height/1px}";
// ^error{The binding for the property 'text' is part of a binding loop} // ^error{The binding for the property 'text' is part of a binding loop}
@ -46,8 +46,8 @@ Test := Rectangle {
} }
tc := TC { tc := TC {
// ^error{The binding for the property 'preferred_width' is part of a binding loop} // ^error{The binding for the property 'preferred-width' is part of a binding loop}
// ^^error{The binding for the property 'layoutinfo_h' is part of a binding loop} // ^^error{The binding for the property 'layoutinfo-h' is part of a binding loop}
width: preferred-width; width: preferred-width;
// ^error{The binding for the property 'width' is part of a binding loop} // ^error{The binding for the property 'width' is part of a binding loop}
} }

View file

@ -12,9 +12,9 @@ LICENSE END */
Test := Rectangle { Test := Rectangle {
property <image> source; property <image> source;
GridLayout { GridLayout {
// ^error{The binding for the property 'layout_cache_h' is part of a binding loop} // ^error{The binding for the property 'layout-cache-h' is part of a binding loop}
// ^^error{The binding for the property 'width' is part of a binding loop} // ^^error{The binding for the property 'width' is part of a binding loop}
// ^^^error{The binding for the property 'layout_cache_v' is part of a binding loop} // ^^^error{The binding for the property 'layout-cache-v' is part of a binding loop}
// ^^^^error{The binding for the property 'height' is part of a binding loop} // ^^^^error{The binding for the property 'height' is part of a binding loop}
Image { Image {
source: root.source; source: root.source;

View file

@ -9,11 +9,11 @@
LICENSE END */ LICENSE END */
SuperSimple := Rectangle { SuperSimple := Rectangle {
drop-shadow-color: #00000080; drop-shadow-color: #00000080;
// ^warning{The drop_shadow_color property cannot be used on the root element, the shadow will not be visible} // ^warning{The drop-shadow-color property cannot be used on the root element, the shadow will not be visible}
Text { Text {
drop-shadow-color: black; drop-shadow-color: black;
// ^error{The drop_shadow_color property is only supported on Rectangle and Clip elements right now} // ^error{The drop-shadow-color property is only supported on Rectangle and Clip elements right now}
} }
} }

View file

@ -18,7 +18,7 @@ X := Rectangle {
// ^error{Duplicated property binding} // ^error{Duplicated property binding}
not_exist <=> 12phx; not_exist <=> 12phx;
// ^error{Unknown property not_exist in Rectangle} // ^error{Unknown property not-exist in Rectangle}
property <int> foo: 12; property <int> foo: 12;
foo: 13; foo: 13;

View file

@ -17,6 +17,6 @@ X := Rectangle {
callback xxx() -> string; callback xxx() -> string;
xxx => { xxx => {
return 42phx; return 42phx;
// ^error{Cannot convert physical_length to string. Divide by 1phx to convert to a plain number} // ^error{Cannot convert physical-length to string. Divide by 1phx to convert to a plain number}
} }
} }

View file

@ -34,13 +34,13 @@ SubElements := Rectangle {
} }
does_not_exist => { does_not_exist => {
// ^error{'does_not_exist' is not a callback in Rectangle} // ^error{'does-not-exist' is not a callback in Rectangle}
root.does_not_exist(); root.does_not_exist();
} }
foobar() => { foobar() } foobar() => { foobar() }
callback_with_arg(a, b, c, d) => { } callback_with_arg(a, b, c, d) => { }
// ^error{'callback_with_arg' only has 2 arguments, but 4 were provided} // ^error{'callback-with-arg' only has 2 arguments, but 4 were provided}
} }

View file

@ -20,7 +20,7 @@ TestCase := Rectangle {
transitions [ transitions [
in does_not_exist: { in does_not_exist: {
// ^error{State 'does_not_exist' does not exist} // ^error{State 'does-not-exist' does not exist}
animate * { } animate * { }
} }
in checked: { in checked: {

View file

@ -26,7 +26,7 @@ export Demo := Window {
t.y: 100px; t.y: 100px;
// ^error{Cannot change the property 'y' in a state because it is initialized with a two-way binding} // ^error{Cannot change the property 'y' in a state because it is initialized with a two-way binding}
some_prop: "plop"; some_prop: "plop";
// ^error{Cannot change the property 'some_prop' in a state because it is initialized with a two-way binding} // ^error{Cannot change the property 'some-prop' in a state because it is initialized with a two-way binding}
} }
] ]
} }

View file

@ -23,7 +23,7 @@ SuperSimple := Rectangle {
Rectangle { Rectangle {
background: blue; background: blue;
foo_bar: blue; foo_bar: blue;
// ^error{Unknown property foo_bar in Rectangle} // ^error{Unknown property foo-bar in Rectangle}
} }
} }
@ -45,7 +45,7 @@ SuperSimple := Rectangle {
Rectangle { Rectangle {
foo_bar: blue; foo_bar: blue;
// ^error{Unknown property foo_bar in Rectangle} // ^error{Unknown property foo-bar in Rectangle}
} }
NativeLineEdit { } NativeLineEdit { }

View file

@ -12,13 +12,13 @@ Test := Rectangle {
GridLayout { GridLayout {
Rectangle { Rectangle {
height: 42px; height: 42px;
// ^error{Cannot specify both 'height' and 'min_height'} // ^error{Cannot specify both 'height' and 'min-height'}
min-height: 42px; min-height: 42px;
max-width: 42px; max-width: 42px;
} }
Rectangle { Rectangle {
width: 42px; width: 42px;
// ^error{Cannot specify both 'width' and 'max_width'} // ^error{Cannot specify both 'width' and 'max-width'}
min-height: 42px; min-height: 42px;
max-width: 42px; max-width: 42px;
} }

View file

@ -22,8 +22,8 @@ Xxx := Rectangle {
} }
minimum-height: root.maximum-width; minimum-height: root.maximum-width;
// ^warning{The property 'minimum_height' has been deprecated. Please use 'min_height' instead} // ^warning{The property 'minimum-height' has been deprecated. Please use 'min-height' instead}
// ^^warning{The property 'maximum_width' has been deprecated. Please use 'max_width' instead} // ^^warning{The property 'maximum-width' has been deprecated. Please use 'max-width' instead}
callback not_called; callback not_called;
not_called() => { not_called() => {

View file

@ -65,7 +65,7 @@ Hello := Rectangle {
y: pp.b; y: pp.b;
// ^error{Cannot convert string to length} // ^error{Cannot convert string to length}
property<int> ggg: pp; property<int> ggg: pp;
// ^error{Cannot convert \{ a: physical_length,b: string,\} to int} // ^error{Cannot convert \{ a: physical-length,b: string,\} to int}
} }

View file

@ -37,6 +37,6 @@ X := Rectangle {
x <=> self.loop_on_x; x <=> self.loop_on_x;
// ^error{The binding for the property 'x' is part of a binding loop} // ^error{The binding for the property 'x' is part of a binding loop}
property <length> loop_on_x <=> x; property <length> loop_on_x <=> x;
// ^error{The binding for the property 'loop_on_x' is part of a binding loop} // ^error{The binding for the property 'loop-on-x' is part of a binding loop}
} }
} }

View file

@ -11,20 +11,20 @@ LICENSE END */
X := Rectangle { X := Rectangle {
property infer_loop <=> infer_loop2; property infer_loop <=> infer_loop2;
// ^error{Could not infer type of property 'infer_loop'} // ^error{Could not infer type of property 'infer-loop'}
property infer_loop2 <=> infer_loop3; property infer_loop2 <=> infer_loop3;
// ^error{Could not infer type of property 'infer_loop2'} // ^error{Could not infer type of property 'infer-loop2'}
property infer_loop3 <=> infer_loop; property infer_loop3 <=> infer_loop;
// ^error{Could not infer type of property 'infer_loop3'} // ^error{Could not infer type of property 'infer-loop3'}
// ^^error{Unknown unqualified identifier 'infer_loop'} // ^^error{Unknown unqualified identifier 'infer_loop'}
// ^^^error{The expression in a two way binding must be a property reference} // ^^^error{The expression in a two way binding must be a property reference}
property infer_error <=> r.infer_error; property infer_error <=> r.infer_error;
// ^error{Could not infer type of property 'infer_error'} // ^error{Could not infer type of property 'infer-error'}
r := Rectangle { r := Rectangle {
property infer_error <=> 0; property infer_error <=> 0;
// ^error{The expression in a two way binding must be a property reference} // ^error{The expression in a two way binding must be a property reference}
// ^^error{Could not infer type of property 'infer_error'} // ^^error{Could not infer type of property 'infer-error'}
} }
property auto_background <=> background; property auto_background <=> background;

View file

@ -24,19 +24,19 @@ pub(crate) const RESERVED_GEOMETRY_PROPERTIES: &[(&str, Type)] = &[
]; ];
const RESERVED_LAYOUT_PROPERTIES: &[(&str, Type)] = &[ const RESERVED_LAYOUT_PROPERTIES: &[(&str, Type)] = &[
("min_width", Type::LogicalLength), ("min-width", Type::LogicalLength),
("min_height", Type::LogicalLength), ("min-height", Type::LogicalLength),
("max_width", Type::LogicalLength), ("max-width", Type::LogicalLength),
("max_height", Type::LogicalLength), ("max-height", Type::LogicalLength),
("padding", Type::LogicalLength), ("padding", Type::LogicalLength),
("padding_left", Type::LogicalLength), ("padding-left", Type::LogicalLength),
("padding_right", Type::LogicalLength), ("padding-right", Type::LogicalLength),
("padding_top", Type::LogicalLength), ("padding-top", Type::LogicalLength),
("padding_bottom", Type::LogicalLength), ("padding-bottom", Type::LogicalLength),
("preferred_width", Type::LogicalLength), ("preferred-width", Type::LogicalLength),
("preferred_height", Type::LogicalLength), ("preferred-height", Type::LogicalLength),
("horizontal_stretch", Type::Float32), ("horizontal-stretch", Type::Float32),
("vertical_stretch", Type::Float32), ("vertical-stretch", Type::Float32),
("col", Type::Int32), ("col", Type::Int32),
("row", Type::Int32), ("row", Type::Int32),
("colspan", Type::Int32), ("colspan", Type::Int32),
@ -50,10 +50,10 @@ const RESERVED_OTHER_PROPERTIES: &[(&str, Type)] = &[
]; ];
pub(crate) const RESERVED_DROP_SHADOW_PROPERTIES: &[(&str, Type)] = &[ pub(crate) const RESERVED_DROP_SHADOW_PROPERTIES: &[(&str, Type)] = &[
("drop_shadow_offset_x", Type::LogicalLength), ("drop-shadow-offset-x", Type::LogicalLength),
("drop_shadow_offset_y", Type::LogicalLength), ("drop-shadow-offset-y", Type::LogicalLength),
("drop_shadow_blur", Type::LogicalLength), ("drop-shadow-blur", Type::LogicalLength),
("drop_shadow_color", Type::Color), ("drop-shadow-color", Type::Color),
]; ];
/// list of reserved property injected in every item /// list of reserved property injected in every item
@ -65,7 +65,7 @@ pub fn reserved_properties() -> impl Iterator<Item = (&'static str, Type)> {
.chain(RESERVED_DROP_SHADOW_PROPERTIES.iter()) .chain(RESERVED_DROP_SHADOW_PROPERTIES.iter())
.map(|(k, v)| (*k, v.clone())) .map(|(k, v)| (*k, v.clone()))
.chain(std::array::IntoIter::new([ .chain(std::array::IntoIter::new([
("forward_focus", Type::ElementReference), ("forward-focus", Type::ElementReference),
("focus", BuiltinFunction::SetFocusItem.ty()), ("focus", BuiltinFunction::SetFocusItem.ty()),
])) ]))
} }
@ -83,10 +83,10 @@ pub fn reserved_property(name: &str) -> PropertyLookupResult {
if let Some(a) = name.strip_prefix(pre) { if let Some(a) = name.strip_prefix(pre) {
for suf in &["width", "height"] { for suf in &["width", "height"] {
if let Some(b) = a.strip_suffix(suf) { if let Some(b) = a.strip_suffix(suf) {
if b == "imum_" { if b == "imum-" {
return PropertyLookupResult { return PropertyLookupResult {
property_type: Type::LogicalLength, property_type: Type::LogicalLength,
resolved_name: format!("{}_{}", pre, suf).into(), resolved_name: format!("{}-{}", pre, suf).into(),
}; };
} }
} }
@ -164,11 +164,11 @@ impl TypeRegister {
declare_enum("TextHorizontalAlignment", &["left", "center", "right"]); declare_enum("TextHorizontalAlignment", &["left", "center", "right"]);
declare_enum("TextVerticalAlignment", &["top", "center", "bottom"]); declare_enum("TextVerticalAlignment", &["top", "center", "bottom"]);
declare_enum("TextWrap", &["no_wrap", "word_wrap"]); declare_enum("TextWrap", &["no-wrap", "word-wrap"]);
declare_enum("TextOverflow", &["clip", "elide"]); declare_enum("TextOverflow", &["clip", "elide"]);
declare_enum( declare_enum(
"LayoutAlignment", "LayoutAlignment",
&["stretch", "center", "start", "end", "space_between", "space_around"], &["stretch", "center", "start", "end", "space-between", "space-around"],
); );
declare_enum("ImageFit", &["fill", "contain", "cover"]); declare_enum("ImageFit", &["fill", "contain", "cover"]);
declare_enum("EventResult", &["reject", "accept"]); declare_enum("EventResult", &["reject", "accept"]);

View file

@ -39,6 +39,7 @@ pub fn sixtyfps_element(input: TokenStream) -> TokenStream {
}; };
let mut pub_prop_field_names = Vec::new(); let mut pub_prop_field_names = Vec::new();
let mut pub_prop_field_names_normalized = Vec::new();
let mut pub_prop_field_types = Vec::new(); let mut pub_prop_field_types = Vec::new();
let mut property_names = Vec::new(); let mut property_names = Vec::new();
let mut property_visibility = Vec::new(); let mut property_visibility = Vec::new();
@ -47,6 +48,7 @@ pub fn sixtyfps_element(input: TokenStream) -> TokenStream {
if let Some(property_type) = property_type(&field.ty) { if let Some(property_type) = property_type(&field.ty) {
let name = field.ident.as_ref().unwrap(); let name = field.ident.as_ref().unwrap();
if matches!(field.vis, syn::Visibility::Public(_)) { if matches!(field.vis, syn::Visibility::Public(_)) {
pub_prop_field_names_normalized.push(normalize_identifier(name));
pub_prop_field_names.push(name); pub_prop_field_names.push(name);
pub_prop_field_types.push(&field.ty); pub_prop_field_types.push(&field.ty);
} }
@ -73,14 +75,18 @@ pub fn sixtyfps_element(input: TokenStream) -> TokenStream {
}) })
.map(|f| (f.ident.as_ref().unwrap(), &f.ty)) .map(|f| (f.ident.as_ref().unwrap(), &f.ty))
.unzip(); .unzip();
let plain_field_names_normalized =
plain_field_names.iter().map(|f| normalize_identifier(*f)).collect::<Vec<_>>();
let mut callback_field_names = Vec::new(); let mut callback_field_names = Vec::new();
let mut callback_field_names_normalized = Vec::new();
let mut callback_args = Vec::new(); let mut callback_args = Vec::new();
let mut callback_rets = Vec::new(); let mut callback_rets = Vec::new();
for field in fields { for field in fields {
if let Some((arg, ret)) = callback_arg(&field.ty) { if let Some((arg, ret)) = callback_arg(&field.ty) {
if matches!(field.vis, syn::Visibility::Public(_)) { if matches!(field.vis, syn::Visibility::Public(_)) {
let name = field.ident.as_ref().unwrap(); let name = field.ident.as_ref().unwrap();
callback_field_names_normalized.push(normalize_identifier(name));
callback_field_names.push(name); callback_field_names.push(name);
callback_args.push(arg); callback_args.push(arg);
callback_rets.push(ret); callback_rets.push(ret);
@ -101,21 +107,21 @@ pub fn sixtyfps_element(input: TokenStream) -> TokenStream {
vec![#( { vec![#( {
const O : MaybeAnimatedPropertyInfoWrapper<#item_name, #pub_prop_field_types> = const O : MaybeAnimatedPropertyInfoWrapper<#item_name, #pub_prop_field_types> =
MaybeAnimatedPropertyInfoWrapper(#item_name::FIELD_OFFSETS.#pub_prop_field_names); MaybeAnimatedPropertyInfoWrapper(#item_name::FIELD_OFFSETS.#pub_prop_field_names);
(stringify!(#pub_prop_field_names), (&O).as_property_info()) (#pub_prop_field_names_normalized, (&O).as_property_info())
} ),*] } ),*]
} }
fn fields<Value: ValueType>() -> Vec<(&'static str, &'static dyn FieldInfo<Self, Value>)> { fn fields<Value: ValueType>() -> Vec<(&'static str, &'static dyn FieldInfo<Self, Value>)> {
vec![#( { vec![#( {
const O : const_field_offset::FieldOffset<#item_name, #plain_field_types, const_field_offset::AllowPin> = const O : const_field_offset::FieldOffset<#item_name, #plain_field_types, const_field_offset::AllowPin> =
#item_name::FIELD_OFFSETS.#plain_field_names; #item_name::FIELD_OFFSETS.#plain_field_names;
(stringify!(#plain_field_names), &O as &'static dyn FieldInfo<Self, Value>) (#plain_field_names_normalized, &O as &'static dyn FieldInfo<Self, Value>)
} ),*] } ),*]
} }
fn callbacks<Value: ValueType>() -> Vec<(&'static str, &'static dyn CallbackInfo<Self, Value>)> { fn callbacks<Value: ValueType>() -> Vec<(&'static str, &'static dyn CallbackInfo<Self, Value>)> {
vec![#( { vec![#( {
const O : const_field_offset::FieldOffset<#item_name, Callback<#callback_args, #callback_rets>, const_field_offset::AllowPin> = const O : const_field_offset::FieldOffset<#item_name, Callback<#callback_args, #callback_rets>, const_field_offset::AllowPin> =
#item_name::FIELD_OFFSETS.#callback_field_names; #item_name::FIELD_OFFSETS.#callback_field_names;
(stringify!(#callback_field_names), &O as &'static dyn CallbackInfo<Self, Value>) (#callback_field_names_normalized, &O as &'static dyn CallbackInfo<Self, Value>)
} ),*] } ),*]
} }
} }
@ -131,6 +137,10 @@ pub fn sixtyfps_element(input: TokenStream) -> TokenStream {
.into() .into()
} }
fn normalize_identifier(name: &syn::Ident) -> String {
name.to_string().replace('_', "-")
}
// Try to match `Property<Foo>` on the syn tree and return Foo if found // Try to match `Property<Foo>` on the syn tree and return Foo if found
fn property_type(ty: &syn::Type) -> Option<&syn::Type> { fn property_type(ty: &syn::Type) -> Option<&syn::Type> {
if let syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) = ty { if let syn::Type::Path(syn::TypePath { path: syn::Path { segments, .. }, .. }) = ty {

View file

@ -12,6 +12,7 @@ use core::convert::TryInto;
use sixtyfps_compilerlib::langtype::Type as LangType; use sixtyfps_compilerlib::langtype::Type as LangType;
use sixtyfps_corelib::graphics::Image; use sixtyfps_corelib::graphics::Image;
use sixtyfps_corelib::{Brush, PathData, SharedString, SharedVector}; use sixtyfps_corelib::{Brush, PathData, SharedString, SharedVector};
use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::iter::FromIterator; use std::iter::FromIterator;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -281,7 +282,9 @@ macro_rules! declare_value_enum_conversion {
return Err(()); return Err(());
} }
<$ty>::from_str(value.as_str()).map_err(|_| ()) <$ty>::from_str(value.as_str())
.or_else(|_| <$ty>::from_str(&value.as_str().replace('-', "_")))
.map_err(|_| ())
} }
_ => Err(()), _ => Err(()),
} }
@ -352,6 +355,15 @@ impl TryInto<sixtyfps_corelib::Color> for Value {
} }
} }
/// Normalize the identifier to use dashes
fn normalize_identifier(ident: &str) -> Cow<'_, str> {
if ident.contains('_') {
ident.replace('_', "-").into()
} else {
ident.into()
}
}
/// This type represents a runtime instance of structure in `.60`. /// This type represents a runtime instance of structure in `.60`.
/// ///
/// This can either be an instance of a name structure introduced /// This can either be an instance of a name structure introduced
@ -378,12 +390,16 @@ pub struct Struct(HashMap<String, Value>);
impl Struct { impl Struct {
/// Get the value for a given struct field /// Get the value for a given struct field
pub fn get_field(&self, name: &str) -> Option<&Value> { pub fn get_field(&self, name: &str) -> Option<&Value> {
self.0.get(name) self.0.get(&*normalize_identifier(name))
} }
/// Set the value of a given struct field /// Set the value of a given struct field
pub fn set_field(&mut self, name: String, value: Value) { pub fn set_field(&mut self, name: String, value: Value) {
if name.contains('_') {
self.0.insert(name.replace('_', "-"), value);
} else {
self.0.insert(name, value); self.0.insert(name, value);
} }
}
/// Iterate over all the fields in this struct /// Iterate over all the fields in this struct
pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> { pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
@ -393,7 +409,11 @@ impl Struct {
impl FromIterator<(String, Value)> for Struct { impl FromIterator<(String, Value)> for Struct {
fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
Self(iter.into_iter().collect()) Self(
iter.into_iter()
.map(|(s, v)| (if s.contains('_') { s.replace('_', "-") } else { s }, v))
.collect(),
)
} }
} }
@ -700,7 +720,7 @@ impl ComponentInstance {
generativity::make_guard!(guard); generativity::make_guard!(guard);
let comp = self.inner.unerase(guard); let comp = self.inner.unerase(guard);
comp.description() comp.description()
.get_property(comp.borrow(), name) .get_property(comp.borrow(), &normalize_identifier(name))
.map_err(|()| GetPropertyError::NoSuchProperty) .map_err(|()| GetPropertyError::NoSuchProperty)
} }
@ -709,7 +729,7 @@ impl ComponentInstance {
generativity::make_guard!(guard); generativity::make_guard!(guard);
let comp = self.inner.unerase(guard); let comp = self.inner.unerase(guard);
comp.description() comp.description()
.set_property(comp.borrow(), name, value) .set_property(comp.borrow(), &normalize_identifier(name), value)
.map_err(|()| todo!("set_property don't return the right error type")) .map_err(|()| todo!("set_property don't return the right error type"))
} }
@ -754,7 +774,7 @@ impl ComponentInstance {
generativity::make_guard!(guard); generativity::make_guard!(guard);
let comp = self.inner.unerase(guard); let comp = self.inner.unerase(guard);
comp.description() comp.description()
.set_callback_handler(comp.borrow(), name, Box::new(callback)) .set_callback_handler(comp.borrow(), &normalize_identifier(name), Box::new(callback))
.map_err(|()| SetCallbackError::NoSuchCallback) .map_err(|()| SetCallbackError::NoSuchCallback)
} }
@ -765,7 +785,9 @@ impl ComponentInstance {
pub fn invoke_callback(&self, name: &str, args: &[Value]) -> Result<Value, CallCallbackError> { pub fn invoke_callback(&self, name: &str, args: &[Value]) -> Result<Value, CallCallbackError> {
generativity::make_guard!(guard); generativity::make_guard!(guard);
let comp = self.inner.unerase(guard); let comp = self.inner.unerase(guard);
comp.description().invoke_callback(comp.borrow(), name, args).map_err(|()| todo!()) comp.description()
.invoke_callback(comp.borrow(), &normalize_identifier(name), args)
.map_err(|()| todo!())
} }
/// Marks the window of this component to be shown on the screen. This registers /// Marks the window of this component to be shown on the screen. This registers

View file

@ -85,7 +85,7 @@ try {
instance.test_callback(); instance.test_callback();
assert(false); assert(false);
} catch(e) { } catch(e) {
assert.equal(e.toString(), "Error: test_callback expect 1 arguments, but 0 where provided"); assert.equal(e.toString(), "Error: test-callback expect 1 arguments, but 0 where provided");
} }
assert.equal(instance.callback_emission_count, 0); assert.equal(instance.callback_emission_count, 0);

View file

@ -66,6 +66,7 @@ let super_player = { name: "Super Player", score: 99, energy_level: 0.4 };
instance.player_2 = super_player; instance.player_2 = super_player;
assert.equal(instance.player_2.name, "Super Player"); assert.equal(instance.player_2.name, "Super Player");
assert.equal(instance.player_2_score, 99); assert.equal(instance.player_2_score, 99);
assert.equal(instance.player_2.energy_level, 0.4);
``` ```
*/ */