Split Expression::CallbackReference and Expresison::FunctionReference

This commit is contained in:
Olivier Goffart 2022-12-01 15:27:31 +01:00 committed by Olivier Goffart
parent 4672e54f5e
commit dfdbc942f6
14 changed files with 74 additions and 49 deletions

View file

@ -346,9 +346,12 @@ pub enum Expression {
/// Note: if we are to separate expression and statement, we probably do not need to have callback reference within expressions
CallbackReference(NamedReference),
/// Reference to the callback `<name>` in the `<element>`
/// Reference to the property
PropertyReference(NamedReference),
/// Reference to a Function
FunctionReference(NamedReference),
/// Reference to a function built into the run-time, implemented natively
BuiltinFunctionReference(BuiltinFunction, Option<SourceLocation>),
@ -516,6 +519,7 @@ impl Expression {
Expression::NumberLiteral(_, unit) => unit.ty(),
Expression::BoolLiteral(_) => Type::Bool,
Expression::CallbackReference(nr) => nr.ty(),
Expression::FunctionReference(nr) => nr.ty(),
Expression::PropertyReference(nr) => nr.ty(),
Expression::BuiltinFunctionReference(funcref, _) => funcref.ty(),
Expression::MemberFunction { member, .. } => member.ty(),
@ -653,6 +657,7 @@ impl Expression {
Expression::BoolLiteral(_) => {}
Expression::CallbackReference { .. } => {}
Expression::PropertyReference { .. } => {}
Expression::FunctionReference { .. } => {}
Expression::FunctionParameterReference { .. } => {}
Expression::BuiltinFunctionReference { .. } => {}
Expression::MemberFunction { base, member, .. } => {
@ -749,6 +754,7 @@ impl Expression {
Expression::BoolLiteral(_) => {}
Expression::CallbackReference { .. } => {}
Expression::PropertyReference { .. } => {}
Expression::FunctionReference { .. } => {}
Expression::FunctionParameterReference { .. } => {}
Expression::BuiltinFunctionReference { .. } => {}
Expression::MemberFunction { base, member, .. } => {
@ -859,6 +865,7 @@ impl Expression {
Expression::NumberLiteral(_, _) => true,
Expression::BoolLiteral(_) => true,
Expression::CallbackReference { .. } => false,
Expression::FunctionReference(nr) => nr.is_constant(),
Expression::PropertyReference(nr) => nr.is_constant(),
Expression::BuiltinFunctionReference(func, _) => func.is_pure(),
Expression::MemberFunction { .. } => false,
@ -1364,6 +1371,7 @@ pub fn pretty_print(f: &mut dyn std::fmt::Write, expression: &Expression) -> std
Expression::BoolLiteral(b) => write!(f, "{:?}", b),
Expression::CallbackReference(a) => write!(f, "{:?}", a),
Expression::PropertyReference(a) => write!(f, "{:?}", a),
Expression::FunctionReference(a) => write!(f, "{:?}", a),
Expression::BuiltinFunctionReference(a, _) => write!(f, "{:?}", a),
Expression::MemberFunction { base, base_node: _, member } => {
pretty_print(f, base)?;

View file

@ -68,10 +68,9 @@ pub fn lower_expression(
llr_Expression::NumberLiteral(unit.normalize(*n))
}
tree_Expression::BoolLiteral(b) => llr_Expression::BoolLiteral(*b),
tree_Expression::CallbackReference(nr) => {
llr_Expression::PropertyReference(ctx.map_property_reference(nr))
}
tree_Expression::PropertyReference(nr) => {
tree_Expression::CallbackReference(nr)
| tree_Expression::PropertyReference(nr)
| tree_Expression::FunctionReference(nr) => {
llr_Expression::PropertyReference(ctx.map_property_reference(nr))
}
tree_Expression::BuiltinFunctionReference(_, _) => panic!(),
@ -123,17 +122,11 @@ pub fn lower_expression(
}
tree_Expression::CallbackReference(nr) => {
let arguments = arguments.iter().map(|e| lower_expression(e, ctx)).collect::<_>();
if matches!(nr.ty(), Type::Function { .. }) {
llr_Expression::FunctionCall {
function: ctx.map_property_reference(nr),
arguments,
}
} else {
llr_Expression::CallBackCall {
callback: ctx.map_property_reference(nr),
arguments,
}
}
llr_Expression::CallBackCall { callback: ctx.map_property_reference(nr), arguments }
}
tree_Expression::FunctionReference(nr) => {
let arguments = arguments.iter().map(|e| lower_expression(e, ctx)).collect::<_>();
llr_Expression::FunctionCall { function: ctx.map_property_reference(nr), arguments }
}
_ => panic!("not calling a function"),
},

View file

@ -421,10 +421,10 @@ impl LookupObject for ElementRc {
}
fn expression_from_reference(n: NamedReference, ty: &Type) -> Expression {
if matches!(ty, Type::Callback { .. } | Type::Function { .. }) {
Expression::CallbackReference(n)
} else {
Expression::PropertyReference(n)
match ty {
Type::Callback { .. } => Expression::CallbackReference(n),
Type::Function { .. } => Expression::FunctionReference(n),
_ => Expression::PropertyReference(n),
}
}

View file

@ -1878,7 +1878,9 @@ pub fn visit_named_references_in_expression(
) {
expr.visit_mut(|sub| visit_named_references_in_expression(sub, vis));
match expr {
Expression::PropertyReference(r) | Expression::CallbackReference(r) => vis(r),
Expression::PropertyReference(r)
| Expression::CallbackReference(r)
| Expression::FunctionReference(r) => vis(r),
Expression::LayoutCacheAccess { layout_cache_prop, .. } => vis(layout_cache_prop),
Expression::SolveLayout(l, _) => l.visit_named_references(vis),
Expression::ComputeLayoutInfo(l, _) => l.visit_named_references(vis),

View file

@ -334,9 +334,9 @@ fn process_property(
fn recurse_expression(expr: &Expression, vis: &mut impl FnMut(&PropertyPath)) {
expr.visit(|sub| recurse_expression(sub, vis));
match expr {
Expression::PropertyReference(r) | Expression::CallbackReference(r) => {
vis(&r.clone().into())
}
Expression::PropertyReference(r)
| Expression::CallbackReference(r)
| Expression::FunctionReference(r) => vis(&r.clone().into()),
Expression::LayoutCacheAccess { layout_cache_prop, .. } => {
vis(&layout_cache_prop.clone().into())
}

View file

@ -119,6 +119,7 @@ fn simplify_expression(expr: &mut Expression) -> bool {
Expression::CallbackReference { .. } => false,
Expression::ElementReference { .. } => false,
// FIXME
Expression::FunctionReference { .. } => false,
Expression::LayoutCacheAccess { .. } => false,
Expression::SolveLayout { .. } => false,
Expression::ComputeLayoutInfo { .. } => false,

View file

@ -215,7 +215,9 @@ fn expression_for_property(element: &ElementRc, name: &str) -> ExpressionForProp
// Check that the expresison is valid in the new scope
let mut has_invalid = false;
e.expression.visit_recursive(&mut |ex| match ex {
Expression::CallbackReference(nr) | Expression::PropertyReference(nr) => {
Expression::CallbackReference(nr)
| Expression::PropertyReference(nr)
| Expression::FunctionReference(nr) => {
let e = nr.element();
if !Rc::ptr_eq(&e, &element)
&& Weak::ptr_eq(

View file

@ -570,11 +570,15 @@ impl Expression {
expression: r @ Expression::CallbackReference(..), ..
} => {
if let Some(x) = it.next() {
if matches!(r.ty(), Type::Function { .. }) {
ctx.diag.push_error("Cannot access fields of a function".into(), &x)
} else {
ctx.diag.push_error("Cannot access fields of callback".into(), &x)
}
ctx.diag.push_error("Cannot access fields of callback".into(), &x)
}
r
}
LookupResult::Expression {
expression: r @ Expression::FunctionReference(..), ..
} => {
if let Some(x) = it.next() {
ctx.diag.push_error("Cannot access fields of a function".into(), &x)
}
r
}
@ -1073,7 +1077,7 @@ fn continue_lookup_within_element(
member: Box::new(member),
}
} else {
Expression::CallbackReference(NamedReference::new(elem, &lookup_result.resolved_name))
Expression::FunctionReference(NamedReference::new(elem, &lookup_result.resolved_name))
}
} else {
let mut err = |extra: &str| {
@ -1293,6 +1297,10 @@ pub fn resolve_two_way_binding(
Some(n)
}
}
Expression::FunctionReference(..) => {
ctx.diag.push_error("Cannot bind to a function".into(), &node);
None
}
_ => {
ctx.diag.push_error(
"The expression in a two way binding must be a property reference".into(),

View file

@ -41,6 +41,10 @@ Xxx := Rectangle {
Abc { par => {} }
// ^error{'par' is not a callback in Abc}
aa := Abc { par: 42; }
// ^error{Cannot assign to par in Abc because it does not have a valid property type}
Abc { par <=> aa.par; }
// ^error{Cannot assign to par in Abc because it does not have a valid property type}
fooo => {}
// ^error{'fooo' is not a callback in Rectangle}

View file

@ -19,8 +19,8 @@ Xxx := Rectangle {
root.foo.hello(45);
// ^error{Cannot access fields of a function}
}
callback xx <=> foo;
// ^error{Cannot bind to a function}
}

View file

@ -142,6 +142,7 @@ pub fn eval_expression(expression: &Expression, local_context: &mut EvalLocalCon
Expression::NumberLiteral(n, unit) => Value::Number(unit.normalize(*n)),
Expression::BoolLiteral(b) => Value::Bool(*b),
Expression::CallbackReference { .. } => panic!("callback in expression"),
Expression::FunctionReference { .. } => panic!("function in expression"),
Expression::BuiltinFunctionReference(..) => panic!(
"naked builtin function reference not allowed, should be handled by function call"
),
@ -211,22 +212,22 @@ pub fn eval_expression(expression: &Expression, local_context: &mut EvalLocalCon
v
}
Expression::FunctionCall { function, arguments, source_location: _ } => match &**function {
Expression::FunctionReference(nr) => {
let args = arguments.iter().map(|e| eval_expression(e, local_context)).collect::<Vec<_>>();
generativity::make_guard!(guard);
match enclosing_component_instance_for_element(&nr.element(), local_context.component_instance, guard) {
ComponentInstance::InstanceRef(c) => {
let mut ctx = EvalLocalContext::from_function_arguments(c, args);
eval_expression(&nr.element().borrow().bindings.get(nr.name()).unwrap().borrow().expression, &mut ctx)
}
ComponentInstance::GlobalComponent(g) => {
g.as_ref().eval_function(nr.name(), args).unwrap()
},
}
}
Expression::CallbackReference(nr) => {
let args = arguments.iter().map(|e| eval_expression(e, local_context)).collect::<Vec<_>>();
if matches!(nr.ty(), Type::Function { .. }) {
generativity::make_guard!(guard);
match enclosing_component_instance_for_element(&nr.element(), local_context.component_instance, guard) {
ComponentInstance::InstanceRef(c) => {
let mut ctx = EvalLocalContext::from_function_arguments(c, args);
eval_expression(&nr.element().borrow().bindings.get(nr.name()).unwrap().borrow().expression, &mut ctx)
}
ComponentInstance::GlobalComponent(g) => {
g.as_ref().eval_function(nr.name(), args).unwrap()
},
}
} else {
invoke_callback(local_context.component_instance, &nr.element(), nr.name(), &args).unwrap()
}
invoke_callback(local_context.component_instance, &nr.element(), nr.name(), &args).unwrap()
}
Expression::BuiltinFunctionReference(f, _) => call_builtin_function(*f, arguments, local_context),
_ => panic!("call of something not a callback: {function:?}"),

View file

@ -454,6 +454,7 @@ fn completion_item_from_expression(str: &str, lookup_result: LookupResult) -> Co
c.kind = match expression {
Expression::BoolLiteral(_) => Some(CompletionItemKind::CONSTANT),
Expression::CallbackReference(_) => Some(CompletionItemKind::METHOD),
Expression::FunctionReference(_) => Some(CompletionItemKind::FUNCTION),
Expression::PropertyReference(_) => Some(CompletionItemKind::PROPERTY),
Expression::BuiltinFunctionReference(..) => Some(CompletionItemKind::FUNCTION),
Expression::BuiltinMacroReference(..) => Some(CompletionItemKind::FUNCTION),

View file

@ -71,7 +71,9 @@ pub fn goto_definition(
} => e.upgrade()?.borrow().node.clone()?.into(),
LookupResult::Expression {
expression:
Expression::CallbackReference(nr) | Expression::PropertyReference(nr),
Expression::CallbackReference(nr)
| Expression::PropertyReference(nr)
| Expression::FunctionReference(nr),
..
} => {
let mut el = nr.element();

View file

@ -125,7 +125,10 @@ fn fully_qualify_property_access(
let global_lookup = i_slint_compiler::lookup::global_lookup();
match global_lookup.lookup(ctx, &first_str) {
Some(LookupResult::Expression {
expression: Expression::PropertyReference(nr) | Expression::CallbackReference(nr),
expression:
Expression::PropertyReference(nr)
| Expression::CallbackReference(nr)
| Expression::FunctionReference(nr),
..
}) => {
if let Some(new_name) = state.lookup_change.property_mappings.get(&nr) {