mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-03 07:04:34 +00:00
Parse declaration of signal with arguments
This commit is contained in:
parent
5682b7c989
commit
9f026c820d
12 changed files with 68 additions and 33 deletions
|
@ -97,7 +97,7 @@ fn create<'cx>(
|
|||
cx.throw_error(format!("Property {} not found in the component", prop_name))
|
||||
})?
|
||||
.clone();
|
||||
if ty == Type::Signal {
|
||||
if let Type::Signal { .. } = ty {
|
||||
let _fun = value.downcast_or_throw::<JsFunction, _>(cx)?;
|
||||
let fun_idx = persistent_context.allocate(cx, value);
|
||||
component_type
|
||||
|
@ -152,7 +152,7 @@ fn to_eval_value<'cx>(
|
|||
| Type::Native(_)
|
||||
| Type::Function { .. }
|
||||
| Type::Model
|
||||
| Type::Signal
|
||||
| Type::Signal { .. }
|
||||
| Type::Easing
|
||||
| Type::PathElements => cx.throw_error("Cannot convert to a Sixtyfps property value"),
|
||||
Type::Float32 | Type::Int32 | Type::Duration | Type::Length | Type::LogicalLength => {
|
||||
|
@ -245,7 +245,7 @@ declare_types! {
|
|||
let properties = ct.properties();
|
||||
let array = JsArray::new(&mut cx, properties.len() as u32);
|
||||
let mut len: u32 = 0;
|
||||
for (p, _) in properties.iter().filter(|(_, prop_type)| **prop_type == Type::Signal) {
|
||||
for (p, _) in properties.iter().filter(|(_, prop_type)| matches!(**prop_type, Type::Signal{..})) {
|
||||
let prop_name = JsString::new(&mut cx, p);
|
||||
array.set(&mut cx, len, prop_name)?;
|
||||
len = len + 1;
|
||||
|
|
|
@ -293,7 +293,9 @@ impl Expression {
|
|||
Expression::StringLiteral(_) => Type::String,
|
||||
Expression::NumberLiteral(_, unit) => unit.ty(),
|
||||
Expression::BoolLiteral(_) => Type::Bool,
|
||||
Expression::SignalReference { .. } => Type::Signal,
|
||||
Expression::SignalReference(NamedReference { element, name }) => {
|
||||
element.upgrade().unwrap().borrow().lookup_property(name)
|
||||
}
|
||||
Expression::PropertyReference(NamedReference { element, name }) => {
|
||||
element.upgrade().unwrap().borrow().lookup_property(name)
|
||||
}
|
||||
|
@ -619,7 +621,7 @@ impl Expression {
|
|||
| Type::Component(_)
|
||||
| Type::Builtin(_)
|
||||
| Type::Native(_)
|
||||
| Type::Signal
|
||||
| Type::Signal { .. }
|
||||
| Type::Function { .. }
|
||||
| Type::Void => Expression::Invalid,
|
||||
Type::Float32 => Expression::NumberLiteral(0., Unit::None),
|
||||
|
|
|
@ -302,7 +302,7 @@ fn handle_item(item: &Element, main_struct: &mut Struct, init: &mut Vec<String>)
|
|||
|
||||
let id = &item.id;
|
||||
init.extend(item.bindings.iter().map(|(s, i)| {
|
||||
if matches!(item.lookup_property(s.as_str()), Type::Signal) {
|
||||
if matches!(item.lookup_property(s.as_str()), Type::Signal{..}) {
|
||||
let signal_accessor_prefix = if item.property_declarations.contains_key(s) {
|
||||
String::new()
|
||||
} else {
|
||||
|
@ -483,7 +483,7 @@ fn generate_component(
|
|||
let mut init = vec!["[[maybe_unused]] auto self = this;".into()];
|
||||
|
||||
for (cpp_name, property_decl) in component.root_element.borrow().property_declarations.iter() {
|
||||
let ty = if property_decl.property_type == Type::Signal {
|
||||
let ty = if matches!(property_decl.property_type, Type::Signal{..}) {
|
||||
if property_decl.expose_in_public_api && is_root {
|
||||
let signal_emitter = vec![format!("{}.emit();", cpp_name)];
|
||||
component_struct.members.push((
|
||||
|
@ -1006,7 +1006,7 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
|
|||
format!("[&]{{ {} }}()", x.join(";"))
|
||||
}
|
||||
Expression::FunctionCall { function } => {
|
||||
if matches!(function.ty(), Type::Signal | Type::Function{..}) {
|
||||
if matches!(function.ty(), Type::Signal{..} | Type::Function{..}) {
|
||||
compile_expression(&*function, component)
|
||||
} else {
|
||||
format!("\n#error the function `{:?}` is not a signal\n", function)
|
||||
|
|
|
@ -94,7 +94,7 @@ fn generate_component(
|
|||
let mut property_and_signal_accessors: Vec<TokenStream> = vec![];
|
||||
for (prop_name, property_decl) in component.root_element.borrow().property_declarations.iter() {
|
||||
let prop_ident = quote::format_ident!("{}", prop_name);
|
||||
if property_decl.property_type == Type::Signal {
|
||||
if matches!(property_decl.property_type, Type::Signal{..}) {
|
||||
declared_signals.push(prop_ident.clone());
|
||||
if property_decl.expose_in_public_api {
|
||||
let emitter_ident = quote::format_ident!("emit_{}", prop_name);
|
||||
|
@ -299,7 +299,7 @@ fn generate_component(
|
|||
let rust_property = quote!(#rust_property_accessor_prefix#rust_property_ident);
|
||||
let tokens_for_expression = compile_expression(binding_expression, &component);
|
||||
|
||||
if matches!(item.lookup_property(k.as_str()), Type::Signal) {
|
||||
if matches!(item.lookup_property(k.as_str()), Type::Signal{..}) {
|
||||
init.push(quote!(
|
||||
self_pinned.#rust_property.set_handler({
|
||||
let self_weak = sixtyfps::re_exports::PinWeak::downgrade(self_pinned.clone());
|
||||
|
@ -757,7 +757,7 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
|
|||
quote!(#access.emit(()))
|
||||
}
|
||||
Expression::FunctionCall { function } => {
|
||||
if matches!(function.ty(), Type::Signal | Type::Function{..}) {
|
||||
if matches!(function.ty(), Type::Signal{..} | Type::Function{..}) {
|
||||
compile_expression(function, &component)
|
||||
} else {
|
||||
let error = format!("the function {:?} is not a signal", e);
|
||||
|
|
|
@ -259,10 +259,11 @@ impl Element {
|
|||
let name_token =
|
||||
sig_decl.DeclaredIdentifier().child_token(SyntaxKind::Identifier).unwrap();
|
||||
let name = name_token.text().to_string();
|
||||
let args = sig_decl.Type().map(|node_ty| type_from_node(node_ty, diag, tr)).collect();
|
||||
r.property_declarations.insert(
|
||||
name,
|
||||
PropertyDeclaration {
|
||||
property_type: Type::Signal,
|
||||
property_type: Type::Signal { args },
|
||||
type_node: Some(sig_decl.into()),
|
||||
..Default::default()
|
||||
},
|
||||
|
@ -276,7 +277,7 @@ impl Element {
|
|||
};
|
||||
let name = name_token.text().to_string();
|
||||
let prop_type = r.lookup_property(&name);
|
||||
if !matches!(prop_type, Type::Signal) {
|
||||
if !matches!(prop_type, Type::Signal{..}) {
|
||||
diag.push_error(format!("'{}' is not a signal in {}", name, base), &name_token);
|
||||
}
|
||||
if r.bindings
|
||||
|
@ -522,7 +523,9 @@ impl Element {
|
|||
diag.push_error(
|
||||
match prop_type {
|
||||
Type::Invalid => format!("Unknown property {} in {}", name, base),
|
||||
Type::Signal => format!("'{}' is a signal. Use `=>` to connect", name),
|
||||
Type::Signal { .. } => {
|
||||
format!("'{}' is a signal. Use `=>` to connect", name)
|
||||
}
|
||||
_ => format!("Cannot assing to {} in {}", name, base),
|
||||
},
|
||||
&name_token,
|
||||
|
|
|
@ -283,7 +283,7 @@ declare_syntax! {
|
|||
RepeatedElement -> [ ?DeclaredIdentifier, ?RepeatedIndex, Expression , Element],
|
||||
RepeatedIndex -> [],
|
||||
ConditionalElement -> [ Expression , Element],
|
||||
SignalDeclaration -> [ DeclaredIdentifier ],
|
||||
SignalDeclaration -> [ DeclaredIdentifier, *Type ],
|
||||
SignalConnection -> [ CodeBlock ],
|
||||
/// Declaration of a propery.
|
||||
PropertyDeclaration-> [ Type , DeclaredIdentifier, ?BindingExpression ],
|
||||
|
@ -428,7 +428,11 @@ mod parser_trait {
|
|||
checkpoint: Option<Self::Checkpoint>,
|
||||
token: NodeToken,
|
||||
);
|
||||
fn peek(&mut self) -> Token;
|
||||
|
||||
/// Same as nth(0)
|
||||
fn peek(&mut self) -> Token {
|
||||
self.nth(0)
|
||||
}
|
||||
/// Peek the n'th token, not including whitespaces and comments
|
||||
fn nth(&mut self, n: usize) -> Token;
|
||||
fn consume(&mut self);
|
||||
|
@ -540,11 +544,6 @@ impl Parser for DefaultParser {
|
|||
self.builder.finish_node();
|
||||
}
|
||||
|
||||
fn peek(&mut self) -> Token {
|
||||
self.consume_ws();
|
||||
self.current_token()
|
||||
}
|
||||
|
||||
/// Peek the n'th token, not including whitespaces and comments
|
||||
fn nth(&mut self, mut n: usize) -> Token {
|
||||
self.consume_ws();
|
||||
|
|
|
@ -310,6 +310,10 @@ fn parse_signal_connection(p: &mut impl Parser) {
|
|||
#[cfg_attr(test, parser_test)]
|
||||
/// ```test,SignalDeclaration
|
||||
/// signal foobar;
|
||||
/// signal my_signal();
|
||||
/// signal foo(int, string);
|
||||
/// signal one_arg({ a: string, b: string});
|
||||
/// signal end_coma(a, b, c,);
|
||||
/// ```
|
||||
/// Must consume at least one token
|
||||
fn parse_signal_declaration(p: &mut impl Parser) {
|
||||
|
@ -320,6 +324,15 @@ fn parse_signal_declaration(p: &mut impl Parser) {
|
|||
let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
|
||||
p.expect(SyntaxKind::Identifier);
|
||||
}
|
||||
if p.test(SyntaxKind::LParent) {
|
||||
while p.peek().kind() != SyntaxKind::RParent {
|
||||
parse_type(&mut *p);
|
||||
if !p.test(SyntaxKind::Comma) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
p.expect(SyntaxKind::RParent);
|
||||
}
|
||||
p.expect(SyntaxKind::Semicolon);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,10 @@ fn generate_test(fn_name: &str, doc: &str) -> String {
|
|||
{{
|
||||
let mut p = DefaultParser::new("{source}".to_owned());
|
||||
{fn}(&mut p);
|
||||
assert!(!p.diags.has_error());
|
||||
let has_error = p.diags.has_error();
|
||||
//#[cfg(feature = "display-diagnostics")]
|
||||
//p.diags.print();
|
||||
assert!(!has_error);
|
||||
assert_eq!(p.cursor, p.tokens.len());
|
||||
{verify}
|
||||
}}
|
||||
|
|
|
@ -17,7 +17,7 @@ use std::{cell::RefCell, collections::HashMap};
|
|||
pub fn deduplicate_property_read(component: &Component) {
|
||||
recurse_elem(&component.root_element, &(), &mut |elem, _| {
|
||||
visit_element_expressions(elem, |expr, ty| {
|
||||
if ty() == Type::Signal {
|
||||
if matches!(ty(), Type::Signal{..}) {
|
||||
// Signal handler can't be optimizes because they can have side effect.
|
||||
// But that's fine as they also do not register dependencies
|
||||
return;
|
||||
|
|
|
@ -351,7 +351,7 @@ impl Expression {
|
|||
name: prop_name.text().to_string(),
|
||||
});
|
||||
return maybe_lookup_object(prop, it, ctx);
|
||||
} else if matches!(p, Type::Signal) {
|
||||
} else if matches!(p, Type::Signal{..}) {
|
||||
if let Some(x) = it.next() {
|
||||
ctx.diag.push_error("Cannot access fields of signal".into(), &x)
|
||||
}
|
||||
|
@ -382,7 +382,7 @@ impl Expression {
|
|||
name: first_str.to_string(),
|
||||
});
|
||||
return maybe_lookup_object(prop, it, ctx);
|
||||
} else if matches!(property, Type::Signal) {
|
||||
} else if matches!(property, Type::Signal{..}) {
|
||||
if let Some(x) = it.next() {
|
||||
ctx.diag.push_error("Cannot access fields of signal".into(), &x)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@ pub enum Type {
|
|||
Builtin(Rc<BuiltinElement>),
|
||||
Native(Rc<NativeClass>),
|
||||
|
||||
Signal,
|
||||
Signal {
|
||||
args: Vec<Type>,
|
||||
},
|
||||
Function {
|
||||
return_type: Box<Type>,
|
||||
args: Vec<Type>,
|
||||
|
@ -55,7 +57,7 @@ impl core::cmp::PartialEq for Type {
|
|||
(Type::Component(a), Type::Component(b)) => Rc::ptr_eq(a, b),
|
||||
(Type::Builtin(a), Type::Builtin(b)) => Rc::ptr_eq(a, b),
|
||||
(Type::Native(a), Type::Native(b)) => Rc::ptr_eq(a, b),
|
||||
(Type::Signal, Type::Signal) => true,
|
||||
(Type::Signal { args: a }, Type::Signal { args: b }) => a == b,
|
||||
(
|
||||
Type::Function { return_type: lhs_rt, args: lhs_args },
|
||||
Type::Function { return_type: rhs_rt, args: rhs_args },
|
||||
|
@ -88,7 +90,20 @@ impl Display for Type {
|
|||
Type::Component(c) => c.id.fmt(f),
|
||||
Type::Builtin(b) => b.native_class.class_name.fmt(f),
|
||||
Type::Native(b) => b.class_name.fmt(f),
|
||||
Type::Signal => write!(f, "signal"),
|
||||
Type::Signal { args } => {
|
||||
write!(f, "signal")?;
|
||||
if !args.is_empty() {
|
||||
write!(f, "(")?;
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, ",")?;
|
||||
}
|
||||
write!(f, "{}", arg)?;
|
||||
}
|
||||
write!(f, ")")?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Type::Function { return_type, args } => {
|
||||
write!(f, "function(")?;
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
|
@ -555,7 +570,7 @@ impl TypeRegister {
|
|||
("mouse_y", Type::Length),
|
||||
("pressed_x", Type::Length),
|
||||
("pressed_y", Type::Length),
|
||||
("clicked", Type::Signal),
|
||||
("clicked", Type::Signal { args: vec![] }),
|
||||
],
|
||||
);
|
||||
|
||||
|
@ -683,7 +698,7 @@ impl TypeRegister {
|
|||
("height", Type::Length),
|
||||
("text", Type::String),
|
||||
("pressed", Type::Bool),
|
||||
("clicked", Type::Signal),
|
||||
("clicked", Type::Signal { args: vec![] }),
|
||||
],
|
||||
);
|
||||
native_class(
|
||||
|
@ -696,7 +711,7 @@ impl TypeRegister {
|
|||
("height", Type::Length),
|
||||
("text", Type::String),
|
||||
("checked", Type::Bool),
|
||||
("toggled", Type::Signal),
|
||||
("toggled", Type::Signal { args: vec![] }),
|
||||
],
|
||||
);
|
||||
native_class(
|
||||
|
|
|
@ -470,7 +470,7 @@ fn generate_component<'id>(
|
|||
Type::LogicalLength => animated_property_info::<f32>(),
|
||||
Type::Resource => property_info::<Resource>(),
|
||||
Type::Bool => property_info::<bool>(),
|
||||
Type::Signal => {
|
||||
Type::Signal { .. } => {
|
||||
custom_signals.insert(name.clone(), builder.add_field_type::<Signal<()>>());
|
||||
continue;
|
||||
}
|
||||
|
@ -610,7 +610,7 @@ pub fn instantiate<'id>(
|
|||
let elem = item_within_component.elem.borrow();
|
||||
for (prop, expr) in &elem.bindings {
|
||||
let ty = elem.lookup_property(prop.as_str());
|
||||
if ty == Type::Signal {
|
||||
if let Type::Signal { .. } = ty {
|
||||
let signal = item_within_component
|
||||
.rtti
|
||||
.signals
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue