From 8f9882d1ad4e15ba8e48a2902abeefbec7ecc26d Mon Sep 17 00:00:00 2001 From: oxalica Date: Sun, 25 Sep 2022 20:53:08 +0800 Subject: [PATCH] Always wrap error syntax in ERROR nodes This prevents error tokens accidentally affect the container node, eg. the dangling `let` inside an Attrset. Fixes #20 --- crates/syntax/src/parser.rs | 23 +- .../test_data/parser/err/incomplete-pat.ast | 3 +- .../test_data/parser/err/invalid-or.ast | 3 +- .../test_data/parser/err/invalid-rec.ast | 3 +- .../test_data/parser/err/let-as-binding.ast | 60 +++ .../test_data/parser/err/let-as-binding.nix | 8 + .../test_data/parser/err/multiple-or.ast | 10 +- crates/syntax/test_data/parser/fuzz/0001.ast | 3 +- crates/syntax/test_data/parser/fuzz/0002.ast | 427 ++++++++++++------ 9 files changed, 378 insertions(+), 162 deletions(-) create mode 100644 crates/syntax/test_data/parser/err/let-as-binding.ast create mode 100644 crates/syntax/test_data/parser/err/let-as-binding.nix diff --git a/crates/syntax/src/parser.rs b/crates/syntax/src/parser.rs index 2c0e498..f02b597 100644 --- a/crates/syntax/src/parser.rs +++ b/crates/syntax/src/parser.rs @@ -68,7 +68,7 @@ impl<'i> Parser<'i> { self.expr_function_opt(); // Don't stuck. if self.tokens.len() == prev { - self.bump(); + self.bump_error(); } } self.finish_node(); @@ -116,6 +116,13 @@ impl<'i> Parser<'i> { self.builder.token(kind.into(), &self.src[range]); } + /// Consume the next token and wrap it in an ERROR node. + fn bump_error(&mut self) { + self.start_node(ERROR); + self.bump(); + self.finish_node(); + } + /// Peek the next token, including whitespaces. fn peek_full(&mut self) -> Option<(SyntaxKind, TextRange)> { self.steps += 1; @@ -181,12 +188,14 @@ impl<'i> Parser<'i> { return true; } Some(k) if !k.is_separator() => { + self.start_node(ERROR); let prev = self.tokens.len(); self.expr_function_opt(); // Don't stuck! if self.tokens.len() == prev { self.bump(); } + self.finish_node(); } _ => return false, } @@ -239,7 +248,7 @@ impl<'i> Parser<'i> { if matches!(self.peek_iter_non_ws().nth(1), Some(T!['{'])) { self.expr_operator_opt() } else { - self.bump(); + self.bump_error(); self.error(ErrorKind::MissingToken(T!['{'])); } } @@ -320,7 +329,7 @@ impl<'i> Parser<'i> { self.bump(); // IDENT self.finish_node(); if self.peek_non_ws() == Some(T![@]) { - self.bump(); + self.bump(); // @ if self.peek_non_ws() == Some(T!['{']) { self.pat(); } else { @@ -509,7 +518,7 @@ impl<'i> Parser<'i> { } Some(k) if !k.is_separator() => { self.error(ErrorKind::MissingElemExpr); - self.bump(); + self.bump_error(); } _ => { self.error(ErrorKind::MissingToken(T![']'])); @@ -609,7 +618,7 @@ impl<'i> Parser<'i> { } Some(k) => { self.error(ErrorKind::MissingParamIdent); - self.bump(); + self.bump_error(); // Don't double error. if k == T![,] { continue; @@ -641,7 +650,7 @@ impl<'i> Parser<'i> { break; } Some(k) if k == guard => { - self.bump(); + self.bump(); // guard break; } Some(T![inherit]) => { @@ -699,7 +708,7 @@ impl<'i> Parser<'i> { // This can happen for some extra tokens (eg. unfinished exprs) in AttrSet or LetIn. Some(_) => { self.error(ErrorKind::MissingBinding); - self.bump(); + self.bump_error(); } } } diff --git a/crates/syntax/test_data/parser/err/incomplete-pat.ast b/crates/syntax/test_data/parser/err/incomplete-pat.ast index 850f6c5..a73a36a 100644 --- a/crates/syntax/test_data/parser/err/incomplete-pat.ast +++ b/crates/syntax/test_data/parser/err/incomplete-pat.ast @@ -12,7 +12,8 @@ SOURCE_FILE@0..25 SPACE@3..4 "\n" COMMA@4..5 "," SPACE@5..6 "\n" - COMMA@6..7 "," + ERROR@6..7 + COMMA@6..7 "," SPACE@7..8 " " PAT_FIELD@8..10 NAME@8..9 diff --git a/crates/syntax/test_data/parser/err/invalid-or.ast b/crates/syntax/test_data/parser/err/invalid-or.ast index c65e3f3..fc462de 100644 --- a/crates/syntax/test_data/parser/err/invalid-or.ast +++ b/crates/syntax/test_data/parser/err/invalid-or.ast @@ -7,7 +7,8 @@ SOURCE_FILE@0..21 LIST@0..6 L_BRACK@0..1 "[" SPACE@1..2 " " - KW_OR@2..4 "or" + ERROR@2..4 + KW_OR@2..4 "or" SPACE@4..5 " " R_BRACK@5..6 "]" SPACE@6..7 " " diff --git a/crates/syntax/test_data/parser/err/invalid-rec.ast b/crates/syntax/test_data/parser/err/invalid-rec.ast index b4ad26a..2d021e0 100644 --- a/crates/syntax/test_data/parser/err/invalid-rec.ast +++ b/crates/syntax/test_data/parser/err/invalid-rec.ast @@ -13,5 +13,6 @@ SOURCE_FILE@0..12 SPACE@5..6 " " EQ@6..7 "=" SPACE@7..8 " " - KW_REC@8..11 "rec" + ERROR@8..11 + KW_REC@8..11 "rec" SPACE@11..12 "\n" diff --git a/crates/syntax/test_data/parser/err/let-as-binding.ast b/crates/syntax/test_data/parser/err/let-as-binding.ast new file mode 100644 index 0000000..f2bc0a0 --- /dev/null +++ b/crates/syntax/test_data/parser/err/let-as-binding.ast @@ -0,0 +1,60 @@ +Mising binding at 13..16 +Mising binding at 30..32 +Mising binding at 33..34 +Multiple root expressions at 49..50 +Missing expression at 49..50 +Multiple root expressions at 51..52 +Missing expression at 51..52 +SOURCE_FILE@0..53 + ATTR_SET@0..49 + L_CURLY@0..1 "{" + SPACE@1..4 "\n " + ATTR_PATH_VALUE@4..10 + ATTR_PATH@4..6 + NAME@4..5 + IDENT@4..5 "a" + SPACE@5..6 " " + EQ@6..7 "=" + SPACE@7..8 " " + LITERAL@8..9 + INT@8..9 "1" + SEMICOLON@9..10 ";" + SPACE@10..13 "\n " + ERROR@13..16 + KW_LET@13..16 "let" + SPACE@16..21 "\n " + ATTR_PATH_VALUE@21..27 + ATTR_PATH@21..23 + NAME@21..22 + IDENT@21..22 "b" + SPACE@22..23 " " + EQ@23..24 "=" + SPACE@24..25 " " + LITERAL@25..26 + INT@25..26 "1" + SEMICOLON@26..27 ";" + SPACE@27..30 "\n " + ERROR@30..32 + KW_IN@30..32 "in" + SPACE@32..33 " " + ERROR@33..34 + L_CURLY@33..34 "{" + SPACE@34..39 "\n " + ATTR_PATH_VALUE@39..45 + ATTR_PATH@39..41 + NAME@39..40 + IDENT@39..40 "c" + SPACE@40..41 " " + EQ@41..42 "=" + SPACE@42..43 " " + REF@43..44 + IDENT@43..44 "b" + SEMICOLON@44..45 ";" + SPACE@45..48 "\n " + R_CURLY@48..49 "}" + ERROR@49..50 + SEMICOLON@49..50 ";" + SPACE@50..51 "\n" + ERROR@51..52 + R_CURLY@51..52 "}" + SPACE@52..53 "\n" diff --git a/crates/syntax/test_data/parser/err/let-as-binding.nix b/crates/syntax/test_data/parser/err/let-as-binding.nix new file mode 100644 index 0000000..c12a35d --- /dev/null +++ b/crates/syntax/test_data/parser/err/let-as-binding.nix @@ -0,0 +1,8 @@ +{ + a = 1; + let + b = 1; + in { + c = b; + }; +} diff --git a/crates/syntax/test_data/parser/err/multiple-or.ast b/crates/syntax/test_data/parser/err/multiple-or.ast index 72f366d..73840b6 100644 --- a/crates/syntax/test_data/parser/err/multiple-or.ast +++ b/crates/syntax/test_data/parser/err/multiple-or.ast @@ -12,9 +12,10 @@ SOURCE_FILE@0..24 REF@3..5 IDENT@3..5 "or" SPACE@5..6 " " - APPLY@6..8 - REF@6..8 - IDENT@6..8 "or" + ERROR@6..8 + APPLY@6..8 + REF@6..8 + IDENT@6..8 "or" R_PAREN@8..9 ")" SPACE@9..10 " " LIST@10..23 @@ -27,7 +28,8 @@ SOURCE_FILE@0..24 REF@14..16 IDENT@14..16 "or" SPACE@16..17 " " - KW_OR@17..19 "or" + ERROR@17..19 + KW_OR@17..19 "or" SPACE@19..20 " " REF@20..21 IDENT@20..21 "b" diff --git a/crates/syntax/test_data/parser/fuzz/0001.ast b/crates/syntax/test_data/parser/fuzz/0001.ast index 2688e3c..a671168 100644 --- a/crates/syntax/test_data/parser/fuzz/0001.ast +++ b/crates/syntax/test_data/parser/fuzz/0001.ast @@ -11,6 +11,7 @@ SOURCE_FILE@0..6 NAME@1..2 IDENT@1..2 "Y" COMMA@2..3 "," - L_CURLY@3..4 "{" + ERROR@3..4 + L_CURLY@3..4 "{" COMMA@4..5 "," SPACE@5..6 "\n" diff --git a/crates/syntax/test_data/parser/fuzz/0002.ast b/crates/syntax/test_data/parser/fuzz/0002.ast index 984363a..178dfc9 100644 --- a/crates/syntax/test_data/parser/fuzz/0002.ast +++ b/crates/syntax/test_data/parser/fuzz/0002.ast @@ -190,13 +190,18 @@ SOURCE_FILE@0..241 BANG@7..8 "!" REF@8..17 IDENT@8..17 "KKKKKKKKK" - ERROR@17..18 "%" - ERROR@18..19 "$" + ERROR@17..18 + ERROR@17..18 "%" + ERROR@18..19 + ERROR@18..19 "$" LIST@19..129 L_BRACK@19..20 "[" - ERROR@20..21 "^" - ERROR@21..22 "'" - ERROR@22..23 "$" + ERROR@20..21 + ERROR@20..21 "^" + ERROR@21..22 + ERROR@21..22 "'" + ERROR@22..23 + ERROR@22..23 "$" PATH_INTERPOLATION@23..129 PATH_START@23..23 "" PATH_FRAGMENT@23..24 "/" @@ -204,88 +209,168 @@ SOURCE_FILE@0..241 DOLLAR_L_CURLY@24..26 "${" REF@26..50 IDENT@26..50 "KKKKKKKKKKKKKKKcKKkKKKKK" - ERROR@50..51 "\u{11}" - ERROR@51..52 "\u{11}" - ERROR@52..53 "\u{11}" - ERROR@53..54 "\u{11}" - ERROR@54..55 "\u{11}" - ERROR@55..56 "\u{11}" - ERROR@56..57 "\u{11}" - ERROR@57..58 "\u{11}" - ERROR@58..59 "\u{11}" - ERROR@59..60 "\u{11}" - ERROR@60..61 "\u{11}" - ERROR@61..62 "\u{11}" - ERROR@62..63 "\u{11}" - ERROR@63..64 "\u{11}" - ERROR@64..65 "\u{11}" - ERROR@65..66 "\u{11}" - ERROR@66..67 "\u{11}" - ERROR@67..68 "\u{11}" - ERROR@68..69 "\u{11}" - ERROR@69..70 "\u{11}" - ERROR@70..71 "\u{11}" - ERROR@71..72 "\u{11}" - ERROR@72..73 "\u{11}" - ERROR@73..74 "\u{11}" - ERROR@74..75 "\u{11}" - ERROR@75..76 "\u{11}" - ERROR@76..77 "\u{11}" - ERROR@77..78 "\u{11}" - ERROR@78..79 "\u{11}" - ERROR@79..80 "\u{11}" - ERROR@80..81 "\u{11}" - ERROR@81..82 "\u{11}" - ERROR@82..83 "\u{11}" - ERROR@83..84 "\u{11}" - ERROR@84..85 "\u{11}" - ERROR@85..86 "\u{11}" - ERROR@86..87 "\u{11}" - ERROR@87..88 "\u{11}" - ERROR@88..89 "\u{11}" - ERROR@89..90 "\u{11}" - ERROR@90..91 "\u{11}" - ERROR@91..92 "\u{11}" - ERROR@92..93 "\u{11}" - ERROR@93..94 "\u{11}" - ERROR@94..95 "\u{11}" - ERROR@95..96 "\u{11}" - ERROR@96..97 "\u{11}" - ERROR@97..98 "\u{11}" - ERROR@98..99 "\u{11}" - ERROR@99..100 "\u{11}" - ERROR@100..101 "\u{11}" - ERROR@101..102 "\u{11}" - ERROR@102..103 "\u{11}" - ERROR@103..104 "\u{11}" - ERROR@104..105 "\u{11}" - ERROR@105..106 "\u{11}" - ERROR@106..107 "\u{11}" - ERROR@107..108 "\u{11}" - ERROR@108..109 "\u{11}" - ERROR@109..110 "\u{11}" - ERROR@110..111 "\u{11}" - ERROR@111..112 "\u{11}" - ERROR@112..113 "\u{11}" - ERROR@113..114 "\u{11}" - ERROR@114..115 "\u{11}" - ERROR@115..116 "\u{11}" - ERROR@116..117 "\u{11}" - ERROR@117..118 "\u{11}" - REF@118..122 - IDENT@118..122 "KKKK" - ERROR@122..123 "%" - ERROR@123..124 "\0" - ERROR@124..125 "\0" - ERROR@125..126 "\0" - ERROR@126..127 "\u{14}" - ERROR@127..128 "$" - LIST@128..129 - L_BRACK@128..129 "[" - R_PAREN@129..130 ")" - ERROR@130..131 "^" - ERROR@131..132 "'" - ERROR@132..133 "$" + ERROR@50..51 + ERROR@50..51 "\u{11}" + ERROR@51..52 + ERROR@51..52 "\u{11}" + ERROR@52..53 + ERROR@52..53 "\u{11}" + ERROR@53..54 + ERROR@53..54 "\u{11}" + ERROR@54..55 + ERROR@54..55 "\u{11}" + ERROR@55..56 + ERROR@55..56 "\u{11}" + ERROR@56..57 + ERROR@56..57 "\u{11}" + ERROR@57..58 + ERROR@57..58 "\u{11}" + ERROR@58..59 + ERROR@58..59 "\u{11}" + ERROR@59..60 + ERROR@59..60 "\u{11}" + ERROR@60..61 + ERROR@60..61 "\u{11}" + ERROR@61..62 + ERROR@61..62 "\u{11}" + ERROR@62..63 + ERROR@62..63 "\u{11}" + ERROR@63..64 + ERROR@63..64 "\u{11}" + ERROR@64..65 + ERROR@64..65 "\u{11}" + ERROR@65..66 + ERROR@65..66 "\u{11}" + ERROR@66..67 + ERROR@66..67 "\u{11}" + ERROR@67..68 + ERROR@67..68 "\u{11}" + ERROR@68..69 + ERROR@68..69 "\u{11}" + ERROR@69..70 + ERROR@69..70 "\u{11}" + ERROR@70..71 + ERROR@70..71 "\u{11}" + ERROR@71..72 + ERROR@71..72 "\u{11}" + ERROR@72..73 + ERROR@72..73 "\u{11}" + ERROR@73..74 + ERROR@73..74 "\u{11}" + ERROR@74..75 + ERROR@74..75 "\u{11}" + ERROR@75..76 + ERROR@75..76 "\u{11}" + ERROR@76..77 + ERROR@76..77 "\u{11}" + ERROR@77..78 + ERROR@77..78 "\u{11}" + ERROR@78..79 + ERROR@78..79 "\u{11}" + ERROR@79..80 + ERROR@79..80 "\u{11}" + ERROR@80..81 + ERROR@80..81 "\u{11}" + ERROR@81..82 + ERROR@81..82 "\u{11}" + ERROR@82..83 + ERROR@82..83 "\u{11}" + ERROR@83..84 + ERROR@83..84 "\u{11}" + ERROR@84..85 + ERROR@84..85 "\u{11}" + ERROR@85..86 + ERROR@85..86 "\u{11}" + ERROR@86..87 + ERROR@86..87 "\u{11}" + ERROR@87..88 + ERROR@87..88 "\u{11}" + ERROR@88..89 + ERROR@88..89 "\u{11}" + ERROR@89..90 + ERROR@89..90 "\u{11}" + ERROR@90..91 + ERROR@90..91 "\u{11}" + ERROR@91..92 + ERROR@91..92 "\u{11}" + ERROR@92..93 + ERROR@92..93 "\u{11}" + ERROR@93..94 + ERROR@93..94 "\u{11}" + ERROR@94..95 + ERROR@94..95 "\u{11}" + ERROR@95..96 + ERROR@95..96 "\u{11}" + ERROR@96..97 + ERROR@96..97 "\u{11}" + ERROR@97..98 + ERROR@97..98 "\u{11}" + ERROR@98..99 + ERROR@98..99 "\u{11}" + ERROR@99..100 + ERROR@99..100 "\u{11}" + ERROR@100..101 + ERROR@100..101 "\u{11}" + ERROR@101..102 + ERROR@101..102 "\u{11}" + ERROR@102..103 + ERROR@102..103 "\u{11}" + ERROR@103..104 + ERROR@103..104 "\u{11}" + ERROR@104..105 + ERROR@104..105 "\u{11}" + ERROR@105..106 + ERROR@105..106 "\u{11}" + ERROR@106..107 + ERROR@106..107 "\u{11}" + ERROR@107..108 + ERROR@107..108 "\u{11}" + ERROR@108..109 + ERROR@108..109 "\u{11}" + ERROR@109..110 + ERROR@109..110 "\u{11}" + ERROR@110..111 + ERROR@110..111 "\u{11}" + ERROR@111..112 + ERROR@111..112 "\u{11}" + ERROR@112..113 + ERROR@112..113 "\u{11}" + ERROR@113..114 + ERROR@113..114 "\u{11}" + ERROR@114..115 + ERROR@114..115 "\u{11}" + ERROR@115..116 + ERROR@115..116 "\u{11}" + ERROR@116..117 + ERROR@116..117 "\u{11}" + ERROR@117..118 + ERROR@117..118 "\u{11}" + ERROR@118..122 + REF@118..122 + IDENT@118..122 "KKKK" + ERROR@122..123 + ERROR@122..123 "%" + ERROR@123..124 + ERROR@123..124 "\0" + ERROR@124..125 + ERROR@124..125 "\0" + ERROR@125..126 + ERROR@125..126 "\0" + ERROR@126..127 + ERROR@126..127 "\u{14}" + ERROR@127..128 + ERROR@127..128 "$" + ERROR@128..129 + LIST@128..129 + L_BRACK@128..129 "[" + ERROR@129..130 + R_PAREN@129..130 ")" + ERROR@130..131 + ERROR@130..131 "^" + ERROR@131..132 + ERROR@131..132 "'" + ERROR@132..133 + ERROR@132..133 "$" PATH_INTERPOLATION@133..157 PATH_START@133..133 "" PATH_FRAGMENT@133..134 "/" @@ -293,33 +378,53 @@ SOURCE_FILE@0..241 DOLLAR_L_CURLY@134..136 "${" REF@136..141 IDENT@136..141 "KKKKK" - ERROR@141..142 "\u{6}" - ERROR@142..143 "\u{6}" - ATTR_SET@143..156 - L_CURLY@143..144 "{" - ATTR_PATH_VALUE@144..146 - ATTR_PATH@144..146 - NAME@144..146 - IDENT@144..146 "YY" - L_CURLY@146..147 "{" - ERROR@147..148 "'" - ERROR@148..149 "\0" - ERROR@149..150 "\0" - ERROR@150..151 "\0" - ERROR@151..152 "\0" - ERROR@152..153 "\0" - ERROR@153..154 "\0" - ERROR@154..155 "\0" - R_CURLY@155..156 "}" + ERROR@141..142 + ERROR@141..142 "\u{6}" + ERROR@142..143 + ERROR@142..143 "\u{6}" + ERROR@143..156 + ATTR_SET@143..156 + L_CURLY@143..144 "{" + ATTR_PATH_VALUE@144..146 + ATTR_PATH@144..146 + NAME@144..146 + IDENT@144..146 "YY" + ERROR@146..147 + L_CURLY@146..147 "{" + ERROR@147..148 + ERROR@147..148 "'" + ERROR@148..149 + ERROR@148..149 "\0" + ERROR@149..150 + ERROR@149..150 "\0" + ERROR@150..151 + ERROR@150..151 "\0" + ERROR@151..152 + ERROR@151..152 "\0" + ERROR@152..153 + ERROR@152..153 "\0" + ERROR@153..154 + ERROR@153..154 "\0" + ERROR@154..155 + ERROR@154..155 "\0" + R_CURLY@155..156 "}" R_CURLY@156..157 "}" - ERROR@157..158 "\u{1}" - ERROR@158..159 "\0" - ERROR@159..160 "|" - ERROR@160..161 "\0" - ERROR@161..162 "\0" - ERROR@162..163 "\0" - ERROR@163..164 "\0" - ERROR@164..165 "\0" + ERROR@157..158 + ERROR@157..158 "\u{1}" + ERROR@158..159 + ERROR@158..159 "\0" + ERROR@159..160 + ERROR@159..160 "|" + ERROR@160..161 + ERROR@160..161 "\0" + ERROR@161..162 + ERROR@161..162 "\0" + ERROR@162..163 + ERROR@162..163 "\0" + ERROR@163..164 + ERROR@163..164 "\0" + ERROR@164..165 + ERROR@164..165 "\0" LIST@165..169 L_BRACK@165..166 "[" REF@166..167 @@ -327,20 +432,28 @@ SOURCE_FILE@0..241 ATTR_SET@167..169 L_CURLY@167..168 "{" R_CURLY@168..169 "}" - R_CURLY@169..170 "}" - PATH_END@170..170 "" + ERROR@169..170 + R_CURLY@169..170 "}" + ERROR@170..170 + PATH_END@170..170 "" LAMBDA@170..173 PARAM@170..172 PAT@170..172 L_CURLY@170..171 "{" R_CURLY@171..172 "}" COLON@172..173 ":" - R_CURLY@173..174 "}" - PATH_END@174..174 "" - ERROR@174..175 "\0" - ERROR@175..176 "\0" - ERROR@176..177 "\0" - R_PAREN@177..178 ")" + ERROR@173..174 + R_CURLY@173..174 "}" + ERROR@174..174 + PATH_END@174..174 "" + ERROR@174..175 + ERROR@174..175 "\0" + ERROR@175..176 + ERROR@175..176 "\0" + ERROR@176..177 + ERROR@176..177 "\0" + ERROR@177..178 + R_PAREN@177..178 ")" LIST@178..182 L_BRACK@178..179 "[" REF@179..180 @@ -348,33 +461,47 @@ SOURCE_FILE@0..241 ATTR_SET@180..182 L_CURLY@180..181 "{" R_CURLY@181..182 "}" - R_CURLY@182..183 "}" + ERROR@182..183 + R_CURLY@182..183 "}" ATTR_SET@183..186 L_CURLY@183..184 "{" - L_CURLY@184..185 "{" + ERROR@184..185 + L_CURLY@184..185 "{" R_CURLY@185..186 "}" - R_CURLY@186..187 "}" + ERROR@186..187 + R_CURLY@186..187 "}" LAMBDA@187..190 PARAM@187..189 PAT@187..189 L_CURLY@187..188 "{" R_CURLY@188..189 "}" COLON@189..190 ":" - R_CURLY@190..191 "}" + ERROR@190..191 + R_CURLY@190..191 "}" REF@191..210 IDENT@191..210 "KKKKKKKKKKKKKKKKKKK" - ERROR@210..211 "%" - ERROR@211..212 "\0" - ERROR@212..213 "\0" - ERROR@213..214 "\0" - ERROR@214..215 "\u{14}" - ERROR@215..216 "$" + ERROR@210..211 + ERROR@210..211 "%" + ERROR@211..212 + ERROR@211..212 "\0" + ERROR@212..213 + ERROR@212..213 "\0" + ERROR@213..214 + ERROR@213..214 "\0" + ERROR@214..215 + ERROR@214..215 "\u{14}" + ERROR@215..216 + ERROR@215..216 "$" LIST@216..241 L_BRACK@216..217 "[" - PLUS@217..218 "+" - ERROR@218..219 "^" - ERROR@219..220 "'" - ERROR@220..221 "$" + ERROR@217..218 + PLUS@217..218 "+" + ERROR@218..219 + ERROR@218..219 "^" + ERROR@219..220 + ERROR@219..220 "'" + ERROR@220..221 + ERROR@220..221 "$" PATH_INTERPOLATION@221..241 PATH_START@221..221 "" PATH_FRAGMENT@221..222 "/" @@ -382,15 +509,21 @@ SOURCE_FILE@0..241 DOLLAR_L_CURLY@222..224 "${" REF@224..232 IDENT@224..232 "KKKKKKKK" - ERROR@232..233 "%" - ERROR@233..234 "$" - LIST@234..241 - L_BRACK@234..235 "[" - ERROR@235..236 "^" - ERROR@236..237 "'" - ERROR@237..238 "$" - PATH_INTERPOLATION@238..241 - PATH_START@238..238 "" - PATH_FRAGMENT@238..239 "/" - DYNAMIC@239..241 - DOLLAR_L_CURLY@239..241 "${" + ERROR@232..233 + ERROR@232..233 "%" + ERROR@233..234 + ERROR@233..234 "$" + ERROR@234..241 + LIST@234..241 + L_BRACK@234..235 "[" + ERROR@235..236 + ERROR@235..236 "^" + ERROR@236..237 + ERROR@236..237 "'" + ERROR@237..238 + ERROR@237..238 "$" + PATH_INTERPOLATION@238..241 + PATH_START@238..238 "" + PATH_FRAGMENT@238..239 "/" + DYNAMIC@239..241 + DOLLAR_L_CURLY@239..241 "${"