mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 14:21: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),
|
EasingCurve(EasingCurve),
|
||||||
|
|
||||||
EnumerationValue(EnumerationValue),
|
EnumerationValue(EnumerationValue),
|
||||||
|
|
||||||
|
ReturnStatement(Option<Box<Expression>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Expression {
|
impl Default for Expression {
|
||||||
|
@ -469,6 +471,7 @@ impl Expression {
|
||||||
Expression::ReadLocalVariable { ty, .. } => ty.clone(),
|
Expression::ReadLocalVariable { ty, .. } => ty.clone(),
|
||||||
Expression::EasingCurve(_) => Type::Easing,
|
Expression::EasingCurve(_) => Type::Easing,
|
||||||
Expression::EnumerationValue(value) => Type::Enumeration(value.enumeration.clone()),
|
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::ReadLocalVariable { .. } => {}
|
||||||
Expression::EasingCurve(_) => {}
|
Expression::EasingCurve(_) => {}
|
||||||
Expression::EnumerationValue(_) => {}
|
Expression::EnumerationValue(_) => {}
|
||||||
|
Expression::ReturnStatement(expr) => {
|
||||||
|
expr.as_deref().map(|expr| visitor(expr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,6 +620,9 @@ impl Expression {
|
||||||
Expression::ReadLocalVariable { .. } => {}
|
Expression::ReadLocalVariable { .. } => {}
|
||||||
Expression::EasingCurve(_) => {}
|
Expression::EasingCurve(_) => {}
|
||||||
Expression::EnumerationValue(_) => {}
|
Expression::EnumerationValue(_) => {}
|
||||||
|
Expression::ReturnStatement(expr) => {
|
||||||
|
expr.as_deref_mut().map(|expr| visitor(expr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,6 +675,9 @@ impl Expression {
|
||||||
Expression::ReadLocalVariable { .. } => false,
|
Expression::ReadLocalVariable { .. } => false,
|
||||||
Expression::EasingCurve(_) => true,
|
Expression::EasingCurve(_) => true,
|
||||||
Expression::EnumerationValue(_) => 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,
|
node: &impl SpannedWithSourceFile,
|
||||||
diag: &mut BuildDiagnostics,
|
diag: &mut BuildDiagnostics,
|
||||||
) -> Expression {
|
) -> 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();
|
let ty = self.ty();
|
||||||
if ty == target_type || target_type == Type::Void || target_type == Type::Invalid {
|
if ty == target_type || target_type == Type::Void || target_type == Type::Invalid {
|
||||||
self
|
self
|
||||||
|
|
|
@ -1452,8 +1452,18 @@ fn compile_expression(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::CodeBlock(sub) => {
|
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) };
|
if let Some(s) = x.last_mut() { *s = format!("return {};", s) };
|
||||||
|
|
||||||
format!("[&]{{ {} }}()", x.join(";"))
|
format!("[&]{{ {} }}()", x.join(";"))
|
||||||
}
|
}
|
||||||
Expression::FunctionCall { function, arguments, source_location: _ } => match &**function {
|
Expression::FunctionCall { function, arguments, source_location: _ } => match &**function {
|
||||||
|
@ -1608,6 +1618,7 @@ fn compile_expression(
|
||||||
}
|
}
|
||||||
Expression::Uncompiled(_) | Expression::TwoWayBinding(..) => panic!(),
|
Expression::Uncompiled(_) | Expression::TwoWayBinding(..) => panic!(),
|
||||||
Expression::Invalid => "\n#error invalid expression\n".to_string(),
|
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());
|
let value_ident = format_ident!("{}", value.to_string());
|
||||||
quote!(sixtyfps::re_exports::#base_ident::#value_ident)
|
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 {
|
fn from_codeblock_node(node: syntax_nodes::CodeBlock, ctx: &mut LookupCtx) -> Expression {
|
||||||
debug_assert_eq!(node.kind(), SyntaxKind::CodeBlock);
|
debug_assert_eq!(node.kind(), SyntaxKind::CodeBlock);
|
||||||
Expression::CodeBlock(
|
|
||||||
node.children()
|
let mut statements_or_exprs = node
|
||||||
.filter(|n| n.kind() == SyntaxKind::Expression)
|
.children()
|
||||||
.map(|n| Self::from_expression_node(n.into(), ctx))
|
.filter_map(|n| match n.kind() {
|
||||||
.collect(),
|
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) => {
|
Expression::CodeBlock(sub) => {
|
||||||
let mut v = Value::Void;
|
let mut v = Value::Void;
|
||||||
for e in sub {
|
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 = eval_expression(e, local_context);
|
||||||
}
|
}
|
||||||
v
|
v
|
||||||
|
@ -606,6 +609,7 @@ pub fn eval_expression(e: &Expression, local_context: &mut EvalLocalContext) ->
|
||||||
Expression::EnumerationValue(value) => {
|
Expression::EnumerationValue(value) => {
|
||||||
Value::EnumerationValue(value.enumeration.name.clone(), value.to_string())
|
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