Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion internal/compiler/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,12 +374,14 @@ declare_syntax! {
// FIXME: the test should test that as alternative rather than several of them (but it can also be a literal)
Expression-> [ ?Expression, ?FunctionCallExpression, ?IndexExpression, ?SelfAssignment,
?ConditionalExpression, ?QualifiedName, ?BinaryExpression, ?Array, ?ObjectLiteral,
?UnaryOpExpression, ?CodeBlock, ?StringTemplate, ?AtImageUrl, ?AtGradient, ?AtTr,
?UnaryOpExpression, ?CodeBlock, ?StringTemplate, ?AtImageUrl, ?AtIncludeString, ?AtGradient, ?AtTr,
?MemberAccess, ?AtKeys ],
/// Concatenate the Expressions to make a string (usually expended from a template string)
StringTemplate -> [*Expression],
/// `@image-url("foo.png")`
AtImageUrl -> [],
/// `@include_string("foo.txt")`
AtIncludeString -> [],
/// `@linear-gradient(...)` or `@radial-gradient(...)`
AtGradient -> [*Expression],
/// `@tr("foo", ...)` // the string is a StringLiteral
Expand Down
39 changes: 38 additions & 1 deletion internal/compiler/parser/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ fn parse_at_keyword(p: &mut impl Parser) {
"image-url" | "image_url" => {
parse_image_url(p);
}
"include-string" | "include_string" => {
parse_include_string(p);
}
"linear-gradient" | "linear_gradient" => {
parse_gradient(p);
}
Expand All @@ -264,7 +267,7 @@ fn parse_at_keyword(p: &mut impl Parser) {
_ => {
p.consume();
p.test(SyntaxKind::Identifier); // consume the identifier, so that autocomplete works
p.error("Expected 'image-url', 'tr', 'keys', 'conic-gradient', 'linear-gradient', or 'radial-gradient' after '@'");
p.error("Expected 'image-url', 'include-string', 'tr', 'keys', 'conic-gradient', 'linear-gradient', or 'radial-gradient' after '@'");
}
}
}
Expand Down Expand Up @@ -738,3 +741,37 @@ fn parse_image_url(p: &mut impl Parser) {
p.until(SyntaxKind::RParent);
}
}

#[cfg_attr(test, parser_test)]
/// ```test,AtIncludeString
/// @include_string("foo.txt")
/// @include_string("foo.txt",)
/// ```
fn parse_include_string(p: &mut impl Parser) {
let mut p = p.start_node(SyntaxKind::AtIncludeString);
p.consume(); // "@"
p.consume(); // "include-string"
if !(p.expect(SyntaxKind::LParent)) {
return;
}
let peek = p.peek();
if peek.kind() != SyntaxKind::StringLiteral {
p.error("@include_string must contain a plain path as a string literal");
p.until(SyntaxKind::RParent);
return;
}
if !peek.as_str().starts_with('"') || !peek.as_str().ends_with('"') {
p.error("@include_string must contain a plain path as a string literal, without any '\\{}' expressions");
p.until(SyntaxKind::RParent);
return;
}
p.expect(SyntaxKind::StringLiteral);
if !p.test(SyntaxKind::Comma) {
if !p.test(SyntaxKind::RParent) {
p.error("Expected ')' or ','");
p.until(SyntaxKind::RParent);
}
return;
}
p.expect(SyntaxKind::RParent);
}
56 changes: 56 additions & 0 deletions internal/compiler/passes/resolving.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,9 @@ impl Expression {
NodeOrToken::Node(node) => match node.kind() {
SyntaxKind::Expression => Some(Self::from_expression_node(node.into(), ctx)),
SyntaxKind::AtImageUrl => Some(Self::from_at_image_url_node(node.into(), ctx)),
SyntaxKind::AtIncludeString => {
Some(Self::from_at_include_string_node(node.into(), ctx))
}
SyntaxKind::AtGradient => Some(Self::from_at_gradient(node.into(), ctx)),
SyntaxKind::AtTr => Some(Self::from_at_tr(node.into(), ctx)),
SyntaxKind::AtMarkdown => Some(Self::from_at_markdown(node.into(), ctx)),
Expand Down Expand Up @@ -521,6 +524,59 @@ impl Expression {
}
}

fn from_at_include_string_node(
node: syntax_nodes::AtIncludeString,
ctx: &mut LookupCtx,
) -> Self {
let s = match node
.child_text(SyntaxKind::StringLiteral)
.and_then(|x| crate::literals::unescape_string(&x))
{
Some(s) => s,
None => {
ctx.diag.push_error("Cannot parse string literal".into(), &node);
return Self::Invalid;
}
};

if s.is_empty() {
return Expression::StringLiteral(String::new().into());
}

let path = std::path::Path::new(&s);
if crate::pathutils::is_absolute(path) {
match std::fs::read_to_string(path) {
Ok(content) => Expression::StringLiteral(content.into()),
Err(e) => {
ctx.diag.push_error(format!("Cannot read file: {}", e), &node);
Self::Invalid
}
}
} else {
let resolved_path = ctx
.type_loader
.and_then(|loader| loader.resolve_import_path(Some(&(*node).clone().into()), &s))
.map(|i| i.0.to_string_lossy().into())
.unwrap_or_else(|| {
crate::pathutils::join(
&crate::pathutils::dirname(node.source_file.path()),
path,
)
.map(|p| p.to_string_lossy().into())
.unwrap_or(s.clone())
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this code is duplicated from from_at_image_url_node, I think it presents a good candidate for moving that into a helper function.


match std::fs::read_to_string(&resolved_path) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the approach of embedding the text should be the same that we also use for images. So for Rust we use include_bytes!() (could be include_str!()), and for C++ we read the file at slint-compiler run-time and then embed it as an array or perhaps a u8 literal.

I have the feeling that this will require a dedicated Expression that can be handled in the generators as well as from_at_markdown.

Ok(content) => Expression::StringLiteral(content.into()),
Err(e) => {
ctx.diag
.push_error(format!("Cannot read file '{}': {}", resolved_path, e), &node);
Self::Invalid
}
}
}
}

pub fn from_at_gradient(node: syntax_nodes::AtGradient, ctx: &mut LookupCtx) -> Self {
enum GradKind {
Linear { angle: Box<Expression> },
Expand Down
Loading