mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00
WIP: Implement the return statement
This commit is contained in:
parent
16a75a2ff8
commit
b22bbb1c0f
6 changed files with 128 additions and 6 deletions
|
@ -363,6 +363,8 @@ pub enum Expression {
|
|||
EasingCurve(EasingCurve),
|
||||
|
||||
EnumerationValue(EnumerationValue),
|
||||
|
||||
ReturnStatement(Option<Box<Expression>>),
|
||||
}
|
||||
|
||||
impl Default for Expression {
|
||||
|
@ -469,6 +471,7 @@ impl Expression {
|
|||
Expression::ReadLocalVariable { ty, .. } => ty.clone(),
|
||||
Expression::EasingCurve(_) => Type::Easing,
|
||||
Expression::EnumerationValue(value) => Type::Enumeration(value.enumeration.clone()),
|
||||
Expression::ReturnStatement(expr) => expr.as_ref().map_or(Type::Void, |expr| expr.ty()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -542,6 +545,9 @@ impl Expression {
|
|||
Expression::ReadLocalVariable { .. } => {}
|
||||
Expression::EasingCurve(_) => {}
|
||||
Expression::EnumerationValue(_) => {}
|
||||
Expression::ReturnStatement(expr) => {
|
||||
expr.as_deref().map(|expr| visitor(expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -614,6 +620,9 @@ impl Expression {
|
|||
Expression::ReadLocalVariable { .. } => {}
|
||||
Expression::EasingCurve(_) => {}
|
||||
Expression::EnumerationValue(_) => {}
|
||||
Expression::ReturnStatement(expr) => {
|
||||
expr.as_deref_mut().map(|expr| visitor(expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -666,6 +675,9 @@ impl Expression {
|
|||
Expression::ReadLocalVariable { .. } => false,
|
||||
Expression::EasingCurve(_) => true,
|
||||
Expression::EnumerationValue(_) => true,
|
||||
Expression::ReturnStatement(expr) => {
|
||||
expr.as_ref().map_or(true, |expr| expr.is_constant())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -676,6 +688,13 @@ impl Expression {
|
|||
node: &impl SpannedWithSourceFile,
|
||||
diag: &mut BuildDiagnostics,
|
||||
) -> Expression {
|
||||
if let Expression::ReturnStatement(expr) = self {
|
||||
return Expression::ReturnStatement(expr.map(|mut expr| {
|
||||
let expr = std::mem::replace(&mut *expr, Expression::Invalid);
|
||||
Box::new(expr.maybe_convert_to(target_type, node, diag))
|
||||
}));
|
||||
}
|
||||
|
||||
let ty = self.ty();
|
||||
if ty == target_type || target_type == Type::Void || target_type == Type::Invalid {
|
||||
self
|
||||
|
|
|
@ -1452,8 +1452,18 @@ fn compile_expression(
|
|||
}
|
||||
}
|
||||
Expression::CodeBlock(sub) => {
|
||||
let mut x = sub.iter().map(|e| compile_expression(e, component)).collect::<Vec<_>>();
|
||||
let len = sub.len();
|
||||
let mut x = sub.iter().enumerate().map(|(i, e)| {
|
||||
match e {
|
||||
Expression::ReturnStatement(return_expr) if i == len - 1 => {
|
||||
return_expr.as_ref().map_or_else(String::new, |return_expr| compile_expression(return_expr, component))
|
||||
},
|
||||
e => compile_expression(e, component)
|
||||
}
|
||||
|
||||
}).collect::<Vec<_>>();
|
||||
if let Some(s) = x.last_mut() { *s = format!("return {};", s) };
|
||||
|
||||
format!("[&]{{ {} }}()", x.join(";"))
|
||||
}
|
||||
Expression::FunctionCall { function, arguments, source_location: _ } => match &**function {
|
||||
|
@ -1608,6 +1618,7 @@ fn compile_expression(
|
|||
}
|
||||
Expression::Uncompiled(_) | Expression::TwoWayBinding(..) => panic!(),
|
||||
Expression::Invalid => "\n#error invalid expression\n".to_string(),
|
||||
Expression::ReturnStatement(expr) => format!("return {};", expr.as_ref().map_or_else(String::new, |expr| compile_expression(expr, component))),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1296,6 +1296,10 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
|
|||
let value_ident = format_ident!("{}", value.to_string());
|
||||
quote!(sixtyfps::re_exports::#base_ident::#value_ident)
|
||||
}
|
||||
Expression::ReturnStatement(expr) => {
|
||||
let return_expr = expr.as_ref().map(|expr| compile_expression(expr, component));
|
||||
quote!(return (#return_expr) as _;)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -269,11 +269,49 @@ impl Expression {
|
|||
|
||||
fn from_codeblock_node(node: syntax_nodes::CodeBlock, ctx: &mut LookupCtx) -> Expression {
|
||||
debug_assert_eq!(node.kind(), SyntaxKind::CodeBlock);
|
||||
Expression::CodeBlock(
|
||||
node.children()
|
||||
.filter(|n| n.kind() == SyntaxKind::Expression)
|
||||
.map(|n| Self::from_expression_node(n.into(), ctx))
|
||||
.collect(),
|
||||
|
||||
let mut statements_or_exprs = node
|
||||
.children()
|
||||
.filter_map(|n| match n.kind() {
|
||||
SyntaxKind::Expression => Some(Self::from_expression_node(n.into(), ctx)),
|
||||
SyntaxKind::ReturnStatement => Some(Self::from_return_statement(n.into(), ctx)),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let exit_points_and_return_types = statements_or_exprs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, statement_or_expr)| {
|
||||
if index == statements_or_exprs.len()
|
||||
|| matches!(statement_or_expr, Expression::ReturnStatement(..))
|
||||
{
|
||||
Some((index, statement_or_expr.ty()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let common_return_type = Self::common_target_type_for_type_list(
|
||||
exit_points_and_return_types.iter().map(|(_, ty)| ty.clone()),
|
||||
);
|
||||
|
||||
exit_points_and_return_types.into_iter().for_each(|(index, _)| {
|
||||
let mut expr = std::mem::replace(&mut statements_or_exprs[index], Expression::Invalid);
|
||||
expr = expr.maybe_convert_to(common_return_type.clone(), &node, &mut ctx.diag);
|
||||
statements_or_exprs[index] = expr;
|
||||
});
|
||||
|
||||
Expression::CodeBlock(statements_or_exprs)
|
||||
}
|
||||
|
||||
fn from_return_statement(
|
||||
node: syntax_nodes::ReturnStatement,
|
||||
ctx: &mut LookupCtx,
|
||||
) -> Expression {
|
||||
Expression::ReturnStatement(
|
||||
node.Expression().map(|n| Box::new(Self::from_expression_node(n.into(), ctx))),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -360,6 +360,9 @@ pub fn eval_expression(e: &Expression, local_context: &mut EvalLocalContext) ->
|
|||
Expression::CodeBlock(sub) => {
|
||||
let mut v = Value::Void;
|
||||
for e in sub {
|
||||
if let Expression::ReturnStatement(expr) = e {
|
||||
return expr.as_ref().map_or(Value::Void, |expr| eval_expression(expr, local_context))
|
||||
}
|
||||
v = eval_expression(e, local_context);
|
||||
}
|
||||
v
|
||||
|
@ -606,6 +609,7 @@ pub fn eval_expression(e: &Expression, local_context: &mut EvalLocalContext) ->
|
|||
Expression::EnumerationValue(value) => {
|
||||
Value::EnumerationValue(value.enumeration.name.clone(), value.to_string())
|
||||
}
|
||||
Expression::ReturnStatement(_) => panic!("internal error: return statement must only appear inside code block and handled there")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
46
tests/cases/expr/return.60
Normal file
46
tests/cases/expr/return.60
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* LICENSE BEGIN
|
||||
This file is part of the SixtyFPS Project -- https://sixtyfps.io
|
||||
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
|
||||
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
This file is also available under commercial licensing terms.
|
||||
Please contact info@sixtyfps.io for more information.
|
||||
LICENSE END */
|
||||
TestCase := Rectangle {
|
||||
property <bool> toggle;
|
||||
property <int> value: {
|
||||
if (toggle) {
|
||||
return 42;
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
|
||||
signal test_signal;
|
||||
property <bool> block_signal;
|
||||
property <bool> signal_handled;
|
||||
test_signal => {
|
||||
if (block_signal) {
|
||||
return;
|
||||
}
|
||||
signal_handled = true;
|
||||
}
|
||||
}
|
||||
/*
|
||||
```cpp
|
||||
auto handle = TestCase::create();
|
||||
const TestCase &instance = *handle;
|
||||
assert_eq(instance.get_value(), 100);
|
||||
instance.set_toggle(true);
|
||||
assert_eq(instance.get_value(), 42);
|
||||
|
||||
instance.emit_test_signal();
|
||||
assert(instance.get_signal_handled());
|
||||
|
||||
instance.set_signal_handled(false);
|
||||
instance.set_block_signal(true);
|
||||
instance.emit_test_signal();
|
||||
assert(!instance.get_signal_handled());
|
||||
```
|
||||
|
||||
*/
|
Loading…
Add table
Add a link
Reference in a new issue