From bf44f9a24df6713f89ed95eaa69eab28f102d0cc Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 25 Apr 2024 19:27:34 +0200 Subject: rebel-parse: token: represent string tokens as a Vec as well --- crates/rebel-parse/src/ast.rs | 18 ++++++++++++++++++ crates/rebel-parse/src/grammar/recipe.rs | 6 +++--- crates/rebel-parse/src/grammar/tokenize.rs | 21 +++++++++++++++------ crates/rebel-parse/src/token.rs | 11 +++++++++-- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/crates/rebel-parse/src/ast.rs b/crates/rebel-parse/src/ast.rs index f9943d4..648a79e 100644 --- a/crates/rebel-parse/src/ast.rs +++ b/crates/rebel-parse/src/ast.rs @@ -1,3 +1,5 @@ +use crate::token; + pub type Recipe<'a> = Vec>; #[derive(Debug, Clone, PartialEq, Eq)] @@ -165,6 +167,22 @@ pub enum StringPiece<'a> { Interp(Expr<'a>), } +impl<'a> TryFrom<&token::StringPiece<'a>> for StringPiece<'a> { + type Error = &'static str; + + fn try_from(value: &token::StringPiece<'a>) -> Result { + use crate::recipe; + + Ok(match value { + token::StringPiece::Chars(chars) => StringPiece::Chars(chars), + token::StringPiece::Escape(c) => StringPiece::Escape(*c), + token::StringPiece::Interp(tokens) => StringPiece::Interp( + recipe::expr(tokens).or(Err("Invalid expression in string interpolation"))?, + ), + }) + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct MapEntry<'a> { pub key: &'a str, diff --git a/crates/rebel-parse/src/grammar/recipe.rs b/crates/rebel-parse/src/grammar/recipe.rs index 6bd96bb..49b1689 100644 --- a/crates/rebel-parse/src/grammar/recipe.rs +++ b/crates/rebel-parse/src/grammar/recipe.rs @@ -97,9 +97,9 @@ peg::parser! { / [Token::Number(content)] { ? ast::Literal::number(content) } - / [Token::String(String { content, .. })] { - let ast_pieces = vec![ast::StringPiece::Chars(content)]; - ast::Literal::String(ast_pieces) + / [Token::String(String { pieces, .. })] { ? + let ast_pieces = pieces.iter().map(|piece| piece.try_into()).collect::>()?; + Ok(ast::Literal::String(ast_pieces)) } / p('(') p(')') { ast::Literal::Unit } / p('(') elements:(expr() ** p(',')) p(',')? p(')') { diff --git a/crates/rebel-parse/src/grammar/tokenize.rs b/crates/rebel-parse/src/grammar/tokenize.rs index 5f21461..a64c5e1 100644 --- a/crates/rebel-parse/src/grammar/tokenize.rs +++ b/crates/rebel-parse/src/grammar/tokenize.rs @@ -33,14 +33,23 @@ peg::parser! { = $(['0'..='9'] ['0'..='9' | 'a'..='z' | 'A'..='Z' | '_']*) rule string() -> String<'input> - = "\"" content:$(string_char()*) "\"" { - String { content, kind: StringKind::String } + = "\"" chars:$(string_char()*) "\"" { + String { + pieces: vec![StringPiece::Chars(chars)], + kind: StringKind::String, + } } - / "r\"" content:$([^'"']*) "\"" { - String { content, kind: StringKind::RawString } + / "r\"" chars:$([^'"']*) "\"" { + String { + pieces: vec![StringPiece::Chars(chars)], + kind: StringKind::RawString, + } } - / "```" newline() content:$((!"```" [_])+) "```" { - String { content, kind: StringKind::ScriptString } + / "```" newline() chars:$((!"```" [_])+) "```" { + String { + pieces: vec![StringPiece::Chars(chars)], + kind: StringKind::ScriptString, + } } rule string_char() diff --git a/crates/rebel-parse/src/token.rs b/crates/rebel-parse/src/token.rs index d147205..2f2f849 100644 --- a/crates/rebel-parse/src/token.rs +++ b/crates/rebel-parse/src/token.rs @@ -15,12 +15,19 @@ pub enum Spacing { Joint, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct String<'a> { - pub content: &'a str, + pub pieces: Vec>, pub kind: StringKind, } +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum StringPiece<'a> { + Chars(&'a str), + Escape(char), + Interp(TokenStream<'a>), +} + #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum StringKind { String, -- cgit v1.2.3