diff --git a/hornbeam_grammar/src/hornbeam.pest b/hornbeam_grammar/src/hornbeam.pest index ee171c7..2360878 100644 --- a/hornbeam_grammar/src/hornbeam.pest +++ b/hornbeam_grammar/src/hornbeam.pest @@ -125,20 +125,21 @@ lineEnd = _{ ws_nocnl* ~ nlOrEoi ~ (ws_nocnl* ~ NEWLINE)* ~ (ws_nocnl* ~ &EOI)? // was: lineEnd = _{ ws_nocnl* ~ nlOrEoi ~ (!EOI ~ ws* ~ nlOrEoi)* } SingleStringContent = { (!("'" | "\\" | "$") ~ ANY)+ } -singleString = _{ !("''") ~ "'" ~ (SingleStringContent | SEscape | SInterpol)* ~ "'" } +singleString = _{ !("''") ~ "'" ~ (SingleStringContent | SEscape | SSimpleVarInterpol | SInterpol)* ~ "'" } DoubleStringContent = { (!("\"" | "\\" | "$") ~ ANY)+ } -doubleString = _{ "\"" ~ (DoubleStringContent | SEscape | SInterpol)* ~ "\"" } +doubleString = _{ "\"" ~ (DoubleStringContent | SEscape | SSimpleVarInterpol | SInterpol)* ~ "\"" } blockStringStart = _{ "''" ~ NEWLINE ~ PEEK_ALL } blockStringEnd = _{ NEWLINE ~ (" " | "\t")* ~ "''" } BlockStringContent = { (!(NEWLINE | blockStringEnd | "\\" | "$" | "@") ~ ANY)+ } // This rule becomes just \n later on, so it effectively strips leading indentation! BlockStringNewline = { !blockStringEnd ~ NEWLINE ~ PEEK_ALL } -blockString = _{ blockStringStart ~ (BlockStringContent | SEscape | SInterpol | ParameterisedLocalisation | BlockStringNewline)* ~ blockStringEnd } +blockString = _{ blockStringStart ~ (BlockStringContent | SEscape | SSimpleVarInterpol | SInterpol | ParameterisedLocalisation | BlockStringNewline)* ~ blockStringEnd } String = { blockString | singleString | doubleString | ParameterisedLocalisation } SEscape = { "\\" ~ ("\\" | "'" | "\"" | "$" | "@") } +SSimpleVarInterpol = { "$" ~ Identifier } SInterpol = { "${" ~ ws* ~ Expr ~ ws* ~ "}" } diff --git a/hornbeam_grammar/src/parser.rs b/hornbeam_grammar/src/parser.rs index 1e0f3b9..425c5b1 100644 --- a/hornbeam_grammar/src/parser.rs +++ b/hornbeam_grammar/src/parser.rs @@ -205,8 +205,17 @@ impl HornbeamParser { fn String(input: Node) -> PCResult { let mut pieces = Vec::new(); for node in input.into_children() { + let loc = nodeloc(&node); match node.as_rule() { Rule::SEscape => pieces.push(StringPiece::Literal(HornbeamParser::SEscape(node)?)), + Rule::SSimpleVarInterpol => { + let var_identifier = + HornbeamParser::Identifier(node.into_children().single()?)?; + pieces.push(StringPiece::Interpolation(Expression::Variable { + name: var_identifier, + loc, + })); + } Rule::SInterpol => pieces.push(StringPiece::Interpolation(HornbeamParser::Expr( node.into_children().single()?, )?)),