Change Type::Object to be able to hold a name

Internally, structure will be represented with a Type::Object with a name
instead of a Component with a void base type
This commit is contained in:
Olivier Goffart 2020-10-27 15:03:31 +01:00
parent b9533a217e
commit 333c96fd79
9 changed files with 176 additions and 66 deletions

View file

@ -182,10 +182,10 @@ fn to_eval_value<'cx>(
}, },
Type::Resource => Ok(Value::String(val.to_string(cx)?.value().into())), Type::Resource => Ok(Value::String(val.to_string(cx)?.value().into())),
Type::Bool => Ok(Value::Bool(val.downcast_or_throw::<JsBoolean, _>(cx)?.value())), Type::Bool => Ok(Value::Bool(val.downcast_or_throw::<JsBoolean, _>(cx)?.value())),
Type::Object(o) => { Type::Object{fields, ..} => {
let obj = val.downcast_or_throw::<JsObject, _>(cx)?; let obj = val.downcast_or_throw::<JsObject, _>(cx)?;
Ok(Value::Object( Ok(Value::Object(
o fields
.iter() .iter()
.map(|(pro_name, pro_ty)| { .map(|(pro_name, pro_ty)| {
Ok(( Ok((

View file

@ -362,7 +362,9 @@ impl Expression {
} }
Expression::FunctionParameterReference { ty, .. } => ty.clone(), Expression::FunctionParameterReference { ty, .. } => ty.clone(),
Expression::ObjectAccess { base, name } => match base.ty() { Expression::ObjectAccess { base, name } => match base.ty() {
Type::Object(o) => o.get(name.as_str()).unwrap_or(&Type::Invalid).clone(), Type::Object { fields, .. } => {
fields.get(name.as_str()).unwrap_or(&Type::Invalid).clone()
}
Type::Component(c) => c.root_element.borrow().lookup_property(name.as_str()), Type::Component(c) => c.root_element.borrow().lookup_property(name.as_str()),
_ => Type::Invalid, _ => Type::Invalid,
}, },
@ -636,7 +638,9 @@ impl Expression {
rhs: Box::new(Expression::NumberLiteral(0.01, Unit::None)), rhs: Box::new(Expression::NumberLiteral(0.01, Unit::None)),
op: '*', op: '*',
}, },
(Type::Object(ref a), Type::Object(b)) => { (Type::Object { fields: ref a, .. }, Type::Object { fields: b, name })
if a != b =>
{
if let Expression::Object { mut values, .. } = self { if let Expression::Object { mut values, .. } = self {
let mut new_values = HashMap::new(); let mut new_values = HashMap::new();
for (k, ty) in b { for (k, ty) in b {
@ -655,7 +659,7 @@ impl Expression {
Expression::ObjectAccess { Expression::ObjectAccess {
base: Box::new(Expression::ReadLocalVariable { base: Box::new(Expression::ReadLocalVariable {
name: var_name.into(), name: var_name.into(),
ty: Type::Object(a.clone()), ty: Type::Object { fields: a.clone(), name: name.clone() },
}), }),
name: k.clone(), name: k.clone(),
} }
@ -678,9 +682,10 @@ impl Expression {
Expression::Object { values: new_values, ty: target_type }, Expression::Object { values: new_values, ty: target_type },
]); ]);
} }
(Type::Object(_), Type::Component(c)) => { (Type::Object { .. }, Type::Component(c)) => {
let object_type_for_component = Type::Object( let object_type_for_component = Type::Object {
c.root_element fields: c
.root_element
.borrow() .borrow()
.property_declarations .property_declarations
.iter() .iter()
@ -688,7 +693,8 @@ impl Expression {
(name.clone(), prop_decl.property_type.clone()) (name.clone(), prop_decl.property_type.clone())
}) })
.collect(), .collect(),
); name: None,
};
self.maybe_convert_to(object_type_for_component, None, node, diag) self.maybe_convert_to(object_type_for_component, None, node, diag)
} }
_ => self, _ => self,
@ -777,9 +783,9 @@ impl Expression {
Type::Array(element_ty) => { Type::Array(element_ty) => {
Expression::Array { element_ty: (**element_ty).clone(), values: vec![] } Expression::Array { element_ty: (**element_ty).clone(), values: vec![] }
} }
Type::Object(map) => Expression::Object { Type::Object { fields, .. } => Expression::Object {
ty: ty.clone(), ty: ty.clone(),
values: map values: fields
.into_iter() .into_iter()
.map(|(k, v)| (k.clone(), Expression::default_value_for_type(v))) .map(|(k, v)| (k.clone(), Expression::default_value_for_type(v)))
.collect(), .collect(),

View file

@ -207,11 +207,15 @@ 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::Object(o) => { Type::Object { fields, name } => {
let elem = o.values().map(|v| v.cpp_type()).collect::<Option<Vec<_>>>()?; if let Some(name) = name {
Some(name.clone())
} else {
let elem = fields.values().map(|v| v.cpp_type()).collect::<Option<Vec<_>>>()?;
// This will produce a tuple // This will produce a tuple
Some(format!("std::tuple<{}>", elem.join(", "))) Some(format!("std::tuple<{}>", elem.join(", ")))
} }
}
Type::Array(i) => Some(format!("std::shared_ptr<sixtyfps::Model<{}>>", i.cpp_type()?)), Type::Array(i) => Some(format!("std::shared_ptr<sixtyfps::Model<{}>>", i.cpp_type()?)),
Type::Resource => Some("sixtyfps::Resource".to_owned()), Type::Resource => Some("sixtyfps::Resource".to_owned()),
Type::Builtin(elem) => elem.native_class.cpp_type.clone(), Type::Builtin(elem) => elem.native_class.cpp_type.clone(),
@ -1181,13 +1185,16 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
} }
Expression::ReadLocalVariable { name, .. } => name.clone(), Expression::ReadLocalVariable { name, .. } => name.clone(),
Expression::ObjectAccess { base, name } => match base.ty() { Expression::ObjectAccess { base, name } => match base.ty() {
Type::Object(ty) => { Type::Object { fields, name : None } => {
let index = ty let index = fields
.keys() .keys()
.position(|k| k == name) .position(|k| k == name)
.expect("Expression::ObjectAccess: Cannot find a key in an object"); .expect("Expression::ObjectAccess: Cannot find a key in an object");
format!("std::get<{}>({})", index, compile_expression(base, component)) format!("std::get<{}>({})", index, compile_expression(base, component))
} }
Type::Object{..} => {
format!("{}.{}", compile_expression(base, component), name)
}
Type::Component(c) if c.root_element.borrow().base_type == Type::Void => { Type::Component(c) if c.root_element.borrow().base_type == Type::Void => {
format!("{}.{}", compile_expression(base, component), name) format!("{}.{}", compile_expression(base, component), name)
} }
@ -1206,7 +1213,7 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
(Type::Float32, Type::Color) => { (Type::Float32, Type::Color) => {
format!("sixtyfps::Color::from_argb_encoded({})", f) format!("sixtyfps::Color::from_argb_encoded({})", f)
} }
(Type::Object(_), Type::Component(c)) (Type::Object { .. }, Type::Component(c))
if c.root_element.borrow().base_type == Type::Void => if c.root_element.borrow().base_type == Type::Void =>
{ {
format!( format!(
@ -1219,6 +1226,17 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
.join("; ") .join("; ")
) )
} }
(Type::Object { .. }, Type::Object{ fields, name: Some(n)}) => {
format!(
"[&](const auto &o){{ {struct_name} s; auto& [{field_members}] = s; {fields}; return s; }}({obj})",
struct_name = n,
field_members = (0..fields.len()).map(|idx| format!("f_{}", idx)).join(", "),
obj = f,
fields = (0..fields.len())
.map(|idx| format!("f_{} = std::get<{}>(o)", idx, idx))
.join("; ")
)
}
_ => f, _ => f,
} }
} }
@ -1321,14 +1339,18 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
) )
} }
Expression::Object { ty, values } => { Expression::Object { ty, values } => {
if let Type::Object(ty) = ty { if let Type::Object{fields, name} = ty {
let mut elem = ty.keys().map(|k| { let mut elem = fields.keys().map(|k| {
values values
.get(k) .get(k)
.map(|e| compile_expression(e, component)) .map(|e| compile_expression(e, component))
.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 {
format!("{}{{{}}}", name, elem.join(", "))
} else {
format!("std::make_tuple({})", elem.join(", ")) format!("std::make_tuple({})", elem.join(", "))
}
} else { } else {
panic!("Expression::Object is not a Type::Object") panic!("Expression::Object is not a Type::Object")
} }
@ -1367,13 +1389,14 @@ fn compile_assignment(
let get_obj = compile_expression(base, component); let get_obj = compile_expression(base, component);
let ty = base.ty(); let ty = base.ty();
let member = match &ty { let member = match &ty {
Type::Object(ty) => { Type::Object { fields, name: None } => {
let index = ty let index = fields
.keys() .keys()
.position(|k| k == name) .position(|k| k == name)
.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::Object { .. } => format!("{}.{}", tmpobj, name),
Type::Component(c) if c.root_element.borrow().base_type == Type::Void => { Type::Component(c) if c.root_element.borrow().base_type == Type::Void => {
format!("{}.{}", tmpobj, name) format!("{}.{}", tmpobj, name)
} }

View file

@ -36,11 +36,13 @@ fn rust_type(
Type::Percent => Ok(quote!(f32)), Type::Percent => Ok(quote!(f32)),
Type::Bool => Ok(quote!(bool)), Type::Bool => Ok(quote!(bool)),
Type::Resource => Ok(quote!(sixtyfps::re_exports::Resource)), Type::Resource => Ok(quote!(sixtyfps::re_exports::Resource)),
Type::Object(o) => { Type::Object { fields, name: None } => {
let elem = o.values().map(|v| rust_type(v, span)).collect::<Result<Vec<_>, _>>()?; let elem =
fields.values().map(|v| rust_type(v, span)).collect::<Result<Vec<_>, _>>()?;
// This will produce a tuple // This will produce a tuple
Ok(quote!((#(#elem,)*))) Ok(quote!((#(#elem,)*)))
} }
Type::Object { name: Some(name), .. } => Ok(name.parse().unwrap()),
Type::Array(o) => { Type::Array(o) => {
let inner = rust_type(&o, span)?; let inner = rust_type(&o, span)?;
Ok(quote!(sixtyfps::re_exports::ModelHandle<#inner>)) Ok(quote!(sixtyfps::re_exports::ModelHandle<#inner>))
@ -968,8 +970,8 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
(Type::Float32, Type::Color) => { (Type::Float32, Type::Color) => {
quote!(sixtyfps::re_exports::Color::from_argb_encoded(#f as u32)) quote!(sixtyfps::re_exports::Color::from_argb_encoded(#f as u32))
} }
(Type::Object(ref o), Type::Component(c)) => { (Type::Object { ref fields, .. }, Type::Component(c)) => {
let fields = o.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!("{}", name); let name = format_ident!("{}", name);
quote!(#name: obj.#index as _) quote!(#name: obj.#index as _)
@ -977,6 +979,15 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
let id : TokenStream = c.id.parse().unwrap(); let id : TokenStream = c.id.parse().unwrap();
quote!({ let obj = #f; #id { #(#fields),*} }) quote!({ let obj = #f; #id { #(#fields),*} })
} }
(Type::Object { ref fields, .. }, Type::Object{ name: Some(n), .. }) => {
let fields = fields.iter().enumerate().map(|(index, (name, _))| {
let index = proc_macro2::Literal::usize_unsuffixed(index);
let name = format_ident!("{}", name);
quote!(#name: obj.#index as _)
});
let id : TokenStream = n.parse().unwrap();
quote!({ let obj = #f; #id { #(#fields),*} })
}
_ => f, _ => f,
} }
} }
@ -1019,8 +1030,8 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
quote! {args.#i.clone()} quote! {args.#i.clone()}
} }
Expression::ObjectAccess { base, name } => match base.ty() { Expression::ObjectAccess { base, name } => match base.ty() {
Type::Object(ty) => { Type::Object { fields, name: None } => {
let index = ty let index = fields
.keys() .keys()
.position(|k| k == name) .position(|k| k == name)
.expect("Expression::ObjectAccess: Cannot find a key in an object"); .expect("Expression::ObjectAccess: Cannot find a key in an object");
@ -1028,6 +1039,11 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
let base_e = compile_expression(base, component); let base_e = compile_expression(base, component);
quote!((#base_e).#index ) quote!((#base_e).#index )
} }
Type::Object { .. } => {
let name = format_ident!("{}", name);
let base_e = compile_expression(base, component);
quote!((#base_e).#name)
}
Type::Component(c) if c.root_element.borrow().base_type == Type::Void => { Type::Component(c) if c.root_element.borrow().base_type == Type::Void => {
let base_e = compile_expression(base, component); let base_e = compile_expression(base, component);
let name = format_ident!("{}", name); let name = format_ident!("{}", name);
@ -1164,16 +1180,22 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
)) ))
} }
Expression::Object { ty, values } => { Expression::Object { ty, values } => {
if let Type::Object(ty) = ty { if let Type::Object { fields, name } = ty {
let elem = ty.iter().map(|(k, t)| { let elem = fields.iter().map(|(k, t)| {
values.get(k).map(|e| { values.get(k).map(|e| {
let ce = compile_expression(e, component); let ce = compile_expression(e, component);
let t = rust_type(t, &Default::default()).unwrap_or_default(); let t = rust_type(t, &Default::default()).unwrap_or_default();
quote!(#ce as #t) quote!(#ce as #t)
}) })
}); });
if let Some(name) = name {
let name : TokenStream = name.parse().unwrap();
let keys = fields.keys().map(|k| k.parse::<TokenStream>().unwrap());
quote!(#name { #(#keys: #elem,)* })
} else {
// This will produce a tuple // This will produce a tuple
quote!((#(#elem,)*)) quote!((#(#elem,)*))
}
} else { } else {
panic!("Expression::Object is not a Type::Object") panic!("Expression::Object is not a Type::Object")
} }
@ -1227,13 +1249,18 @@ fn compile_assignment(
let get_obj = compile_expression(base, component); let get_obj = compile_expression(base, component);
let ty = base.ty(); let ty = base.ty();
let (member, member_ty) = match &ty { let (member, member_ty) = match &ty {
Type::Object(ty) => { Type::Object { fields, name: None } => {
let index = ty let index = fields
.keys() .keys()
.position(|k| k == name) .position(|k| k == name)
.expect("Expression::ObjectAccess: Cannot find a key in an object"); .expect("Expression::ObjectAccess: Cannot find a key in an object");
let index = proc_macro2::Literal::usize_unsuffixed(index); let index = proc_macro2::Literal::usize_unsuffixed(index);
(quote!(#index), ty[name].clone()) (quote!(#index), fields[name].clone())
}
Type::Object { fields, name: Some(_) } => {
let n = format_ident!("{}", name);
(quote!(#n), fields[name].clone())
} }
Type::Component(c) if c.root_element.borrow().base_type == Type::Void => { Type::Component(c) if c.root_element.borrow().base_type == Type::Void => {
let n = format_ident!("{}", name); let n = format_ident!("{}", name);

View file

@ -48,7 +48,10 @@ pub enum Type {
Easing, Easing,
Array(Box<Type>), Array(Box<Type>),
Object(BTreeMap<String, Type>), Object {
fields: BTreeMap<String, Type>,
name: Option<String>,
},
Enumeration(Rc<Enumeration>), Enumeration(Rc<Enumeration>),
EnumerationValue(EnumerationValue), EnumerationValue(EnumerationValue),
@ -82,7 +85,9 @@ impl core::cmp::PartialEq for Type {
Type::PathElements => matches!(other, Type::PathElements), Type::PathElements => matches!(other, Type::PathElements),
Type::Easing => matches!(other, Type::Easing), Type::Easing => matches!(other, Type::Easing),
Type::Array(a) => matches!(other, Type::Array(b) if a == b), Type::Array(a) => matches!(other, Type::Array(b) if a == b),
Type::Object(a) => matches!(other, Type::Object(b) if a == b), Type::Object { fields, name } => {
matches!(other, Type::Object{fields: f, name: n} if fields == f && name == n)
}
Type::Enumeration(lhs) => matches!(other, Type::Enumeration(rhs) if lhs == rhs), Type::Enumeration(lhs) => matches!(other, Type::Enumeration(rhs) if lhs == rhs),
Type::EnumerationValue(lhs) => { Type::EnumerationValue(lhs) => {
matches!(other, Type::EnumerationValue(rhs) if lhs == rhs) matches!(other, Type::EnumerationValue(rhs) if lhs == rhs)
@ -136,9 +141,12 @@ impl Display for Type {
Type::Bool => write!(f, "bool"), Type::Bool => write!(f, "bool"),
Type::Model => write!(f, "model"), Type::Model => write!(f, "model"),
Type::Array(t) => write!(f, "[{}]", t), Type::Array(t) => write!(f, "[{}]", t),
Type::Object(t) => { Type::Object { fields, name } => {
if let Some(name) = name {
write!(f, "{}", name)?;
}
write!(f, "{{ ")?; write!(f, "{{ ")?;
for (k, v) in t { for (k, v) in fields {
write!(f, "{}: {},", k, v)?; write!(f, "{}: {},", k, v)?;
} }
write!(f, "}}") write!(f, "}}")
@ -176,7 +184,7 @@ impl Type {
| Self::Easing | Self::Easing
| Self::Enumeration(_) | Self::Enumeration(_)
| Self::ElementReference | Self::ElementReference
| Self::Object(_) | Self::Object { .. }
| Self::Array(_) => true, | Self::Array(_) => true,
Self::Component(c) => c.root_element.borrow().base_type == Type::Void, Self::Component(c) => c.root_element.borrow().base_type == Type::Void,
_ => false, _ => false,
@ -321,8 +329,16 @@ impl Type {
| (Type::Length, Type::LogicalLength) | (Type::Length, Type::LogicalLength)
| (Type::LogicalLength, Type::Length) | (Type::LogicalLength, Type::Length)
| (Type::Percent, Type::Float32) => true, | (Type::Percent, Type::Float32) => true,
(Type::Object(a), Type::Object(b)) if can_convert_object(a, b) => true, (Type::Object { fields: a, .. }, Type::Object { fields: b, .. })
(Type::Object(a), Type::Component(c)) if can_convert_object_to_component(a, c) => true, if can_convert_object(a, b) =>
{
true
}
(Type::Object { fields, .. }, Type::Component(c))
if can_convert_object_to_component(fields, c) =>
{
true
}
_ => false, _ => false,
} }
} }
@ -372,7 +388,7 @@ impl Type {
Type::PathElements => None, Type::PathElements => None,
Type::Easing => None, Type::Easing => None,
Type::Array(_) => None, Type::Array(_) => None,
Type::Object(_) => None, Type::Object { .. } => None,
Type::Enumeration(_) => None, Type::Enumeration(_) => None,
Type::EnumerationValue(_) => None, Type::EnumerationValue(_) => None,
Type::ElementReference => None, Type::ElementReference => None,

View file

@ -41,16 +41,45 @@ impl Document {
let mut local_registry = TypeRegister::new(parent_registry); let mut local_registry = TypeRegister::new(parent_registry);
let mut inner_components = vec![]; let mut inner_components = vec![];
let mut process_component = |n: syntax_nodes::Component| { let mut process_component =
let compo = Component::from_node(n, diag, &local_registry); |n: syntax_nodes::Component,
diag: &mut FileDiagnostics,
local_registry: &mut TypeRegister| {
let compo = Component::from_node(n, diag, local_registry);
local_registry.add(compo.clone()); local_registry.add(compo.clone());
inner_components.push(compo); inner_components.push(compo);
}; };
let process_struct = |n: syntax_nodes::StructDeclaration,
diag: &mut FileDiagnostics,
local_registry: &mut TypeRegister| {
let mut ty = type_struct_from_node(n.ObjectType(), diag, local_registry);
if let Type::Object { name, .. } = &mut ty {
*name = identifier_text(&n.DeclaredIdentifier());
} else {
assert!(diag.has_error());
return;
}
local_registry.insert_type(ty);
};
for n in node.children() { for n in node.children() {
match n.kind() { match n.kind() {
SyntaxKind::Component => process_component(n.into()), SyntaxKind::Component => process_component(n.into(), diag, &mut local_registry),
SyntaxKind::StructDeclaration => {
process_struct(n.into(), diag, &mut local_registry)
}
SyntaxKind::ExportsList => { SyntaxKind::ExportsList => {
syntax_nodes::ExportsList::from(n).Component().for_each(&mut process_component) for n in n.children() {
match n.kind() {
SyntaxKind::Component => {
process_component(n.into(), diag, &mut local_registry)
}
SyntaxKind::StructDeclaration => {
process_struct(n.into(), diag, &mut local_registry)
}
_ => {}
}
}
} }
_ => {} _ => {}
}; };
@ -712,16 +741,7 @@ fn type_from_node(node: syntax_nodes::Type, diag: &mut FileDiagnostics, tr: &Typ
} }
prop_type prop_type
} else if let Some(object_node) = node.ObjectType() { } else if let Some(object_node) = node.ObjectType() {
let map = object_node type_struct_from_node(object_node, diag, tr)
.ObjectTypeMember()
.map(|member| {
(
identifier_text(&member).unwrap_or_default(),
type_from_node(member.Type(), diag, tr),
)
})
.collect();
Type::Object(map)
} else if let Some(array_node) = node.ArrayType() { } else if let Some(array_node) = node.ArrayType() {
Type::Array(Box::new(type_from_node(array_node.Type(), diag, tr))) Type::Array(Box::new(type_from_node(array_node.Type(), diag, tr)))
} else { } else {
@ -730,6 +750,20 @@ fn type_from_node(node: syntax_nodes::Type, diag: &mut FileDiagnostics, tr: &Typ
} }
} }
fn type_struct_from_node(
object_node: syntax_nodes::ObjectType,
diag: &mut FileDiagnostics,
tr: &TypeRegister,
) -> Type {
let fields = object_node
.ObjectTypeMember()
.map(|member| {
(identifier_text(&member).unwrap_or_default(), type_from_node(member.Type(), diag, tr))
})
.collect();
Type::Object { fields, name: None }
}
fn animation_element_from_node( fn animation_element_from_node(
anim: &syntax_nodes::PropertyAnimation, anim: &syntax_nodes::PropertyAnimation,
prop_name: &syntax_nodes::QualifiedName, prop_name: &syntax_nodes::QualifiedName,

View file

@ -807,7 +807,10 @@ impl Expression {
) )
}) })
.collect(); .collect();
let ty = Type::Object(values.iter().map(|(k, v)| (k.clone(), v.ty())).collect()); let ty = Type::Object {
fields: values.iter().map(|(k, v)| (k.clone(), v.ty())).collect(),
name: None,
};
Expression::Object { ty, values } Expression::Object { ty, values }
} }
@ -855,14 +858,14 @@ fn maybe_lookup_object(
while let Some(next) = it.next() { while let Some(next) = it.next() {
let next_str = crate::parser::normalize_identifier(next.text().as_str()); let next_str = crate::parser::normalize_identifier(next.text().as_str());
match base.ty() { match base.ty() {
Type::Object(obj) => { Type::Object { fields, .. } => {
if obj.get(next_str.as_str()).is_some() { if fields.get(next_str.as_str()).is_some() {
base = Expression::ObjectAccess { base = Expression::ObjectAccess {
base: Box::new(std::mem::replace(&mut base, Expression::Invalid)), base: Box::new(std::mem::replace(&mut base, Expression::Invalid)),
name: next_str, name: next_str,
} }
} else { } else {
return error_or_try_minus(ctx, next, |x| obj.get(x).is_some()); return error_or_try_minus(ctx, next, |x| fields.get(x).is_some());
} }
} }
Type::Component(c) => { Type::Component(c) => {

View file

@ -64,7 +64,8 @@ pub struct TypeRegister {
} }
impl TypeRegister { impl TypeRegister {
fn insert_type(&mut self, t: Type) { /// FIXME: same as 'add' ?
pub fn insert_type(&mut self, t: Type) {
self.types.insert(t.to_string(), t); self.types.insert(t.to_string(), t);
} }

View file

@ -599,7 +599,7 @@ fn generate_component<'id>(
.insert(name.clone(), builder.add_field_type::<Signal<[eval::Value]>>()); .insert(name.clone(), builder.add_field_type::<Signal<[eval::Value]>>());
continue; continue;
} }
Type::Object(_) => property_info::<eval::Value>(), Type::Object { .. } => property_info::<eval::Value>(),
Type::Array(_) => property_info::<eval::Value>(), Type::Array(_) => property_info::<eval::Value>(),
Type::Component(ref c) if c.root_element.borrow().base_type == Type::Void => { Type::Component(ref c) if c.root_element.borrow().base_type == Type::Void => {
property_info::<eval::Value>() property_info::<eval::Value>()