mirror of
https://github.com/slint-ui/slint.git
synced 2025-11-14 17:58:40 +00:00
parent
bef2e3617d
commit
3a4f3c61d5
17 changed files with 196 additions and 16 deletions
|
|
@ -138,6 +138,8 @@ log = { version = "0.4.17", optional = true }
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
slint-build = { path = "../build" }
|
slint-build = { path = "../build" }
|
||||||
i-slint-backend-testing = { version = "=1.0.3", path = "../../../internal/backends/testing" }
|
i-slint-backend-testing = { version = "=1.0.3", path = "../../../internal/backends/testing" }
|
||||||
|
serde_json = "1.0.96"
|
||||||
|
serde = { version = "1.0.163", features = ["derive"] }
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
rustdoc-args = [
|
rustdoc-args = [
|
||||||
|
|
|
||||||
|
|
@ -208,6 +208,26 @@ struct MyStruct {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The `.slint` file allows you to utilize Rust attributes and features for defining structures using the `@rust-attr()` directive.
|
||||||
|
This enables you to customize the generated code by applying additional traits, derivations, or annotations.
|
||||||
|
Consider the following structure defined in the `.slint` file with Rust attributes:
|
||||||
|
```slint,ignore
|
||||||
|
@rust-attr(derive(serde::Serialize, serde::Deserialize))
|
||||||
|
struct MyStruct {
|
||||||
|
foo : i32,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Based on this structure, the following Rust code would be generated:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
#[derive(Default, Clone, Debug, PartialEq)]
|
||||||
|
struct MyStruct {
|
||||||
|
foo : i32,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Exported Global singletons
|
## Exported Global singletons
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -15,3 +15,19 @@ fn empty_stuff() {
|
||||||
slint!(export struct Hei { abcd: bool });
|
slint!(export struct Hei { abcd: bool });
|
||||||
slint!(export global G { });
|
slint!(export global G { });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize_deserialize_struct() {
|
||||||
|
i_slint_backend_testing::init();
|
||||||
|
slint! {
|
||||||
|
@rust-attr(derive(serde::Serialize, serde::Deserialize))
|
||||||
|
export struct TestStruct {
|
||||||
|
foo: int,
|
||||||
|
}
|
||||||
|
export component Test { }
|
||||||
|
}
|
||||||
|
let data = TestStruct { foo: 1 };
|
||||||
|
let serialized = serde_json::to_string(&data).unwrap();
|
||||||
|
let deserialized: TestStruct = serde_json::from_str(&serialized).unwrap();
|
||||||
|
assert_eq!(data, deserialized);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,7 @@ impl BuiltinFunction {
|
||||||
.collect(),
|
.collect(),
|
||||||
name: Some("Size".to_string()),
|
name: Some("Size".to_string()),
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
}),
|
}),
|
||||||
args: vec![Type::Image],
|
args: vec![Type::Image],
|
||||||
},
|
},
|
||||||
|
|
@ -1027,7 +1028,7 @@ impl Expression {
|
||||||
},
|
},
|
||||||
(
|
(
|
||||||
Type::Struct { fields: ref left, .. },
|
Type::Struct { fields: ref left, .. },
|
||||||
Type::Struct { fields: right, name, node: n },
|
Type::Struct { fields: right, name, node: n, rust_attributes },
|
||||||
) if left != right => {
|
) if left != right => {
|
||||||
if let Expression::Struct { mut values, .. } = self {
|
if let Expression::Struct { mut values, .. } = self {
|
||||||
let mut new_values = HashMap::new();
|
let mut new_values = HashMap::new();
|
||||||
|
|
@ -1051,6 +1052,7 @@ impl Expression {
|
||||||
fields: left.clone(),
|
fields: left.clone(),
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
node: n.clone(),
|
node: n.clone(),
|
||||||
|
rust_attributes: rust_attributes.clone(),
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
name: key.clone(),
|
name: key.clone(),
|
||||||
|
|
|
||||||
|
|
@ -579,7 +579,7 @@ pub fn generate(doc: &Document) -> impl std::fmt::Display {
|
||||||
}
|
}
|
||||||
|
|
||||||
for ty in doc.root_component.used_types.borrow().structs.iter() {
|
for ty in doc.root_component.used_types.borrow().structs.iter() {
|
||||||
if let Type::Struct { fields, name: Some(name), node: Some(node) } = ty {
|
if let Type::Struct { fields, name: Some(name), node: Some(node), .. } = ty {
|
||||||
generate_struct(&mut file, name, fields, node);
|
generate_struct(&mut file, name, fields, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ use proc_macro2::{Ident, TokenStream};
|
||||||
use quote::{format_ident, quote};
|
use quote::{format_ident, quote};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
type EvaluationContext<'a> = llr_EvaluationContext<'a, TokenStream>;
|
type EvaluationContext<'a> = llr_EvaluationContext<'a, TokenStream>;
|
||||||
type ParentCtx<'a> = llr_ParentCtx<'a, TokenStream>;
|
type ParentCtx<'a> = llr_ParentCtx<'a, TokenStream>;
|
||||||
|
|
@ -139,8 +140,8 @@ pub fn generate(doc: &Document) -> TokenStream {
|
||||||
.structs
|
.structs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|ty| {
|
.filter_map(|ty| {
|
||||||
if let Type::Struct { fields, name: Some(name), node: Some(_) } = ty {
|
if let Type::Struct { fields, name: Some(name), node: Some(_), rust_attributes } = ty {
|
||||||
Some((ident(name), generate_struct(name, fields)))
|
Some((ident(name), generate_struct(name, fields, rust_attributes)))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -422,12 +423,28 @@ fn generate_public_component(llr: &llr::PublicComponent) -> TokenStream {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_struct(name: &str, fields: &BTreeMap<String, Type>) -> TokenStream {
|
fn generate_struct(
|
||||||
|
name: &str,
|
||||||
|
fields: &BTreeMap<String, Type>,
|
||||||
|
rust_attributes: &Option<Vec<String>>,
|
||||||
|
) -> TokenStream {
|
||||||
let component_id = struct_name_to_tokens(name);
|
let component_id = struct_name_to_tokens(name);
|
||||||
let (declared_property_vars, declared_property_types): (Vec<_>, Vec<_>) =
|
let (declared_property_vars, declared_property_types): (Vec<_>, Vec<_>) =
|
||||||
fields.iter().map(|(name, ty)| (ident(name), rust_primitive_type(ty).unwrap())).unzip();
|
fields.iter().map(|(name, ty)| (ident(name), rust_primitive_type(ty).unwrap())).unzip();
|
||||||
|
|
||||||
|
let attributes = if let Some(feature) = rust_attributes {
|
||||||
|
let attr =
|
||||||
|
feature.iter().map(|f| match TokenStream::from_str(format!(r#"#[{}]"#, f).as_str()) {
|
||||||
|
Ok(eval) => eval,
|
||||||
|
Err(_) => quote! {},
|
||||||
|
});
|
||||||
|
quote! { #(#attr)* }
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
|
#attributes
|
||||||
#[derive(Default, PartialEq, Debug, Clone)]
|
#[derive(Default, PartialEq, Debug, Clone)]
|
||||||
pub struct #component_id {
|
pub struct #component_id {
|
||||||
#(pub #declared_property_vars : #declared_property_types),*
|
#(pub #declared_property_vars : #declared_property_types),*
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,8 @@ pub enum Type {
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
/// When declared in .slint, this is the node of the declaration.
|
/// When declared in .slint, this is the node of the declaration.
|
||||||
node: Option<syntax_nodes::ObjectType>,
|
node: Option<syntax_nodes::ObjectType>,
|
||||||
|
/// deriven
|
||||||
|
rust_attributes: Option<Vec<String>>,
|
||||||
},
|
},
|
||||||
Enumeration(Rc<Enumeration>),
|
Enumeration(Rc<Enumeration>),
|
||||||
|
|
||||||
|
|
@ -104,8 +106,8 @@ impl core::cmp::PartialEq for Type {
|
||||||
Type::Easing => matches!(other, Type::Easing),
|
Type::Easing => matches!(other, Type::Easing),
|
||||||
Type::Brush => matches!(other, Type::Brush),
|
Type::Brush => matches!(other, Type::Brush),
|
||||||
Type::Array(a) => matches!(other, Type::Array(b) if a == b),
|
Type::Array(a) => matches!(other, Type::Array(b) if a == b),
|
||||||
Type::Struct { fields, name, node: _ } => {
|
Type::Struct { fields, name, node: _, rust_attributes: _ } => {
|
||||||
matches!(other, Type::Struct{fields: f, name: n, node: _} if fields == f && name == n)
|
matches!(other, Type::Struct{fields:f,name:n,node:_, rust_attributes: _ } if fields == f && name == n)
|
||||||
}
|
}
|
||||||
Type::Enumeration(lhs) => matches!(other, Type::Enumeration(rhs) if lhs == rhs),
|
Type::Enumeration(lhs) => matches!(other, Type::Enumeration(rhs) if lhs == rhs),
|
||||||
Type::UnitProduct(a) => matches!(other, Type::UnitProduct(b) if a == b),
|
Type::UnitProduct(a) => matches!(other, Type::UnitProduct(b) if a == b),
|
||||||
|
|
|
||||||
|
|
@ -460,6 +460,7 @@ pub fn layout_info_type() -> Type {
|
||||||
.collect(),
|
.collect(),
|
||||||
name: Some("LayoutInfo".into()),
|
name: Some("LayoutInfo".into()),
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -398,6 +398,7 @@ pub fn lower_animation(a: &PropertyAnimation, ctx: &ExpressionContext<'_>) -> An
|
||||||
fields: animation_fields().collect(),
|
fields: animation_fields().collect(),
|
||||||
name: Some("PropertyAnimation".into()),
|
name: Some("PropertyAnimation".into()),
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -435,6 +436,7 @@ pub fn lower_animation(a: &PropertyAnimation, ctx: &ExpressionContext<'_>) -> An
|
||||||
.collect(),
|
.collect(),
|
||||||
name: None,
|
name: None,
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
},
|
},
|
||||||
values: IntoIterator::into_iter([
|
values: IntoIterator::into_iter([
|
||||||
("0".to_string(), get_anim),
|
("0".to_string(), get_anim),
|
||||||
|
|
@ -661,6 +663,7 @@ fn box_layout_data(
|
||||||
.collect(),
|
.collect(),
|
||||||
name: Some("BoxLayoutCellData".into()),
|
name: Some("BoxLayoutCellData".into()),
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if repeater_count == 0 {
|
if repeater_count == 0 {
|
||||||
|
|
@ -747,6 +750,7 @@ pub(super) fn grid_layout_cell_data_ty() -> Type {
|
||||||
.collect(),
|
.collect(),
|
||||||
name: Some("GridLayoutCellData".into()),
|
name: Some("GridLayoutCellData".into()),
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -843,6 +847,7 @@ fn compile_path(path: &crate::expression_tree::Path, ctx: &ExpressionContext) ->
|
||||||
fields: Default::default(),
|
fields: Default::default(),
|
||||||
name: Some("PathElement".to_owned()),
|
name: Some("PathElement".to_owned()),
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
},
|
},
|
||||||
values: elements,
|
values: elements,
|
||||||
as_model: false,
|
as_model: false,
|
||||||
|
|
@ -866,6 +871,7 @@ fn compile_path(path: &crate::expression_tree::Path, ctx: &ExpressionContext) ->
|
||||||
.collect(),
|
.collect(),
|
||||||
name: element.element_type.native_class.cpp_type.clone(),
|
name: element.element_type.native_class.cpp_type.clone(),
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
llr_Expression::Struct {
|
llr_Expression::Struct {
|
||||||
|
|
@ -917,6 +923,7 @@ fn compile_path(path: &crate::expression_tree::Path, ctx: &ExpressionContext) ->
|
||||||
.collect(),
|
.collect(),
|
||||||
name: None,
|
name: None,
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
},
|
},
|
||||||
values: IntoIterator::into_iter([
|
values: IntoIterator::into_iter([
|
||||||
(
|
(
|
||||||
|
|
@ -960,5 +967,8 @@ fn make_struct(
|
||||||
values.insert(name.to_string(), expr);
|
values.insert(name.to_string(), expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
llr_Expression::Struct { ty: Type::Struct { fields, name: Some(name), node: None }, values }
|
llr_Expression::Struct {
|
||||||
|
ty: Type::Struct { fields, name: Some(name), node: None, rust_attributes: None },
|
||||||
|
values,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ pub fn load_builtins(register: &mut TypeRegister) {
|
||||||
// parse structs
|
// parse structs
|
||||||
for s in doc.StructDeclaration().chain(doc.ExportsList().flat_map(|e| e.StructDeclaration())) {
|
for s in doc.StructDeclaration().chain(doc.ExportsList().flat_map(|e| e.StructDeclaration())) {
|
||||||
let external_name = identifier_text(&s.DeclaredIdentifier()).unwrap();
|
let external_name = identifier_text(&s.DeclaredIdentifier()).unwrap();
|
||||||
let mut ty = object_tree::type_struct_from_node(s.ObjectType(), &mut diag, register);
|
let mut ty = object_tree::type_struct_from_node(s.ObjectType(), &mut diag, register, None);
|
||||||
if let Type::Struct { name, .. } = &mut ty {
|
if let Type::Struct { name, .. } = &mut ty {
|
||||||
*name = Some(
|
*name = Some(
|
||||||
parse_annotation("name", &s.ObjectType())
|
parse_annotation("name", &s.ObjectType())
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
// cSpell: ignore qualname
|
// cSpell: ignore qualname
|
||||||
|
|
||||||
use itertools::Either;
|
use itertools::{Either, Itertools};
|
||||||
|
|
||||||
use crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};
|
use crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};
|
||||||
use crate::expression_tree::{self, BindingExpression, Expression, Unit};
|
use crate::expression_tree::{self, BindingExpression, Expression, Unit};
|
||||||
|
|
@ -77,7 +77,21 @@ impl Document {
|
||||||
|n: syntax_nodes::StructDeclaration,
|
|n: syntax_nodes::StructDeclaration,
|
||||||
diag: &mut BuildDiagnostics,
|
diag: &mut BuildDiagnostics,
|
||||||
local_registry: &mut TypeRegister| {
|
local_registry: &mut TypeRegister| {
|
||||||
let mut ty = type_struct_from_node(n.ObjectType(), diag, local_registry);
|
let rust_attributes: Vec<String> = n
|
||||||
|
.children()
|
||||||
|
.filter(|child| child.kind() == SyntaxKind::AtRustAttr)
|
||||||
|
.map(|child| {
|
||||||
|
let mut text = child.text().to_string();
|
||||||
|
text.pop();
|
||||||
|
text
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
let mut ty = type_struct_from_node(
|
||||||
|
n.ObjectType(),
|
||||||
|
diag,
|
||||||
|
local_registry,
|
||||||
|
Some(rust_attributes),
|
||||||
|
);
|
||||||
if let Type::Struct { name, .. } = &mut ty {
|
if let Type::Struct { name, .. } = &mut ty {
|
||||||
*name = parser::identifier_text(&n.DeclaredIdentifier());
|
*name = parser::identifier_text(&n.DeclaredIdentifier());
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1630,7 +1644,7 @@ pub fn type_from_node(
|
||||||
}
|
}
|
||||||
prop_type
|
prop_type
|
||||||
} else if let Some(object_node) = node.ObjectType() {
|
} else if let Some(object_node) = node.ObjectType() {
|
||||||
type_struct_from_node(object_node, diag, tr)
|
type_struct_from_node(object_node, diag, tr, None)
|
||||||
} else if let Some(array_node) = node.ArrayType() {
|
} else if let Some(array_node) = node.ArrayType() {
|
||||||
Type::Array(Box::new(type_from_node(array_node.Type(), diag, tr)))
|
Type::Array(Box::new(type_from_node(array_node.Type(), diag, tr)))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1644,6 +1658,7 @@ pub fn type_struct_from_node(
|
||||||
object_node: syntax_nodes::ObjectType,
|
object_node: syntax_nodes::ObjectType,
|
||||||
diag: &mut BuildDiagnostics,
|
diag: &mut BuildDiagnostics,
|
||||||
tr: &TypeRegister,
|
tr: &TypeRegister,
|
||||||
|
rust_attributes: Option<Vec<String>>,
|
||||||
) -> Type {
|
) -> Type {
|
||||||
let fields = object_node
|
let fields = object_node
|
||||||
.ObjectTypeMember()
|
.ObjectTypeMember()
|
||||||
|
|
@ -1654,7 +1669,7 @@ pub fn type_struct_from_node(
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
Type::Struct { fields, name: None, node: Some(object_node) }
|
Type::Struct { fields, name: None, node: Some(object_node), rust_attributes }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn animation_element_from_node(
|
fn animation_element_from_node(
|
||||||
|
|
|
||||||
|
|
@ -422,8 +422,9 @@ declare_syntax! {
|
||||||
/// `[ type ]`
|
/// `[ type ]`
|
||||||
ArrayType -> [ Type ],
|
ArrayType -> [ Type ],
|
||||||
/// `struct Foo := { ... }
|
/// `struct Foo := { ... }
|
||||||
StructDeclaration -> [DeclaredIdentifier, ObjectType],
|
StructDeclaration -> [DeclaredIdentifier, ObjectType, ?AtRustAttr],
|
||||||
|
/// `@rust-attr(...)`
|
||||||
|
AtRustAttr -> [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
use super::element::{parse_element, parse_element_content};
|
use super::element::{parse_element, parse_element_content};
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use super::r#type::parse_struct_declaration;
|
use super::r#type::parse_struct_declaration;
|
||||||
|
use crate::parser::r#type::parse_rustattr;
|
||||||
|
|
||||||
#[cfg_attr(test, parser_test)]
|
#[cfg_attr(test, parser_test)]
|
||||||
/// ```test,Document
|
/// ```test,Document
|
||||||
|
|
@ -45,6 +46,35 @@ pub fn parse_document(p: &mut impl Parser) -> bool {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"@" if p.nth(1).as_str() == "rust-attr" => {
|
||||||
|
let mut is_export = false;
|
||||||
|
let mut i = 0;
|
||||||
|
loop {
|
||||||
|
let value = p.nth(i);
|
||||||
|
if value.as_str() == ")" && p.nth(i + 1).as_str() == "export" {
|
||||||
|
is_export = true;
|
||||||
|
break;
|
||||||
|
} else if (value.as_str() == ")"
|
||||||
|
&& p.nth(i + 1).as_str() != "struct"
|
||||||
|
&& p.nth(i + 1).as_str() != "export"
|
||||||
|
&& p.nth(i + 1).as_str() != ")")
|
||||||
|
|| (value.as_str() == ")" && p.nth(i + 1).as_str() == "struct")
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
if is_export {
|
||||||
|
let mut p = p.start_node(SyntaxKind::ExportsList);
|
||||||
|
if !parse_rustattr(&mut *p) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !parse_rustattr(&mut *p) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if !parse_component(&mut *p) {
|
if !parse_component(&mut *p) {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -85,3 +85,57 @@ pub fn parse_struct_declaration(p: &mut impl Parser) -> bool {
|
||||||
parse_type_object(&mut *p);
|
parse_type_object(&mut *p);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_rustattr(p: &mut impl Parser) -> bool {
|
||||||
|
let checkpoint = p.checkpoint();
|
||||||
|
debug_assert_eq!(p.peek().as_str(), "@");
|
||||||
|
p.consume(); // "@"
|
||||||
|
if p.peek().as_str() != "rust-attr" {
|
||||||
|
p.expect(SyntaxKind::AtRustAttr);
|
||||||
|
}
|
||||||
|
p.consume(); // "rust-attr"
|
||||||
|
p.expect(SyntaxKind::LParent);
|
||||||
|
parse_parentheses(&mut *p);
|
||||||
|
if p.peek().as_str() == "export" {
|
||||||
|
p.consume();
|
||||||
|
}
|
||||||
|
let mut p = p.start_node_at(checkpoint, SyntaxKind::StructDeclaration);
|
||||||
|
p.consume(); // "struct"
|
||||||
|
{
|
||||||
|
let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
|
||||||
|
p.expect(SyntaxKind::Identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.peek().kind() == SyntaxKind::ColonEqual {
|
||||||
|
p.warning("':=' to declare a struct is deprecated. Remove the ':='");
|
||||||
|
p.consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_type_object(&mut *p);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_parentheses(p: &mut impl Parser) -> bool {
|
||||||
|
let mut p = p.start_node(SyntaxKind::AtRustAttr);
|
||||||
|
let mut opened = 0;
|
||||||
|
let mut closed = 0;
|
||||||
|
while closed <= opened {
|
||||||
|
if p.peek().kind() == SyntaxKind::LParent {
|
||||||
|
opened += 1;
|
||||||
|
}
|
||||||
|
if p.peek().kind() == SyntaxKind::RParent {
|
||||||
|
closed += 1;
|
||||||
|
}
|
||||||
|
if closed == opened && opened != 0 && closed != 0 && p.peek().kind() != SyntaxKind::RParent
|
||||||
|
{
|
||||||
|
p.error("Parse error: `)` or `,`");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
p.consume();
|
||||||
|
}
|
||||||
|
if p.peek().as_str() != "struct" && p.peek().as_str() != "export" {
|
||||||
|
p.error("Parse error: expected `struct` or `export`");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,7 @@ fn compile_path_from_string_literal(
|
||||||
.collect(),
|
.collect(),
|
||||||
name: Some("Point".into()),
|
name: Some("Point".into()),
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut points = Vec::new();
|
let mut points = Vec::new();
|
||||||
|
|
|
||||||
|
|
@ -969,6 +969,7 @@ impl Expression {
|
||||||
fields: values.iter().map(|(k, v)| (k.clone(), v.ty())).collect(),
|
fields: values.iter().map(|(k, v)| (k.clone(), v.ty())).collect(),
|
||||||
name: None,
|
name: None,
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
};
|
};
|
||||||
Expression::Struct { ty, values }
|
Expression::Struct { ty, values }
|
||||||
}
|
}
|
||||||
|
|
@ -1030,8 +1031,14 @@ impl Expression {
|
||||||
fields: mut result_fields,
|
fields: mut result_fields,
|
||||||
name: result_name,
|
name: result_name,
|
||||||
node: result_node,
|
node: result_node,
|
||||||
|
rust_attributes,
|
||||||
|
},
|
||||||
|
Type::Struct {
|
||||||
|
fields: elem_fields,
|
||||||
|
name: elem_name,
|
||||||
|
node: elem_node,
|
||||||
|
rust_attributes: deriven,
|
||||||
},
|
},
|
||||||
Type::Struct { fields: elem_fields, name: elem_name, node: elem_node },
|
|
||||||
) => {
|
) => {
|
||||||
for (elem_name, elem_ty) in elem_fields.into_iter() {
|
for (elem_name, elem_ty) in elem_fields.into_iter() {
|
||||||
match result_fields.entry(elem_name) {
|
match result_fields.entry(elem_name) {
|
||||||
|
|
@ -1052,6 +1059,7 @@ impl Expression {
|
||||||
name: result_name.or(elem_name),
|
name: result_name.or(elem_name),
|
||||||
fields: result_fields,
|
fields: result_fields,
|
||||||
node: result_node.or(elem_node),
|
node: result_node.or(elem_node),
|
||||||
|
rust_attributes: rust_attributes.or(deriven),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(Type::Color, Type::Brush) | (Type::Brush, Type::Color) => Type::Brush,
|
(Type::Color, Type::Brush) | (Type::Brush, Type::Color) => Type::Brush,
|
||||||
|
|
|
||||||
|
|
@ -355,6 +355,7 @@ fn add_highlight_items(doc: &Document) {
|
||||||
.collect(),
|
.collect(),
|
||||||
name: None,
|
name: None,
|
||||||
node: None,
|
node: None,
|
||||||
|
rust_attributes: None,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue