mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 22:54:36 +00:00
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:
parent
b9533a217e
commit
333c96fd79
9 changed files with 176 additions and 66 deletions
|
@ -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((
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -207,10 +207,14 @@ 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 {
|
||||||
// This will produce a tuple
|
Some(name.clone())
|
||||||
Some(format!("std::tuple<{}>", elem.join(", ")))
|
} else {
|
||||||
|
let elem = fields.values().map(|v| v.cpp_type()).collect::<Option<Vec<_>>>()?;
|
||||||
|
// This will produce a tuple
|
||||||
|
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()),
|
||||||
|
@ -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())
|
||||||
});
|
});
|
||||||
format!("std::make_tuple({})", elem.join(", "))
|
if let Some(name) = name {
|
||||||
|
format!("{}{{{}}}", name, elem.join(", "))
|
||||||
|
} else {
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
// This will produce a tuple
|
if let Some(name) = name {
|
||||||
quote!((#(#elem,)*))
|
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
|
||||||
|
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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
local_registry.add(compo.clone());
|
diag: &mut FileDiagnostics,
|
||||||
inner_components.push(compo);
|
local_registry: &mut TypeRegister| {
|
||||||
|
let compo = Component::from_node(n, diag, local_registry);
|
||||||
|
local_registry.add(compo.clone());
|
||||||
|
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,
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue