mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 22:54:36 +00:00
Support for code blocks and signal call
This commit is contained in:
parent
f2df9293a9
commit
95b671c97c
11 changed files with 240 additions and 84 deletions
|
@ -192,13 +192,18 @@ pub fn sixtyfps(stream: TokenStream) -> TokenStream {
|
||||||
};
|
};
|
||||||
let rust_property = quote!(#rust_property_accessor_prefix#rust_property_ident);
|
let rust_property = quote!(#rust_property_accessor_prefix#rust_property_ident);
|
||||||
|
|
||||||
let v = compile_expression(v, &component_id);
|
let v = compile_expression(v);
|
||||||
if v.is_none() {
|
if v.is_none() {
|
||||||
// FIXME: this is because signals are not yet implemented
|
// FIXME: this is because signals are not yet implemented
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
init.push(quote!(self_.#rust_property#v;));
|
init.push(quote!(
|
||||||
|
self_.#rust_property.set_binding(|context| {
|
||||||
|
let _self = context.component.downcast::<#component_id>().unwrap();
|
||||||
|
#v
|
||||||
|
});
|
||||||
|
));
|
||||||
}
|
}
|
||||||
item_names.push(field_name);
|
item_names.push(field_name);
|
||||||
item_types.push(quote::format_ident!("{}", item.base_type.as_builtin().class_name));
|
item_types.push(quote::format_ident!("{}", item.base_type.as_builtin().class_name));
|
||||||
|
@ -251,31 +256,43 @@ pub fn sixtyfps(stream: TokenStream) -> TokenStream {
|
||||||
result.into()
|
result.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_expression(
|
fn compile_expression(e: &Expression) -> Option<proc_macro2::TokenStream> {
|
||||||
e: &Expression,
|
|
||||||
self_id: &proc_macro2::Ident,
|
|
||||||
) -> Option<proc_macro2::TokenStream> {
|
|
||||||
Some(match e {
|
Some(match e {
|
||||||
Expression::StringLiteral(s) => quote!(.set(sixtyfps::re_exports::SharedString::from(#s))),
|
Expression::StringLiteral(s) => quote!(sixtyfps::re_exports::SharedString::from(#s)),
|
||||||
Expression::NumberLiteral(n) => quote!(.set(#n as _)),
|
Expression::NumberLiteral(n) => quote!(#n as _),
|
||||||
Expression::Cast { from, to } => {
|
Expression::Cast { from, to } => {
|
||||||
let f = compile_expression(&*from, self_id)?;
|
let f = compile_expression(&*from)?;
|
||||||
match (from.ty(), to) {
|
match (from.ty(), to) {
|
||||||
(Type::Float32, Type::String) | (Type::Int32, Type::String) => {
|
(Type::Float32, Type::String) | (Type::Int32, Type::String) => {
|
||||||
quote!(.set(sixtyfps::re_exports::SharedString::from(format("{}", #f).to_str())))
|
quote!(sixtyfps::re_exports::SharedString::from(format("{}", #f).to_str()))
|
||||||
}
|
}
|
||||||
_ => f,
|
_ => f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::PropertyReference { component: _, element: _, name } => {
|
Expression::PropertyReference { component: _, element, name } => {
|
||||||
let name_ident = quote::format_ident!("{}", name);
|
let name_ident = quote::format_ident!("{}", name);
|
||||||
quote!(.set_binding(|context| {
|
let e = element.upgrade().unwrap();
|
||||||
let _self: &#self_id = context.component.downcast().unwrap();
|
if !e.borrow().property_declarations.contains_key(name) {
|
||||||
_self.#name_ident.get(context)
|
let elem_ident = quote::format_ident!("{}", e.borrow().id);
|
||||||
}))
|
quote!(_self.#elem_ident.#name_ident.get(context))
|
||||||
|
} else {
|
||||||
|
quote!(_self.#name_ident.get(context))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::CodeBlock(sub) => {
|
||||||
|
if sub.iter().map(|e| compile_expression(e)).any(|e| e.is_none()) {
|
||||||
|
// fixme: Remove!
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let map = sub.iter().map(|e| compile_expression(e));
|
||||||
|
quote!({ #(#map);* })
|
||||||
}
|
}
|
||||||
// FIXME: signals!
|
// FIXME: signals!
|
||||||
Expression::SignalReference { .. } => return None,
|
Expression::SignalReference { .. } => return None,
|
||||||
_ => quote!(compile_error! {"unsupported expression"}),
|
Expression::FunctionCall { .. } => return None,
|
||||||
|
_ => {
|
||||||
|
let error = format!("unsupported expression {:?}", e);
|
||||||
|
quote!(compile_error! {#error})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ component TwoRectangle := Rectangle {
|
||||||
my_area := TouchArea {
|
my_area := TouchArea {
|
||||||
width: 25;
|
width: 25;
|
||||||
height: 25;
|
height: 25;
|
||||||
clicked => { clicked }
|
clicked => { root.clicked() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ component ButtonRectangle := Rectangle {
|
||||||
TouchArea {
|
TouchArea {
|
||||||
width: 100;
|
width: 100;
|
||||||
height: 75;
|
height: 75;
|
||||||
clicked => { clicked }
|
clicked => { root.clicked() }
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
x: 50;
|
x: 50;
|
||||||
|
@ -49,7 +49,7 @@ Hello := Rectangle {
|
||||||
width: 100;
|
width: 100;
|
||||||
height: 100;
|
height: 100;
|
||||||
color: blue;
|
color: blue;
|
||||||
clicked => { foobar }
|
clicked => { foobar() }
|
||||||
}
|
}
|
||||||
Rectangle {
|
Rectangle {
|
||||||
x: 100;
|
x: 100;
|
||||||
|
@ -75,7 +75,7 @@ Hello := Rectangle {
|
||||||
color: 4289374890;
|
color: 4289374890;
|
||||||
x: 50;
|
x: 50;
|
||||||
y: 225;
|
y: 225;
|
||||||
clicked => { plus_clicked }
|
clicked => { plus_clicked() }
|
||||||
button_text: "+";
|
button_text: "+";
|
||||||
}
|
}
|
||||||
property<int32> counter;
|
property<int32> counter;
|
||||||
|
@ -84,7 +84,7 @@ Hello := Rectangle {
|
||||||
color: 4289374890;
|
color: 4289374890;
|
||||||
x: 50;
|
x: 50;
|
||||||
y: 350;
|
y: 350;
|
||||||
clicked => { minus_clicked }
|
clicked => { minus_clicked() }
|
||||||
button_text: "-";
|
button_text: "-";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ component TwoRectangle := Rectangle {
|
||||||
my_area := TouchArea {
|
my_area := TouchArea {
|
||||||
width: 25;
|
width: 25;
|
||||||
height: 25;
|
height: 25;
|
||||||
clicked => { clicked }
|
clicked => { root.clicked() }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ component ButtonRectangle := Rectangle {
|
||||||
TouchArea {
|
TouchArea {
|
||||||
width: 100;
|
width: 100;
|
||||||
height: 75;
|
height: 75;
|
||||||
clicked => { clicked }
|
clicked => { root.clicked() }
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
x: 50;
|
x: 50;
|
||||||
|
@ -52,7 +52,7 @@ Hello := Rectangle {
|
||||||
width: 100;
|
width: 100;
|
||||||
height: 100;
|
height: 100;
|
||||||
color: blue;
|
color: blue;
|
||||||
clicked => { foobar }
|
clicked => { foobar() }
|
||||||
}
|
}
|
||||||
Rectangle {
|
Rectangle {
|
||||||
x: 100;
|
x: 100;
|
||||||
|
@ -78,7 +78,7 @@ Hello := Rectangle {
|
||||||
color: 4289374890;
|
color: 4289374890;
|
||||||
x: 50;
|
x: 50;
|
||||||
y: 225;
|
y: 225;
|
||||||
clicked => { plus_clicked }
|
clicked => { plus_clicked() }
|
||||||
button_text: "+";
|
button_text: "+";
|
||||||
}
|
}
|
||||||
counter := Text { x: 100; y: 300; text: "0"; color: black; }
|
counter := Text { x: 100; y: 300; text: "0"; color: black; }
|
||||||
|
@ -86,7 +86,7 @@ Hello := Rectangle {
|
||||||
color: 4289374890;
|
color: 4289374890;
|
||||||
x: 50;
|
x: 50;
|
||||||
y: 350;
|
y: 350;
|
||||||
clicked => { minus_clicked }
|
clicked => { minus_clicked() }
|
||||||
button_text: "-";
|
button_text: "-";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,12 @@ pub enum Expression {
|
||||||
|
|
||||||
/// Cast an expression to the given type
|
/// Cast an expression to the given type
|
||||||
Cast { from: Box<Expression>, to: Type },
|
Cast { from: Box<Expression>, to: Type },
|
||||||
|
|
||||||
|
/// a code block with different expression
|
||||||
|
CodeBlock(Vec<Expression>),
|
||||||
|
|
||||||
|
/// A function call
|
||||||
|
FunctionCall { function: Box<Expression> },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
|
@ -42,6 +48,8 @@ impl Expression {
|
||||||
element.upgrade().unwrap().borrow().lookup_property(name)
|
element.upgrade().unwrap().borrow().lookup_property(name)
|
||||||
}
|
}
|
||||||
Expression::Cast { to, .. } => to.clone(),
|
Expression::Cast { to, .. } => to.clone(),
|
||||||
|
Expression::CodeBlock(sub) => sub.last().map_or(Type::Invalid, |e| e.ty()),
|
||||||
|
Expression::FunctionCall { function } => function.ty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +63,12 @@ impl Expression {
|
||||||
Expression::SignalReference { .. } => {}
|
Expression::SignalReference { .. } => {}
|
||||||
Expression::PropertyReference { .. } => {}
|
Expression::PropertyReference { .. } => {}
|
||||||
Expression::Cast { from, .. } => visitor(&**from),
|
Expression::Cast { from, .. } => visitor(&**from),
|
||||||
|
Expression::CodeBlock(sub) => {
|
||||||
|
for e in sub {
|
||||||
|
visitor(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::FunctionCall { function } => visitor(&**function),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +81,12 @@ impl Expression {
|
||||||
Expression::SignalReference { .. } => {}
|
Expression::SignalReference { .. } => {}
|
||||||
Expression::PropertyReference { .. } => {}
|
Expression::PropertyReference { .. } => {}
|
||||||
Expression::Cast { from, .. } => visitor(&mut **from),
|
Expression::Cast { from, .. } => visitor(&mut **from),
|
||||||
|
Expression::CodeBlock(sub) => {
|
||||||
|
for e in sub {
|
||||||
|
visitor(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::FunctionCall { function } => visitor(&mut **function),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,9 +162,7 @@ fn handle_item(
|
||||||
|
|
||||||
let id = &item.id;
|
let id = &item.id;
|
||||||
init.extend(item.bindings.iter().map(|(s, i)| {
|
init.extend(item.bindings.iter().map(|(s, i)| {
|
||||||
use crate::expression_tree::Expression;
|
if matches!(item.lookup_property(s.as_str()), Type::Signal) {
|
||||||
match i {
|
|
||||||
Expression::SignalReference { component:_, element:_, name } => {
|
|
||||||
let signal_accessor_prefix = if item.signals_declaration.contains(s) {
|
let signal_accessor_prefix = if item.signals_declaration.contains(s) {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
|
@ -172,11 +170,10 @@ fn handle_item(
|
||||||
};
|
};
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"{signal_accessor_prefix}{prop}.set_handler([](const void *root) {{ reinterpret_cast<const {ty}*>(root)->{fwd}.emit(root); }});",
|
"{signal_accessor_prefix}{prop}.set_handler([](const void *self_) {{ auto self = reinterpret_cast<const {ty}*>(self_); {code}; }});",
|
||||||
signal_accessor_prefix = signal_accessor_prefix, prop = s, fwd = name.clone(), ty = main_struct.name
|
signal_accessor_prefix = signal_accessor_prefix, prop = s, ty = main_struct.name, code = compile_expression(i)
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
_ => {
|
|
||||||
let accessor_prefix = if item.property_declarations.contains_key(s) {
|
let accessor_prefix = if item.property_declarations.contains_key(s) {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
|
@ -191,7 +188,6 @@ fn handle_item(
|
||||||
init = init
|
init = init
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
for i in &item.children {
|
for i in &item.children {
|
||||||
|
@ -225,7 +221,7 @@ pub fn generate(component: &Component, diag: &mut Diagnostics) -> Option<impl st
|
||||||
|
|
||||||
main_struct.members.extend(declared_property_vars);
|
main_struct.members.extend(declared_property_vars);
|
||||||
|
|
||||||
let mut init = Vec::new();
|
let mut init = vec!["auto self = this;".into()];
|
||||||
handle_item(
|
handle_item(
|
||||||
&component.root_element.borrow(),
|
&component.root_element.borrow(),
|
||||||
&declared_property_members,
|
&declared_property_members,
|
||||||
|
@ -303,7 +299,23 @@ fn compile_expression(e: &crate::expression_tree::Expression) -> String {
|
||||||
match e {
|
match e {
|
||||||
StringLiteral(s) => format!(r#"sixtyfps::SharedString("{}")"#, s.escape_default()),
|
StringLiteral(s) => format!(r#"sixtyfps::SharedString("{}")"#, s.escape_default()),
|
||||||
NumberLiteral(n) => n.to_string(),
|
NumberLiteral(n) => n.to_string(),
|
||||||
PropertyReference { name, .. } => format!(r#"{}.get(nullptr)"#, name),
|
PropertyReference { element, name, .. } => {
|
||||||
|
let e = element.upgrade().unwrap();
|
||||||
|
let e = e.borrow();
|
||||||
|
let (elem, dot) = if e.property_declarations.contains_key(name) {
|
||||||
|
("", "")
|
||||||
|
} else {
|
||||||
|
(e.id.as_str(), ".")
|
||||||
|
};
|
||||||
|
format!(r#"self->{}{}{}.get(nullptr)"#, elem, dot, name)
|
||||||
|
}
|
||||||
|
SignalReference { element, name, .. } => {
|
||||||
|
let e = element.upgrade().unwrap();
|
||||||
|
let e = e.borrow();
|
||||||
|
let (elem, dot) =
|
||||||
|
if e.signals_declaration.contains(name) { ("", "") } else { (e.id.as_str(), ".") };
|
||||||
|
format!(r#"self->{}{}{}"#, elem, dot, name)
|
||||||
|
}
|
||||||
Cast { from, to } => {
|
Cast { from, to } => {
|
||||||
let f = compile_expression(&*from);
|
let f = compile_expression(&*from);
|
||||||
match (from.ty(), to) {
|
match (from.ty(), to) {
|
||||||
|
@ -313,6 +325,20 @@ fn compile_expression(e: &crate::expression_tree::Expression) -> String {
|
||||||
_ => f,
|
_ => f,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => format!("\n#error: unsupported expression {:?}\n", e),
|
CodeBlock(sub) => {
|
||||||
|
let mut x = sub.iter().map(|e| compile_expression(e)).collect::<Vec<_>>();
|
||||||
|
x.last_mut().map(|s| *s = format!("return {};", s));
|
||||||
|
|
||||||
|
format!("[&]{{ {} }}()", x.join(";"))
|
||||||
|
}
|
||||||
|
FunctionCall { function } => {
|
||||||
|
if matches!(function.ty(), Type::Signal) {
|
||||||
|
format!("{}.emit(self_)", compile_expression(&*function))
|
||||||
|
} else {
|
||||||
|
format!("\n#error the function `{:?}` is not a signal\n", function)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Uncompiled(_) => panic!(),
|
||||||
|
Invalid => format!("\n#error invalid expression\n"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,6 +259,9 @@ impl Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_property(&self, name: &str) -> Type {
|
pub fn lookup_property(&self, name: &str) -> Type {
|
||||||
|
if self.signals_declaration.iter().any(|x| x == name) {
|
||||||
|
return Type::Signal;
|
||||||
|
}
|
||||||
self.property_declarations
|
self.property_declarations
|
||||||
.get(name)
|
.get(name)
|
||||||
.cloned()
|
.cloned()
|
||||||
|
|
|
@ -47,13 +47,17 @@ macro_rules! declare_token_kind {
|
||||||
SignalDeclaration,
|
SignalDeclaration,
|
||||||
SignalConnection,
|
SignalConnection,
|
||||||
PropertyDeclaration,
|
PropertyDeclaration,
|
||||||
|
/// wraps Identifiers, like Rectangle or SomeModule.SomeType
|
||||||
|
QualifiedName,
|
||||||
Binding,
|
Binding,
|
||||||
BindingExpression, // the right-hand-side of a binding
|
/// the right-hand-side of a binding
|
||||||
|
BindingExpression,
|
||||||
CodeBlock,
|
CodeBlock,
|
||||||
Expression,
|
Expression,
|
||||||
QualifiedName, // wraps Identifiers, like Rectangle or SomeModule.SomeType
|
|
||||||
/// foo!bar
|
/// foo!bar
|
||||||
BangExpression,
|
BangExpression,
|
||||||
|
/// expression()
|
||||||
|
FunctionCallExpression,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lexer() -> m_lexer::Lexer {
|
fn lexer() -> m_lexer::Lexer {
|
||||||
|
@ -124,22 +128,36 @@ mod parser_trait {
|
||||||
//! module allowing to keep implementation details of the node private
|
//! module allowing to keep implementation details of the node private
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
// Todo: rename DefaultParser
|
|
||||||
pub trait Parser: Sized {
|
pub trait Parser: Sized {
|
||||||
|
type Checkpoint: Clone;
|
||||||
|
|
||||||
/// Enter a new node. The node is going to be finished when
|
/// Enter a new node. The node is going to be finished when
|
||||||
/// The return value of this function is drop'ed
|
/// The return value of this function is drop'ed
|
||||||
///
|
///
|
||||||
/// (do not re-implement this function, re-implement
|
/// (do not re-implement this function, re-implement
|
||||||
/// start_node_impl and finish_node_impl)
|
/// start_node_impl and finish_node_impl)
|
||||||
|
#[must_use = "The node will be finished when it is dropped"]
|
||||||
fn start_node(&mut self, kind: SyntaxKind) -> Node<Self> {
|
fn start_node(&mut self, kind: SyntaxKind) -> Node<Self> {
|
||||||
self.start_node_impl(kind, NodeToken(()));
|
self.start_node_impl(kind, None, NodeToken(()));
|
||||||
|
Node(self)
|
||||||
|
}
|
||||||
|
#[must_use = "use start_node_at to use this checkpoint"]
|
||||||
|
fn checkpoint(&mut self) -> Self::Checkpoint;
|
||||||
|
#[must_use = "The node will be finished when it is dropped"]
|
||||||
|
fn start_node_at(&mut self, checkpoint: Self::Checkpoint, kind: SyntaxKind) -> Node<Self> {
|
||||||
|
self.start_node_impl(kind, Some(checkpoint), NodeToken(()));
|
||||||
Node(self)
|
Node(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Can only be called by Node::drop
|
/// Can only be called by Node::drop
|
||||||
fn finish_node_impl(&mut self, token: NodeToken);
|
fn finish_node_impl(&mut self, token: NodeToken);
|
||||||
/// Can only be called by Self::start_node
|
/// Can only be called by Self::start_node
|
||||||
fn start_node_impl(&mut self, kind: SyntaxKind, token: NodeToken);
|
fn start_node_impl(
|
||||||
|
&mut self,
|
||||||
|
kind: SyntaxKind,
|
||||||
|
checkpoint: Option<Self::Checkpoint>,
|
||||||
|
token: NodeToken,
|
||||||
|
);
|
||||||
fn peek(&mut self) -> Token;
|
fn peek(&mut self) -> Token;
|
||||||
/// Peek the n'th token, not including whitespaces and comments
|
/// Peek the n'th token, not including whitespaces and comments
|
||||||
fn nth(&mut self, n: usize) -> SyntaxKind;
|
fn nth(&mut self, n: usize) -> SyntaxKind;
|
||||||
|
@ -243,8 +261,16 @@ impl DefaultParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser for DefaultParser {
|
impl Parser for DefaultParser {
|
||||||
fn start_node_impl(&mut self, kind: SyntaxKind, _: NodeToken) {
|
fn start_node_impl(
|
||||||
self.builder.start_node(kind.into());
|
&mut self,
|
||||||
|
kind: SyntaxKind,
|
||||||
|
checkpoint: Option<Self::Checkpoint>,
|
||||||
|
_: NodeToken,
|
||||||
|
) {
|
||||||
|
match checkpoint {
|
||||||
|
None => self.builder.start_node(kind.into()),
|
||||||
|
Some(cp) => self.builder.start_node_at(cp, kind.into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_node_impl(&mut self, _: NodeToken) {
|
fn finish_node_impl(&mut self, _: NodeToken) {
|
||||||
|
@ -290,6 +316,11 @@ impl Parser for DefaultParser {
|
||||||
}
|
}
|
||||||
self.diags.push_error(e.into(), span);
|
self.diags.push_error(e.into(), span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Checkpoint = rowan::Checkpoint;
|
||||||
|
fn checkpoint(&mut self) -> Self::Checkpoint {
|
||||||
|
self.builder.checkpoint()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)]
|
||||||
|
|
|
@ -10,9 +10,11 @@ use super::prelude::*;
|
||||||
/// (something)
|
/// (something)
|
||||||
/// img!"something"
|
/// img!"something"
|
||||||
/// some_id.some_property
|
/// some_id.some_property
|
||||||
|
/// function_call()
|
||||||
/// ```
|
/// ```
|
||||||
pub fn parse_expression(p: &mut impl Parser) {
|
pub fn parse_expression(p: &mut impl Parser) {
|
||||||
let mut p = p.start_node(SyntaxKind::Expression);
|
let mut p = p.start_node(SyntaxKind::Expression);
|
||||||
|
let checkpoint = p.checkpoint();
|
||||||
match p.nth(0) {
|
match p.nth(0) {
|
||||||
SyntaxKind::Identifier => {
|
SyntaxKind::Identifier => {
|
||||||
if p.nth(1) == SyntaxKind::Bang {
|
if p.nth(1) == SyntaxKind::Bang {
|
||||||
|
@ -28,7 +30,23 @@ pub fn parse_expression(p: &mut impl Parser) {
|
||||||
parse_expression(&mut *p);
|
parse_expression(&mut *p);
|
||||||
p.expect(SyntaxKind::RParent);
|
p.expect(SyntaxKind::RParent);
|
||||||
}
|
}
|
||||||
_ => p.error("invalid expression"),
|
_ => {
|
||||||
|
p.error("invalid expression");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match p.nth(0) {
|
||||||
|
SyntaxKind::LParent => {
|
||||||
|
{
|
||||||
|
let _ = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);
|
||||||
|
}
|
||||||
|
let mut p = p.start_node_at(checkpoint, SyntaxKind::FunctionCallExpression);
|
||||||
|
|
||||||
|
p.consume();
|
||||||
|
p.expect(SyntaxKind::RParent);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,15 +77,26 @@ impl Expression {
|
||||||
debug_assert_eq!(node.kind(), SyntaxKind::BindingExpression);
|
debug_assert_eq!(node.kind(), SyntaxKind::BindingExpression);
|
||||||
let e = node
|
let e = node
|
||||||
.child_node(SyntaxKind::Expression)
|
.child_node(SyntaxKind::Expression)
|
||||||
|
.map(|n| Self::from_expression_node(n, ctx))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
node.child_node(SyntaxKind::CodeBlock)
|
node.child_node(SyntaxKind::CodeBlock).map(|c| Self::from_codeblock_node(c, ctx))
|
||||||
.and_then(|c| c.child_node(SyntaxKind::Expression))
|
|
||||||
})
|
})
|
||||||
.map_or(Self::Invalid, |n| Self::from_expression_node(n, ctx));
|
.unwrap_or(Self::Invalid);
|
||||||
maybe_convert_to(e, ctx, &node)
|
maybe_convert_to(e, ctx, &node)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_codeblock_node(node: SyntaxNode, 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, ctx))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn from_expression_node(node: SyntaxNode, ctx: &mut LookupCtx) -> Self {
|
fn from_expression_node(node: SyntaxNode, ctx: &mut LookupCtx) -> Self {
|
||||||
|
debug_assert_eq!(node.kind(), SyntaxKind::Expression);
|
||||||
node.child_node(SyntaxKind::Expression)
|
node.child_node(SyntaxKind::Expression)
|
||||||
.map(|n| Self::from_expression_node(n, ctx))
|
.map(|n| Self::from_expression_node(n, ctx))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
|
@ -112,6 +123,17 @@ impl Expression {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
node.child_node(SyntaxKind::FunctionCallExpression).map(|n| {
|
||||||
|
Expression::FunctionCall {
|
||||||
|
function: Box::new(
|
||||||
|
n.child_node(SyntaxKind::Expression)
|
||||||
|
.map(|n| Self::from_expression_node(n, ctx))
|
||||||
|
.unwrap_or(Expression::Invalid),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
.unwrap_or(Self::Invalid)
|
.unwrap_or(Self::Invalid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,6 +208,18 @@ impl Expression {
|
||||||
element: Rc::downgrade(&ctx.component.root_element),
|
element: Rc::downgrade(&ctx.component.root_element),
|
||||||
name: s.to_string(),
|
name: s.to_string(),
|
||||||
};
|
};
|
||||||
|
} else if matches!(property, Type::Signal) {
|
||||||
|
if let Some(x) = it.next() {
|
||||||
|
ctx.diag.push_error(
|
||||||
|
"Cannot access fields of signal".into(),
|
||||||
|
x.into_token().unwrap().span(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return Self::SignalReference {
|
||||||
|
component: Rc::downgrade(&ctx.component),
|
||||||
|
element: Rc::downgrade(&ctx.component.root_element),
|
||||||
|
name: s.to_string(),
|
||||||
|
};
|
||||||
} else if property.is_object_type() {
|
} else if property.is_object_type() {
|
||||||
todo!("Continue lookling up");
|
todo!("Continue lookling up");
|
||||||
}
|
}
|
||||||
|
@ -211,6 +245,18 @@ impl Expression {
|
||||||
element: Rc::downgrade(&elem),
|
element: Rc::downgrade(&elem),
|
||||||
name: prop_name.text().to_string(),
|
name: prop_name.text().to_string(),
|
||||||
};
|
};
|
||||||
|
} else if matches!(p, Type::Signal) {
|
||||||
|
if let Some(x) = it.next() {
|
||||||
|
ctx.diag.push_error(
|
||||||
|
"Cannot access fields of signal".into(),
|
||||||
|
x.into_token().unwrap().span(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return Self::SignalReference {
|
||||||
|
component: Rc::downgrade(&ctx.component),
|
||||||
|
element: Rc::downgrade(&elem),
|
||||||
|
name: prop_name.to_string(),
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
ctx.diag.push_error(
|
ctx.diag.push_error(
|
||||||
format!("Cannot access property '{}'", prop_name),
|
format!("Cannot access property '{}'", prop_name),
|
||||||
|
@ -225,20 +271,6 @@ impl Expression {
|
||||||
return Expression::Invalid;
|
return Expression::Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches!(ctx.property_type, Type::Signal) {
|
|
||||||
if let Some(x) = it.next() {
|
|
||||||
ctx.diag.push_error(
|
|
||||||
"Cannot access fields of signal".into(),
|
|
||||||
x.into_token().unwrap().span(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return Self::SignalReference {
|
|
||||||
component: Rc::downgrade(&ctx.component),
|
|
||||||
element: Rc::downgrade(&ctx.component.root_element),
|
|
||||||
name: s.to_string(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if matches!(ctx.property_type, Type::Color) {
|
if matches!(ctx.property_type, Type::Color) {
|
||||||
let value: Option<u32> = match s {
|
let value: Option<u32> = match s {
|
||||||
"blue" => Some(0xff0000ff),
|
"blue" => Some(0xff0000ff),
|
||||||
|
|
|
@ -3,7 +3,7 @@ SubElements := Rectangle {
|
||||||
signal foobar;
|
signal foobar;
|
||||||
|
|
||||||
TouchArea {
|
TouchArea {
|
||||||
clicked => { foobar }
|
clicked => { foobar() }
|
||||||
}
|
}
|
||||||
|
|
||||||
TouchArea {
|
TouchArea {
|
||||||
|
@ -14,8 +14,8 @@ SubElements := Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
TouchArea {
|
TouchArea {
|
||||||
clicked => { foobar }
|
clicked => { foobar() }
|
||||||
clicked => { foobar }
|
clicked => { foobar() }
|
||||||
// ^error{Duplicated signal}
|
// ^error{Duplicated signal}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ use sixtyfps_compiler::typeregister::Type;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
|
Void,
|
||||||
Number(f64),
|
Number(f64),
|
||||||
String(SharedString),
|
String(SharedString),
|
||||||
}
|
}
|
||||||
|
@ -42,5 +43,13 @@ pub fn eval_expression(
|
||||||
(v, _) => v,
|
(v, _) => v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expression::CodeBlock(sub) => {
|
||||||
|
let mut v = Value::Void;
|
||||||
|
for e in sub {
|
||||||
|
v = eval_expression(e, ctx, component_ref);
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
Expression::FunctionCall { .. } => todo!("function call"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue