From 1a658d9cf75aede2eb14d55a254c4c7b4eeec514 Mon Sep 17 00:00:00 2001 From: boyned//Kampfkarren Date: Sat, 20 Jan 2024 13:56:19 -0800 Subject: [PATCH] Parser rewrite (#274) --- .github/workflows/test.yml | 68 +- .vscode/settings.json | 6 +- CHANGELOG.md | 21 + benches/date.rs | 14 +- benches/t.rs | 14 +- full-moon/Cargo.toml | 12 +- full-moon/fuzz/.gitignore | 4 + full-moon/fuzz/Cargo.toml | 36 + full-moon/fuzz/fuzz_targets/parse.rs | 9 + full-moon/fuzz/fuzz_targets/parse_parity.rs | 11 + full-moon/src/ast/mod.rs | 709 +-- full-moon/src/ast/parser_structs.rs | 372 ++ full-moon/src/ast/parser_util.rs | 436 +- full-moon/src/ast/parsers.rs | 5225 ++++++++++------- full-moon/src/ast/punctuated.rs | 27 +- full-moon/src/ast/types.rs | 51 +- full-moon/src/ast/versions.rs | 133 + full-moon/src/ast/visitors.rs | 54 +- full-moon/src/atom.rs | 462 -- full-moon/src/lib.rs | 50 +- full-moon/src/short_string.rs | 6 + .../src/tokenizer/interpolated_strings.rs | 101 + full-moon/src/tokenizer/lexer.rs | 1381 +++++ full-moon/src/tokenizer/mod.rs | 8 + .../{tokenizer.rs => tokenizer/structs.rs} | 1036 ++-- full-moon/src/tokenizer_luau.rs | 23 - full-moon/src/util.rs | 27 +- full-moon/src/visitors.rs | 8 +- .../cases/fail/parser/assignment-1/ast.snap | 71 + .../parser/assignment-1/ast_to_string.snap | 8 + .../cases/fail/parser/assignment-1/error.snap | 20 - .../parser/assignment-1/error_display.snap | 13 + .../fail/parser/assignment-1/errors.snap | 20 + .../cases/fail/parser/assignment-2/ast.snap | 82 + .../parser/assignment-2/ast_to_string.snap | 8 + .../cases/fail/parser/assignment-2/error.snap | 21 - .../parser/assignment-2/error_display.snap | 19 + .../fail/parser/assignment-2/errors.snap | 34 + .../error.snap => assignment-3/ast.snap} | 13 +- .../parser/assignment-3/ast_to_string.snap | 8 + .../cases/fail/parser/assignment-3/error.snap | 21 - .../parser/assignment-3/error_display.snap | 13 + .../fail/parser/assignment-3/errors.snap | 20 + .../tests/cases/fail/parser/bin-op-1/ast.snap | 81 + .../fail/parser/bin-op-1/ast_to_string.snap | 8 + .../cases/fail/parser/bin-op-1/error.snap | 20 - .../fail/parser/bin-op-1/error_display.snap | 13 + .../cases/fail/parser/bin-op-1/errors.snap | 20 + .../tests/cases/fail/parser/bin-op-2/ast.snap | 81 + .../fail/parser/bin-op-2/ast_to_string.snap | 8 + .../cases/fail/parser/bin-op-2/error.snap | 21 - .../fail/parser/bin-op-2/error_display.snap | 19 + .../cases/fail/parser/bin-op-2/errors.snap | 34 + .../tests/cases/fail/parser/call-1/ast.snap | 77 + .../fail/parser/call-1/ast_to_string.snap | 8 + .../tests/cases/fail/parser/call-1/error.snap | 20 - .../fail/parser/call-1/error_display.snap | 13 + .../cases/fail/parser/call-1/errors.snap | 20 + .../tests/cases/fail/parser/call-2/ast.snap | 94 + .../fail/parser/call-2/ast_to_string.snap | 8 + .../tests/cases/fail/parser/call-2/error.snap | 20 - .../fail/parser/call-2/error_display.snap | 13 + .../cases/fail/parser/call-2/errors.snap | 20 + .../tests/cases/fail/parser/call-3/ast.snap | 136 + .../fail/parser/call-3/ast_to_string.snap | 8 + .../fail/parser/call-3/error_display.snap | 13 + .../cases/fail/parser/call-3/errors.snap | 20 + .../tests/cases/fail/parser/call-4/ast.snap | 77 + .../fail/parser/call-4/ast_to_string.snap | 8 + .../tests/cases/fail/parser/call-4/error.snap | 21 - .../fail/parser/call-4/error_display.snap | 19 + .../cases/fail/parser/call-4/errors.snap | 34 + .../tests/cases/fail/parser/do-1/ast.snap | 133 + .../cases/fail/parser/do-1/ast_to_string.snap | 8 + .../tests/cases/fail/parser/do-1/error.snap | 20 - .../cases/fail/parser/do-1/error_display.snap | 13 + .../tests/cases/fail/parser/do-1/errors.snap | 26 + .../tests/cases/fail/parser/do-2/ast.snap | 68 + .../cases/fail/parser/do-2/ast_to_string.snap | 8 + .../tests/cases/fail/parser/do-2/error.snap | 21 - .../cases/fail/parser/do-2/error_display.snap | 19 + .../tests/cases/fail/parser/do-2/errors.snap | 41 + .../function-1/{error.snap => ast.snap} | 11 +- .../fail/parser/function-1/ast_to_string.snap | 8 + .../fail/parser/function-1/error_display.snap | 13 + .../cases/fail/parser/function-1/errors.snap | 19 + .../function-2/{error.snap => ast.snap} | 18 +- .../fail/parser/function-2/ast_to_string.snap | 8 + .../fail/parser/function-2/error_display.snap | 19 + .../cases/fail/parser/function-2/errors.snap | 34 + .../cases/fail/parser/function-3/ast.snap | 23 + .../fail/parser/function-3/ast_to_string.snap | 8 + .../cases/fail/parser/function-3/error.snap | 21 - .../fail/parser/function-3/error_display.snap | 25 + .../cases/fail/parser/function-3/errors.snap | 48 + .../cases/fail/parser/function-4/ast.snap | 120 + .../fail/parser/function-4/ast_to_string.snap | 8 + .../cases/fail/parser/function-4/error.snap | 20 - .../fail/parser/function-4/error_display.snap | 13 + .../cases/fail/parser/function-4/errors.snap | 19 + .../error.snap => function-5/ast.snap} | 13 +- .../fail/parser/function-5/ast_to_string.snap | 8 + .../cases/fail/parser/function-5/error.snap | 21 - .../fail/parser/function-5/error_display.snap | 31 + .../cases/fail/parser/function-5/errors.snap | 62 + .../cases/fail/parser/function-6/ast.snap | 120 + .../fail/parser/function-6/ast_to_string.snap | 8 + .../cases/fail/parser/function-6/error.snap | 20 - .../fail/parser/function-6/error_display.snap | 13 + .../cases/fail/parser/function-6/errors.snap | 26 + .../cases/fail/parser/function-7/ast.snap | 136 + .../fail/parser/function-7/ast_to_string.snap | 8 + .../cases/fail/parser/function-7/error.snap | 21 - .../fail/parser/function-7/error_display.snap | 31 + .../cases/fail/parser/function-7/errors.snap | 62 + .../error.snap => function-8/ast.snap} | 13 +- .../fail/parser/function-8/ast_to_string.snap | 8 + .../cases/fail/parser/function-8/error.snap | 21 - .../fail/parser/function-8/error_display.snap | 31 + .../cases/fail/parser/function-8/errors.snap | 62 + .../generic-for-1/{error.snap => ast.snap} | 11 +- .../parser/generic-for-1/ast_to_string.snap | 8 + .../parser/generic-for-1/error_display.snap | 13 + .../fail/parser/generic-for-1/errors.snap | 20 + .../cases/fail/parser/generic-for-2/ast.snap | 210 + .../parser/generic-for-2/ast_to_string.snap | 8 + .../parser/generic-for-2/error_display.snap | 13 + .../fail/parser/generic-for-2/errors.snap | 19 + .../cases/fail/parser/generic-for-3/ast.snap | 221 + .../parser/generic-for-3/ast_to_string.snap | 8 + .../parser/generic-for-3/error_display.snap | 13 + .../fail/parser/generic-for-3/errors.snap | 26 + .../cases/fail/parser/generic-for-4/ast.snap | 150 + .../parser/generic-for-4/ast_to_string.snap | 8 + .../fail/parser/generic-for-4/error.snap | 21 - .../parser/generic-for-4/error_display.snap | 31 + .../fail/parser/generic-for-4/errors.snap | 62 + .../tests/cases/fail/parser/if-1/ast.snap | 114 + .../cases/fail/parser/if-1/ast_to_string.snap | 8 + .../cases/fail/parser/if-1/error_display.snap | 13 + .../tests/cases/fail/parser/if-1/errors.snap | 19 + .../tests/cases/fail/parser/if-2/ast.snap | 216 + .../cases/fail/parser/if-2/ast_to_string.snap | 8 + .../tests/cases/fail/parser/if-2/error.snap | 20 - .../cases/fail/parser/if-2/error_display.snap | 13 + .../tests/cases/fail/parser/if-2/errors.snap | 19 + .../error.snap => if-3/ast.snap} | 13 +- .../cases/fail/parser/if-3/ast_to_string.snap | 8 + .../tests/cases/fail/parser/if-3/error.snap | 21 - .../cases/fail/parser/if-3/error_display.snap | 25 + .../tests/cases/fail/parser/if-3/errors.snap | 48 + .../tests/cases/fail/parser/if-4/ast.snap | 196 + .../cases/fail/parser/if-4/ast_to_string.snap | 8 + .../tests/cases/fail/parser/if-4/error.snap | 20 - .../cases/fail/parser/if-4/error_display.snap | 13 + .../tests/cases/fail/parser/if-4/errors.snap | 19 + .../tests/cases/fail/parser/if-5/ast.snap | 379 ++ .../cases/fail/parser/if-5/ast_to_string.snap | 8 + .../tests/cases/fail/parser/if-5/error.snap | 21 - .../cases/fail/parser/if-5/error_display.snap | 31 + .../tests/cases/fail/parser/if-5/errors.snap | 62 + .../tests/cases/fail/parser/if-6/ast.snap | 227 + .../cases/fail/parser/if-6/ast_to_string.snap | 8 + .../tests/cases/fail/parser/if-6/error.snap | 21 - .../cases/fail/parser/if-6/error_display.snap | 19 + .../tests/cases/fail/parser/if-6/errors.snap | 34 + .../tests/cases/fail/parser/if-7/ast.snap | 170 + .../cases/fail/parser/if-7/ast_to_string.snap | 8 + .../tests/cases/fail/parser/if-7/error.snap | 20 - .../cases/fail/parser/if-7/error_display.snap | 13 + .../tests/cases/fail/parser/if-7/errors.snap | 19 + .../parser/index-1/{error.snap => ast.snap} | 11 +- .../fail/parser/index-1/ast_to_string.snap | 8 + .../fail/parser/index-1/error_display.snap | 19 + .../cases/fail/parser/index-1/errors.snap | 39 + .../parser/index-2/{error.snap => ast.snap} | 11 +- .../fail/parser/index-2/ast_to_string.snap | 8 + .../fail/parser/index-2/error_display.snap | 19 + .../cases/fail/parser/index-2/errors.snap | 33 + .../fail/parser/index-3/ast.snap} | 13 +- .../fail/parser/index-3/ast_to_string.snap | 8 + .../cases/fail/parser/index-3/error.snap | 21 - .../fail/parser/index-3/error_display.snap | 25 + .../cases/fail/parser/index-3/errors.snap | 48 + .../tests/cases/fail/parser/index-4/ast.snap | 124 + .../fail/parser/index-4/ast_to_string.snap | 8 + .../cases/fail/parser/index-4/error.snap | 21 - .../fail/parser/index-4/error_display.snap | 19 + .../cases/fail/parser/index-4/errors.snap | 34 + .../tests/cases/fail/parser/index-5/ast.snap | 71 + .../fail/parser/index-5/ast_to_string.snap | 8 + .../cases/fail/parser/index-5/error.snap | 21 - .../fail/parser/index-5/error_display.snap | 19 + .../cases/fail/parser/index-5/errors.snap | 34 + .../cases/fail/parser/last-stmt-1/ast.snap | 291 + .../parser/last-stmt-1/ast_to_string.snap | 8 + .../parser/last-stmt-1/error_display.snap | 19 + .../cases/fail/parser/last-stmt-1/errors.snap | 41 + .../cases/fail/parser/last-stmt-1/source.lua | 4 + .../cases/fail/parser/last-stmt-1/tokens.snap | 237 + .../fail/parser/local-assignment-1/ast.snap | 82 + .../local-assignment-1/ast_to_string.snap | 8 + .../fail/parser/local-assignment-1/error.snap | 21 - .../local-assignment-1/error_display.snap | 13 + .../parser/local-assignment-1/errors.snap | 19 + .../fail/parser/local-assignment-2/ast.snap | 96 + .../local-assignment-2/ast_to_string.snap | 8 + .../fail/parser/local-assignment-2/error.snap | 20 - .../local-assignment-2/error_display.snap | 13 + .../parser/local-assignment-2/errors.snap | 20 + .../fail/parser/local-assignment-3/ast.snap | 123 + .../local-assignment-3/ast_to_string.snap | 8 + .../fail/parser/local-assignment-3/error.snap | 21 - .../local-assignment-3/error_display.snap | 13 + .../parser/local-assignment-3/errors.snap | 20 + .../{error.snap => ast.snap} | 18 +- .../local-assignment-4/ast_to_string.snap | 8 + .../local-assignment-4/error_display.snap | 19 + .../parser/local-assignment-4/errors.snap | 34 + .../fail/parser/local-assignment-5/ast.snap | 107 + .../local-assignment-5/ast_to_string.snap | 8 + .../fail/parser/local-assignment-5/error.snap | 21 - .../local-assignment-5/error_display.snap | 19 + .../parser/local-assignment-5/errors.snap | 34 + .../fail/parser/local-assignment-6/ast.snap | 218 + .../local-assignment-6/ast_to_string.snap | 8 + .../local-assignment-6/error_display.snap | 13 + .../parser/local-assignment-6/errors.snap | 20 + .../fail/parser/local-assignment-6/source.lua | 2 + .../parser/local-assignment-6/tokens.snap | 171 + .../local-function-1/{error.snap => ast.snap} | 11 +- .../local-function-1/ast_to_string.snap | 8 + .../local-function-1/error_display.snap | 13 + .../fail/parser/local-function-1/errors.snap | 19 + .../local-function-2/{error.snap => ast.snap} | 11 +- .../local-function-2/ast_to_string.snap | 8 + .../local-function-2/error_display.snap | 13 + .../fail/parser/local-function-2/errors.snap | 20 + .../fail/parser/local-function-3/ast.snap | 142 + .../local-function-3/ast_to_string.snap | 8 + .../fail/parser/local-function-3/error.snap | 20 - .../local-function-3/error_display.snap | 13 + .../fail/parser/local-function-3/errors.snap | 19 + .../fail/parser/local-function-4/ast.snap | 218 + .../local-function-4/ast_to_string.snap | 8 + .../fail/parser/local-function-4/error.snap | 20 - .../local-function-4/error_display.snap | 13 + .../fail/parser/local-function-4/errors.snap | 26 + .../fail/parser/local-function-5/ast.snap | 99 + .../local-function-5/ast_to_string.snap | 8 + .../fail/parser/local-function-5/error.snap | 21 - .../local-function-5/error_display.snap | 25 + .../fail/parser/local-function-5/errors.snap | 48 + .../fail/parser/local-function-6/ast.snap | 142 + .../local-function-6/ast_to_string.snap | 8 + .../fail/parser/local-function-6/error.snap | 21 - .../local-function-6/error_display.snap | 19 + .../fail/parser/local-function-6/errors.snap | 34 + .../fail/parser/local-function-7/ast.snap | 356 ++ .../local-function-7/ast_to_string.snap | 8 + .../local-function-7/error_display.snap | 13 + .../fail/parser/local-function-7/errors.snap | 20 + .../fail/parser/local-function-7/source.lua | 3 + .../fail/parser/local-function-7/tokens.snap | 281 + .../cases/fail/parser/method-call-1/ast.snap | 71 + .../parser/method-call-1/ast_to_string.snap | 8 + .../fail/parser/method-call-1/error.snap | 20 - .../parser/method-call-1/error_display.snap | 13 + .../fail/parser/method-call-1/errors.snap | 20 + .../cases/fail/parser/method-call-2/ast.snap | 139 + .../parser/method-call-2/ast_to_string.snap | 8 + .../fail/parser/method-call-2/error.snap | 20 - .../parser/method-call-2/error_display.snap | 13 + .../fail/parser/method-call-2/errors.snap | 20 + .../cases/fail/parser/method-call-3/ast.snap | 139 + .../parser/method-call-3/ast_to_string.snap | 8 + .../fail/parser/method-call-3/error.snap | 21 - .../parser/method-call-3/error_display.snap | 19 + .../fail/parser/method-call-3/errors.snap | 34 + .../numeric-for-1/{error.snap => ast.snap} | 11 +- .../parser/numeric-for-1/ast_to_string.snap | 8 + .../parser/numeric-for-1/error_display.snap | 13 + .../fail/parser/numeric-for-1/errors.snap | 19 + .../numeric-for-2/{error.snap => ast.snap} | 11 +- .../parser/numeric-for-2/ast_to_string.snap | 8 + .../parser/numeric-for-2/error_display.snap | 13 + .../fail/parser/numeric-for-2/errors.snap | 20 + .../numeric-for-3/{error.snap => ast.snap} | 11 +- .../parser/numeric-for-3/ast_to_string.snap | 8 + .../parser/numeric-for-3/error_display.snap | 13 + .../fail/parser/numeric-for-3/errors.snap | 19 + .../cases/fail/parser/numeric-for-4/ast.snap | 206 + .../parser/numeric-for-4/ast_to_string.snap | 8 + .../fail/parser/numeric-for-4/error.snap | 20 - .../parser/numeric-for-4/error_display.snap | 13 + .../fail/parser/numeric-for-4/errors.snap | 26 + .../cases/fail/parser/numeric-for-5/ast.snap | 68 + .../parser/numeric-for-5/ast_to_string.snap | 8 + .../fail/parser/numeric-for-5/error.snap | 21 - .../parser/numeric-for-5/error_display.snap | 25 + .../fail/parser/numeric-for-5/errors.snap | 48 + .../fail/parser/paren-expression-1/ast.snap | 54 + .../paren-expression-1/ast_to_string.snap | 8 + .../fail/parser/paren-expression-1/error.snap | 20 - .../paren-expression-1/error_display.snap | 13 + .../parser/paren-expression-1/errors.snap | 20 + .../fail/parser/paren-expression-2/ast.snap | 143 + .../paren-expression-2/ast_to_string.snap | 8 + .../fail/parser/paren-expression-2/error.snap | 21 - .../paren-expression-2/error_display.snap | 13 + .../parser/paren-expression-2/errors.snap | 20 + .../fail/parser/paren-expression-3/ast.snap | 143 + .../paren-expression-3/ast_to_string.snap | 8 + .../fail/parser/paren-expression-3/error.snap | 21 - .../paren-expression-3/error_display.snap | 19 + .../parser/paren-expression-3/errors.snap | 34 + .../fail/parser/paren-expression-4/ast.snap | 54 + .../paren-expression-4/ast_to_string.snap | 8 + .../fail/parser/paren-expression-4/error.snap | 21 - .../paren-expression-4/error_display.snap | 19 + .../parser/paren-expression-4/errors.snap | 34 + .../fail/parser/paren-expression-5/ast.snap | 54 + .../paren-expression-5/ast_to_string.snap | 8 + .../fail/parser/paren-expression-5/error.snap | 21 - .../paren-expression-5/error_display.snap | 19 + .../parser/paren-expression-5/errors.snap | 34 + .../cases/fail/parser/repeat-until-1/ast.snap | 79 + .../parser/repeat-until-1/ast_to_string.snap | 8 + .../fail/parser/repeat-until-1/error.snap | 20 - .../parser/repeat-until-1/error_display.snap | 13 + .../fail/parser/repeat-until-1/errors.snap | 19 + .../cases/fail/parser/repeat-until-2/ast.snap | 144 + .../parser/repeat-until-2/ast_to_string.snap | 8 + .../fail/parser/repeat-until-2/error.snap | 20 - .../parser/repeat-until-2/error_display.snap | 13 + .../fail/parser/repeat-until-2/errors.snap | 19 + .../cases/fail/parser/repeat-until-3/ast.snap | 155 + .../parser/repeat-until-3/ast_to_string.snap | 8 + .../fail/parser/repeat-until-3/error.snap | 20 - .../parser/repeat-until-3/error_display.snap | 13 + .../fail/parser/repeat-until-3/errors.snap | 20 + .../cases/fail/parser/repeat-until-4/ast.snap | 155 + .../parser/repeat-until-4/ast_to_string.snap | 8 + .../fail/parser/repeat-until-4/error.snap | 21 - .../parser/repeat-until-4/error_display.snap | 19 + .../fail/parser/repeat-until-4/errors.snap | 34 + .../tests/cases/fail/parser/table-1/ast.snap | 88 + .../fail/parser/table-1/ast_to_string.snap | 8 + .../cases/fail/parser/table-1/error.snap | 20 - .../fail/parser/table-1/error_display.snap | 13 + .../cases/fail/parser/table-1/errors.snap | 20 + .../tests/cases/fail/parser/table-2/ast.snap | 194 + .../fail/parser/table-2/ast_to_string.snap | 8 + .../cases/fail/parser/table-2/error.snap | 20 - .../fail/parser/table-2/error_display.snap | 13 + .../cases/fail/parser/table-2/errors.snap | 20 + .../tests/cases/fail/parser/table-3/ast.snap | 99 + .../fail/parser/table-3/ast_to_string.snap | 8 + .../cases/fail/parser/table-3/error.snap | 20 - .../fail/parser/table-3/error_display.snap | 13 + .../cases/fail/parser/table-3/errors.snap | 20 + .../tests/cases/fail/parser/table-4/ast.snap | 99 + .../fail/parser/table-4/ast_to_string.snap | 8 + .../cases/fail/parser/table-4/error.snap | 21 - .../fail/parser/table-4/error_display.snap | 19 + .../cases/fail/parser/table-4/errors.snap | 34 + .../tests/cases/fail/parser/table-5/ast.snap | 99 + .../fail/parser/table-5/ast_to_string.snap | 8 + .../cases/fail/parser/table-5/error.snap | 21 - .../fail/parser/table-5/error_display.snap | 19 + .../cases/fail/parser/table-5/errors.snap | 34 + .../tests/cases/fail/parser/table-6/ast.snap | 99 + .../fail/parser/table-6/ast_to_string.snap | 8 + .../cases/fail/parser/table-6/error.snap | 21 - .../fail/parser/table-6/error_display.snap | 19 + .../cases/fail/parser/table-6/errors.snap | 34 + .../tests/cases/fail/parser/table-7/ast.snap | 99 + .../fail/parser/table-7/ast_to_string.snap | 8 + .../cases/fail/parser/table-7/error.snap | 21 - .../fail/parser/table-7/error_display.snap | 19 + .../cases/fail/parser/table-7/errors.snap | 34 + .../tests/cases/fail/parser/table-8/ast.snap | 99 + .../fail/parser/table-8/ast_to_string.snap | 8 + .../cases/fail/parser/table-8/error.snap | 21 - .../fail/parser/table-8/error_display.snap | 19 + .../cases/fail/parser/table-8/errors.snap | 34 + .../tests/cases/fail/parser/table-9/ast.snap | 152 + .../fail/parser/table-9/ast_to_string.snap | 8 + .../fail/parser/table-9/error_display.snap | 19 + .../cases/fail/parser/table-9/errors.snap | 41 + .../cases/fail/parser/table-9/source.lua | 3 + .../cases/fail/parser/table-9/tokens.snap | 270 + .../tests/cases/fail/parser/un-op-1/ast.snap | 54 + .../fail/parser/un-op-1/ast_to_string.snap | 8 + .../cases/fail/parser/un-op-1/error.snap | 20 - .../fail/parser/un-op-1/error_display.snap | 13 + .../cases/fail/parser/un-op-1/errors.snap | 20 + .../tests/cases/fail/parser/un-op-2/ast.snap | 54 + .../fail/parser/un-op-2/ast_to_string.snap | 8 + .../cases/fail/parser/un-op-2/error.snap | 21 - .../fail/parser/un-op-2/error_display.snap | 19 + .../cases/fail/parser/un-op-2/errors.snap | 34 + .../parser/while-1/{error.snap => ast.snap} | 11 +- .../fail/parser/while-1/ast_to_string.snap | 8 + .../fail/parser/while-1/error_display.snap | 13 + .../cases/fail/parser/while-1/errors.snap | 20 + .../tests/cases/fail/parser/while-2/ast.snap | 68 + .../fail/parser/while-2/ast_to_string.snap | 8 + .../cases/fail/parser/while-2/error.snap | 21 - .../fail/parser/while-2/error_display.snap | 19 + .../cases/fail/parser/while-2/errors.snap | 34 + .../tests/cases/fail/parser/while-3/ast.snap | 186 + .../fail/parser/while-3/ast_to_string.snap | 8 + .../cases/fail/parser/while-3/error.snap | 20 - .../fail/parser/while-3/error_display.snap | 13 + .../cases/fail/parser/while-3/errors.snap | 26 + .../tests/cases/fail/parser/while-4/ast.snap | 219 + .../fail/parser/while-4/ast_to_string.snap | 8 + .../cases/fail/parser/while-4/error.snap | 21 - .../fail/parser/while-4/error_display.snap | 19 + .../cases/fail/parser/while-4/errors.snap | 34 + .../fail/tokenizer/bad-numbers-1/ast.snap | 98 + .../bad-numbers-1/ast_to_string.snap | 8 + .../bad-numbers-1/error_display.snap | 13 + .../fail/tokenizer/bad-numbers-1/errors.snap | 16 + .../fail/tokenizer/bad-numbers-1/source.lua | 1 + .../bad-numbers-1/tokens_result.snap | 81 + .../tokenizer/unclosed-comment-1/ast.snap | 35 + .../{error.snap => ast_to_string.snap} | 12 +- .../unclosed-comment-1/error_display.snap | 13 + .../tokenizer/unclosed-comment-1/errors.snap | 16 + .../unclosed-comment-1/tokens_result.snap | 38 + .../fail/tokenizer/unclosed-string-1/ast.snap | 124 + .../{error.snap => ast_to_string.snap} | 10 +- .../unclosed-string-1/error_display.snap | 13 + .../tokenizer/unclosed-string-1/errors.snap | 16 + .../unclosed-string-1/tokens_result.snap | 104 + .../fail/tokenizer/unclosed-string-2/ast.snap | 124 + .../{error.snap => ast_to_string.snap} | 10 +- .../unclosed-string-2/error_display.snap | 13 + .../tokenizer/unclosed-string-2/errors.snap | 16 + .../unclosed-string-2/tokens_result.snap | 104 + .../fail/tokenizer/unclosed-string-3/ast.snap | 122 + .../{error.snap => ast_to_string.snap} | 10 +- .../unclosed-string-3/error_display.snap | 15 + .../tokenizer/unclosed-string-3/errors.snap | 16 + .../unclosed-string-3/tokens_result.snap | 102 + .../fail/tokenizer/unclosed-string-4/ast.snap | 134 + .../unclosed-string-4/ast_to_string.snap | 8 + .../unclosed-string-4/error_display.snap | 21 + .../tokenizer/unclosed-string-4/errors.snap | 30 + .../tokenizer/unclosed-string-4/source.lua | 2 + .../unclosed-string-4/tokens_result.snap | 126 + .../tokenizer/unexpected-character/ast.snap | 107 + .../{error.snap => ast_to_string.snap} | 11 +- .../unexpected-character/error_display.snap | 19 + .../unexpected-character/errors.snap | 30 + .../unexpected-character/tokens_result.snap | 93 + .../tokenizer/wrong-place-shebang/ast.snap | 129 + .../{error.snap => ast_to_string.snap} | 10 +- .../wrong-place-shebang/error_display.snap | 61 + .../tokenizer/wrong-place-shebang/errors.snap | 128 + .../wrong-place-shebang/tokens_result.snap | 226 + .../tests/cases/pass/assignment-4/ast.snap | 180 + .../tests/cases/pass/assignment-4/source.lua | 2 + .../tests/cases/pass/assignment-4/tokens.snap | 149 + .../tests/cases/pass/assignment-5/ast.snap | 338 ++ .../tests/cases/pass/assignment-5/source.lua | 1 + .../tests/cases/pass/assignment-5/tokens.snap | 250 + .../cases/pass/body-with-spaces/ast.snap | 62 + .../cases/pass/body-with-spaces/source.lua | 3 + .../cases/pass/body-with-spaces/tokens.snap | 59 + .../cases/pass/multi-line-string-1/ast.snap | 3 - .../pass/multi-line-string-1/tokens.snap | 3 - .../cases/pass/multi-line-string-2/ast.snap | 4 +- .../pass/multi-line-string-2/tokens.snap | 4 +- .../cases/pass/multi-line-string-3/ast.snap | 3 - .../pass/multi-line-string-3/tokens.snap | 3 - .../cases/pass/multi-line-string-4/ast.snap | 3 - .../pass/multi-line-string-4/tokens.snap | 3 - .../cases/pass/multi-line-string-5/ast.snap | 3 - .../pass/multi-line-string-5/tokens.snap | 3 - .../cases/pass/multi-line-string-7/ast.snap | 4 +- .../pass/multi-line-string-7/tokens.snap | 3 +- .../cases/pass/multi-line-string-8/ast.snap | 4 +- .../pass/multi-line-string-8/tokens.snap | 3 +- full-moon/tests/cases/pass/numbers-1/ast.snap | 94 + .../tests/cases/pass/numbers-1/source.lua | 1 + .../tests/cases/pass/numbers-1/tokens.snap | 83 + full-moon/tests/cases/pass/shebang/ast.snap | 17 +- .../tests/cases/pass/shebang/tokens.snap | 17 +- .../pass/single-line-comment-6/tokens.snap | 8 +- .../pass/single-line-comment-7/tokens.snap | 8 +- full-moon/tests/comments_around_functions.rs | 3 +- full-moon/tests/fail_cases.rs | 180 +- .../parser/goto-1/{error.snap => ast.snap} | 11 +- .../fail/parser/goto-1/ast_to_string.snap | 8 + .../fail/parser/goto-1/error_display.snap | 13 + .../fail/parser/goto-1/errors.snap | 26 + .../fail/parser/goto-as-identifier/ast.snap | 23 + .../goto-as-identifier/ast_to_string.snap | 8 + .../fail/parser/goto-as-identifier/error.snap | 20 - .../goto-as-identifier/error_display.snap | 31 + .../parser/goto-as-identifier/errors.snap | 68 + .../lua52_cases/fail/parser/label-1/ast.snap | 70 + .../fail/parser/label-1/ast_to_string.snap | 8 + .../fail/parser/label-1/error_display.snap | 13 + .../fail/parser/label-1/errors.snap | 19 + .../parser/label-2/{error.snap => ast.snap} | 22 +- .../fail/parser/label-2/ast_to_string.snap | 8 + .../fail/parser/label-2/error_display.snap | 19 + .../fail/parser/label-2/errors.snap | 40 + .../tests/lua52_cases/pass/numbers/ast.snap | 379 +- .../tests/lua52_cases/pass/numbers/source.lua | 7 +- .../lua52_cases/pass/numbers/tokens.snap | 263 +- .../parser/double-greater-than-binop/ast.snap | 156 + .../ast_to_string.snap | 8 + .../error_display.snap | 19 + .../double-greater-than-binop/errors.snap | 34 + .../pass/binary-operators/tokens.snap | 15 +- .../fail/parser/unclosed-attribute-1/ast.snap | 127 + .../unclosed-attribute-1/ast_to_string.snap | 7 + .../unclosed-attribute-1/error_display.snap | 12 + .../parser/unclosed-attribute-1/errors.snap | 19 + .../fail/parser/unclosed-attribute-2/ast.snap | 179 + .../unclosed-attribute-2/ast_to_string.snap | 7 + .../unclosed-attribute-2/error_display.snap | 12 + .../parser/unclosed-attribute-2/errors.snap | 20 + full-moon/tests/pass_cases.rs | 45 +- .../function_return_type_thin_arrow/ast.snap | 255 + .../ast_to_string.snap | 6 + .../error_display.snap | 11 + .../errors.snap | 19 + .../source.lua | 3 + .../tokens.snap | 192 + .../generic_declare_no_parameters/ast.snap | 258 + .../ast_to_string.snap | 6 + .../error_display.snap | 11 + .../generic_declare_no_parameters/errors.snap | 19 + .../generic_declare_packs_last/ast.snap | 243 + .../ast_to_string.snap | 6 + .../error_display.snap | 11 + .../generic_declare_packs_last/errors.snap | 19 + .../generic_default_not_a_type_pack/ast.snap | 246 + .../ast_to_string.snap | 6 + .../error_display.snap | 11 + .../errors.snap | 26 + .../source.lua | 1 + .../tokens.snap | 191 + .../generic_must_declare_default/ast.snap | 348 ++ .../ast_to_string.snap | 6 + .../error_display.snap | 11 + .../generic_must_declare_default/errors.snap | 19 + .../fail/parser/generic_nil/ast.snap | 118 + .../parser/generic_nil/ast_to_string.snap | 6 + .../parser/generic_nil/error_display.snap | 23 + .../fail/parser/generic_nil/errors.snap | 47 + .../fail/parser/generic_string/ast.snap | 119 + .../parser/generic_string/ast_to_string.snap | 6 + .../parser/generic_string/error_display.snap | 23 + .../fail/parser/generic_string/errors.snap | 47 + .../parser/named_function_arg_types/ast.snap | 21 + .../ast_to_string.snap | 6 + .../error_display.snap | 11 + .../named_function_arg_types/errors.snap | 18 + .../roblox_cases/fail/parser/nil_dot/ast.snap | 118 + .../fail/parser/nil_dot/ast_to_string.snap | 6 + .../fail/parser/nil_dot/error_display.snap | 35 + .../fail/parser/nil_dot/errors.snap | 75 + .../fail/parser/param_tuple_types/ast.snap | 148 + .../param_tuple_types/ast_to_string.snap | 6 + .../param_tuple_types/error_display.snap | 17 + .../fail/parser/param_tuple_types/errors.snap | 33 + .../fail/parser/param_variadic_types/ast.snap | 136 + .../param_variadic_types/ast_to_string.snap | 6 + .../param_variadic_types/error_display.snap | 35 + .../parser/param_variadic_types/errors.snap | 75 + .../parentheses_variadic_types/ast.snap | 21 + .../ast_to_string.snap | 6 + .../error_display.snap | 11 + .../parentheses_variadic_types/errors.snap | 18 + .../ast.snap | 225 + .../ast_to_string.snap | 8 + .../error_display.snap | 13 + .../errors.snap | 21 + .../source.lua | 1 + .../tokens.snap | 195 + .../ast.snap | 101 + .../ast_to_string.snap | 8 + .../error.snap | 21 - .../error_display.snap | 25 + .../errors.snap | 50 + .../parser/type_table_no_right_brace/ast.snap | 412 ++ .../ast_to_string.snap | 6 + .../error_display.snap | 11 + .../type_table_no_right_brace/errors.snap | 19 + .../type_table_no_right_brace/source.lua | 3 + .../type_table_no_right_brace/tokens.snap | 312 + .../ast.snap | 218 + .../ast_to_string.snap | 8 + .../error_display.snap | 31 + .../errors.snap | 55 + .../source.lua | 3 + .../tokens_result.snap | 212 + .../unfinished-string-interpolation/ast.snap | 126 + .../{error.snap => ast_to_string.snap} | 10 +- .../error_display.snap | 13 + .../errors.snap | 16 + .../tokens_result.snap | 104 + .../pass/generic_functions/ast.snap | 480 +- .../pass/no_roblox_syntax/ast.snap | 128 +- .../tests/roblox_cases/pass/types/ast.snap | 326 +- .../pass/types_chained_optionals/ast.snap | 656 +++ .../pass/types_chained_optionals/source.lua | 5 + .../pass/types_chained_optionals/tokens.snap | 521 ++ .../pass/types_compound_precedence/ast.snap | 663 +++ .../pass/types_compound_precedence/source.lua | 7 + .../types_compound_precedence/tokens.snap | 543 ++ .../pass/types_generic_declaration/ast.snap | 35 +- .../pass/types_generic_no_parameters/ast.snap | 175 +- .../types_generic_no_parameters/source.lua | 3 +- .../types_generic_no_parameters/tokens.snap | 135 +- .../pass/types_indexable/ast.snap | 35 +- .../roblox_cases/pass/types_packs/ast.snap | 101 +- .../pass/types_parentheses/ast.snap | 676 ++- .../roblox_cases/pass/types_variadic/ast.snap | 765 ++- .../pass/types_variadic/source.lua | 3 + .../pass/types_variadic/tokens.snap | 269 +- .../pass/z-escape-string/ast.snap | 106 +- .../pass/z-escape-string/source.lua | 5 +- .../pass/z-escape-string/tokens.snap | 80 +- 631 files changed, 34572 insertions(+), 7603 deletions(-) create mode 100644 full-moon/fuzz/.gitignore create mode 100644 full-moon/fuzz/Cargo.toml create mode 100644 full-moon/fuzz/fuzz_targets/parse.rs create mode 100644 full-moon/fuzz/fuzz_targets/parse_parity.rs create mode 100644 full-moon/src/ast/parser_structs.rs create mode 100644 full-moon/src/ast/versions.rs delete mode 100644 full-moon/src/atom.rs create mode 100644 full-moon/src/tokenizer/interpolated_strings.rs create mode 100644 full-moon/src/tokenizer/lexer.rs create mode 100644 full-moon/src/tokenizer/mod.rs rename full-moon/src/{tokenizer.rs => tokenizer/structs.rs} (52%) create mode 100644 full-moon/tests/cases/fail/parser/assignment-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/assignment-1/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/assignment-1/error.snap create mode 100644 full-moon/tests/cases/fail/parser/assignment-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/assignment-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/assignment-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/assignment-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/assignment-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/assignment-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/assignment-2/errors.snap rename full-moon/tests/cases/fail/parser/{if-1/error.snap => assignment-3/ast.snap} (57%) create mode 100644 full-moon/tests/cases/fail/parser/assignment-3/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/assignment-3/error.snap create mode 100644 full-moon/tests/cases/fail/parser/assignment-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/assignment-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/bin-op-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/bin-op-1/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/bin-op-1/error.snap create mode 100644 full-moon/tests/cases/fail/parser/bin-op-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/bin-op-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/bin-op-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/bin-op-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/bin-op-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/bin-op-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/bin-op-2/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/call-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/call-1/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/call-1/error.snap create mode 100644 full-moon/tests/cases/fail/parser/call-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/call-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/call-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/call-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/call-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/call-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/call-2/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/call-3/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/call-3/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/call-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/call-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/call-4/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/call-4/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/call-4/error.snap create mode 100644 full-moon/tests/cases/fail/parser/call-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/call-4/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/do-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/do-1/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/do-1/error.snap create mode 100644 full-moon/tests/cases/fail/parser/do-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/do-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/do-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/do-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/do-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/do-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/do-2/errors.snap rename full-moon/tests/cases/fail/parser/function-1/{error.snap => ast.snap} (71%) create mode 100644 full-moon/tests/cases/fail/parser/function-1/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/function-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/function-1/errors.snap rename full-moon/tests/cases/fail/parser/function-2/{error.snap => ast.snap} (58%) create mode 100644 full-moon/tests/cases/fail/parser/function-2/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/function-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/function-2/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/function-3/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/function-3/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/function-3/error.snap create mode 100644 full-moon/tests/cases/fail/parser/function-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/function-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/function-4/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/function-4/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/function-4/error.snap create mode 100644 full-moon/tests/cases/fail/parser/function-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/function-4/errors.snap rename full-moon/tests/cases/fail/parser/{generic-for-3/error.snap => function-5/ast.snap} (57%) create mode 100644 full-moon/tests/cases/fail/parser/function-5/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/function-5/error.snap create mode 100644 full-moon/tests/cases/fail/parser/function-5/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/function-5/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/function-6/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/function-6/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/function-6/error.snap create mode 100644 full-moon/tests/cases/fail/parser/function-6/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/function-6/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/function-7/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/function-7/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/function-7/error.snap create mode 100644 full-moon/tests/cases/fail/parser/function-7/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/function-7/errors.snap rename full-moon/tests/cases/fail/parser/{call-3/error.snap => function-8/ast.snap} (57%) create mode 100644 full-moon/tests/cases/fail/parser/function-8/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/function-8/error.snap create mode 100644 full-moon/tests/cases/fail/parser/function-8/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/function-8/errors.snap rename full-moon/tests/cases/fail/parser/generic-for-1/{error.snap => ast.snap} (72%) create mode 100644 full-moon/tests/cases/fail/parser/generic-for-1/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-2/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-2/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-3/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-3/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-4/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-4/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/generic-for-4/error.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/generic-for-4/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/if-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/if-1/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/if-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/if-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/if-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/if-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/if-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/if-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/if-2/errors.snap rename full-moon/tests/cases/fail/parser/{generic-for-2/error.snap => if-3/ast.snap} (58%) create mode 100644 full-moon/tests/cases/fail/parser/if-3/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/if-3/error.snap create mode 100644 full-moon/tests/cases/fail/parser/if-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/if-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/if-4/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/if-4/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/if-4/error.snap create mode 100644 full-moon/tests/cases/fail/parser/if-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/if-4/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/if-5/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/if-5/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/if-5/error.snap create mode 100644 full-moon/tests/cases/fail/parser/if-5/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/if-5/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/if-6/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/if-6/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/if-6/error.snap create mode 100644 full-moon/tests/cases/fail/parser/if-6/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/if-6/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/if-7/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/if-7/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/if-7/error.snap create mode 100644 full-moon/tests/cases/fail/parser/if-7/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/if-7/errors.snap rename full-moon/tests/cases/fail/parser/index-1/{error.snap => ast.snap} (71%) create mode 100644 full-moon/tests/cases/fail/parser/index-1/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/index-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/index-1/errors.snap rename full-moon/tests/cases/fail/parser/index-2/{error.snap => ast.snap} (71%) create mode 100644 full-moon/tests/cases/fail/parser/index-2/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/index-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/index-2/errors.snap rename full-moon/tests/{lua52_cases/fail/parser/label-1/error.snap => cases/fail/parser/index-3/ast.snap} (57%) create mode 100644 full-moon/tests/cases/fail/parser/index-3/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/index-3/error.snap create mode 100644 full-moon/tests/cases/fail/parser/index-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/index-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/index-4/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/index-4/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/index-4/error.snap create mode 100644 full-moon/tests/cases/fail/parser/index-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/index-4/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/index-5/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/index-5/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/index-5/error.snap create mode 100644 full-moon/tests/cases/fail/parser/index-5/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/index-5/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/last-stmt-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/last-stmt-1/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/last-stmt-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/last-stmt-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/last-stmt-1/source.lua create mode 100644 full-moon/tests/cases/fail/parser/last-stmt-1/tokens.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-1/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/local-assignment-1/error.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/local-assignment-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-2/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-3/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-3/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/local-assignment-3/error.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-3/errors.snap rename full-moon/tests/cases/fail/parser/local-assignment-4/{error.snap => ast.snap} (59%) create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-4/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-4/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-5/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-5/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/local-assignment-5/error.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-5/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-5/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-6/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-6/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-6/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-6/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-6/source.lua create mode 100644 full-moon/tests/cases/fail/parser/local-assignment-6/tokens.snap rename full-moon/tests/cases/fail/parser/local-function-1/{error.snap => ast.snap} (72%) create mode 100644 full-moon/tests/cases/fail/parser/local-function-1/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-1/errors.snap rename full-moon/tests/cases/fail/parser/local-function-2/{error.snap => ast.snap} (72%) create mode 100644 full-moon/tests/cases/fail/parser/local-function-2/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-2/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-3/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-3/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/local-function-3/error.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-4/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-4/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/local-function-4/error.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-4/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-5/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-5/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/local-function-5/error.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-5/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-5/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-6/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-6/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/local-function-6/error.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-6/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-6/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-7/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-7/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-7/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-7/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/local-function-7/source.lua create mode 100644 full-moon/tests/cases/fail/parser/local-function-7/tokens.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-1/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/method-call-1/error.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/method-call-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-2/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-3/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-3/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/method-call-3/error.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/method-call-3/errors.snap rename full-moon/tests/cases/fail/parser/numeric-for-1/{error.snap => ast.snap} (72%) create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-1/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-1/errors.snap rename full-moon/tests/cases/fail/parser/numeric-for-2/{error.snap => ast.snap} (72%) create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-2/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-2/errors.snap rename full-moon/tests/cases/fail/parser/numeric-for-3/{error.snap => ast.snap} (72%) create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-3/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-4/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-4/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/numeric-for-4/error.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-4/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-5/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-5/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/numeric-for-5/error.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-5/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/numeric-for-5/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-1/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/paren-expression-1/error.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/paren-expression-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-2/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-3/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-3/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/paren-expression-3/error.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-4/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-4/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/paren-expression-4/error.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-4/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-5/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-5/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/paren-expression-5/error.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-5/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/paren-expression-5/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-1/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/repeat-until-1/error.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/repeat-until-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-2/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-3/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-3/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/repeat-until-3/error.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-4/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-4/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/repeat-until-4/error.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/repeat-until-4/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/table-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/table-1/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/table-1/error.snap create mode 100644 full-moon/tests/cases/fail/parser/table-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/table-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/table-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/table-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/table-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/table-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/table-2/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/table-3/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/table-3/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/table-3/error.snap create mode 100644 full-moon/tests/cases/fail/parser/table-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/table-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/table-4/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/table-4/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/table-4/error.snap create mode 100644 full-moon/tests/cases/fail/parser/table-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/table-4/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/table-5/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/table-5/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/table-5/error.snap create mode 100644 full-moon/tests/cases/fail/parser/table-5/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/table-5/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/table-6/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/table-6/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/table-6/error.snap create mode 100644 full-moon/tests/cases/fail/parser/table-6/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/table-6/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/table-7/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/table-7/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/table-7/error.snap create mode 100644 full-moon/tests/cases/fail/parser/table-7/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/table-7/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/table-8/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/table-8/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/table-8/error.snap create mode 100644 full-moon/tests/cases/fail/parser/table-8/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/table-8/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/table-9/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/table-9/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/table-9/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/table-9/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/table-9/source.lua create mode 100644 full-moon/tests/cases/fail/parser/table-9/tokens.snap create mode 100644 full-moon/tests/cases/fail/parser/un-op-1/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/un-op-1/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/un-op-1/error.snap create mode 100644 full-moon/tests/cases/fail/parser/un-op-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/un-op-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/un-op-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/un-op-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/un-op-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/un-op-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/un-op-2/errors.snap rename full-moon/tests/cases/fail/parser/while-1/{error.snap => ast.snap} (71%) create mode 100644 full-moon/tests/cases/fail/parser/while-1/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/parser/while-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/while-1/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/while-2/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/while-2/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/while-2/error.snap create mode 100644 full-moon/tests/cases/fail/parser/while-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/while-2/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/while-3/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/while-3/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/while-3/error.snap create mode 100644 full-moon/tests/cases/fail/parser/while-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/while-3/errors.snap create mode 100644 full-moon/tests/cases/fail/parser/while-4/ast.snap create mode 100644 full-moon/tests/cases/fail/parser/while-4/ast_to_string.snap delete mode 100644 full-moon/tests/cases/fail/parser/while-4/error.snap create mode 100644 full-moon/tests/cases/fail/parser/while-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/parser/while-4/errors.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/bad-numbers-1/ast.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/bad-numbers-1/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/bad-numbers-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/bad-numbers-1/errors.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/bad-numbers-1/source.lua create mode 100644 full-moon/tests/cases/fail/tokenizer/bad-numbers-1/tokens_result.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/ast.snap rename full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/{error.snap => ast_to_string.snap} (55%) create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/errors.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/tokens_result.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-1/ast.snap rename full-moon/tests/cases/fail/tokenizer/unclosed-string-1/{error.snap => ast_to_string.snap} (56%) create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-1/error_display.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-1/errors.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-1/tokens_result.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-2/ast.snap rename full-moon/tests/cases/fail/tokenizer/unclosed-string-2/{error.snap => ast_to_string.snap} (56%) create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-2/error_display.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-2/errors.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-2/tokens_result.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-3/ast.snap rename full-moon/tests/cases/fail/tokenizer/unclosed-string-3/{error.snap => ast_to_string.snap} (56%) create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-3/error_display.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-3/errors.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-3/tokens_result.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-4/ast.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-4/ast_to_string.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-4/error_display.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-4/errors.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-4/source.lua create mode 100644 full-moon/tests/cases/fail/tokenizer/unclosed-string-4/tokens_result.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unexpected-character/ast.snap rename full-moon/tests/cases/fail/tokenizer/unexpected-character/{error.snap => ast_to_string.snap} (54%) create mode 100644 full-moon/tests/cases/fail/tokenizer/unexpected-character/error_display.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unexpected-character/errors.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/unexpected-character/tokens_result.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/ast.snap rename full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/{error.snap => ast_to_string.snap} (56%) create mode 100644 full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/error_display.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/errors.snap create mode 100644 full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/tokens_result.snap create mode 100644 full-moon/tests/cases/pass/assignment-4/ast.snap create mode 100644 full-moon/tests/cases/pass/assignment-4/source.lua create mode 100644 full-moon/tests/cases/pass/assignment-4/tokens.snap create mode 100644 full-moon/tests/cases/pass/assignment-5/ast.snap create mode 100644 full-moon/tests/cases/pass/assignment-5/source.lua create mode 100644 full-moon/tests/cases/pass/assignment-5/tokens.snap create mode 100644 full-moon/tests/cases/pass/body-with-spaces/ast.snap create mode 100644 full-moon/tests/cases/pass/body-with-spaces/source.lua create mode 100644 full-moon/tests/cases/pass/body-with-spaces/tokens.snap create mode 100644 full-moon/tests/cases/pass/numbers-1/ast.snap create mode 100644 full-moon/tests/cases/pass/numbers-1/source.lua create mode 100644 full-moon/tests/cases/pass/numbers-1/tokens.snap rename full-moon/tests/lua52_cases/fail/parser/goto-1/{error.snap => ast.snap} (72%) create mode 100644 full-moon/tests/lua52_cases/fail/parser/goto-1/ast_to_string.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/goto-1/error_display.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/goto-1/errors.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/ast.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/ast_to_string.snap delete mode 100644 full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/error.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/error_display.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/errors.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/label-1/ast.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/label-1/ast_to_string.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/label-1/error_display.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/label-1/errors.snap rename full-moon/tests/lua52_cases/fail/parser/label-2/{error.snap => ast.snap} (50%) create mode 100644 full-moon/tests/lua52_cases/fail/parser/label-2/ast_to_string.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/label-2/error_display.snap create mode 100644 full-moon/tests/lua52_cases/fail/parser/label-2/errors.snap create mode 100644 full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/ast.snap create mode 100644 full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/ast_to_string.snap create mode 100644 full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/error_display.snap create mode 100644 full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/errors.snap create mode 100644 full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast.snap create mode 100644 full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast_to_string.snap create mode 100644 full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/error_display.snap create mode 100644 full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/errors.snap create mode 100644 full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast.snap create mode 100644 full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast_to_string.snap create mode 100644 full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/error_display.snap create mode 100644 full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/source.lua create mode 100644 full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/tokens.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/source.lua create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/tokens.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_nil/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_nil/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_nil/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_nil/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_string/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_string/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_string/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/generic_string/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/nil_dot/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/nil_dot/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/nil_dot/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/nil_dot/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/param_tuple_types/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/param_tuple_types/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/param_tuple_types/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/param_tuple_types/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/param_variadic_types/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/param_variadic_types/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/param_variadic_types/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/param_variadic_types/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/source.lua create mode 100644 full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/tokens.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/ast_to_string.snap delete mode 100644 full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/error.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/source.lua create mode 100644 full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/tokens.snap create mode 100644 full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/ast.snap create mode 100644 full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/ast_to_string.snap create mode 100644 full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/source.lua create mode 100644 full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/tokens_result.snap create mode 100644 full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/ast.snap rename full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/{error.snap => ast_to_string.snap} (55%) create mode 100644 full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/error_display.snap create mode 100644 full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/errors.snap create mode 100644 full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/tokens_result.snap create mode 100644 full-moon/tests/roblox_cases/pass/types_chained_optionals/ast.snap create mode 100644 full-moon/tests/roblox_cases/pass/types_chained_optionals/source.lua create mode 100644 full-moon/tests/roblox_cases/pass/types_chained_optionals/tokens.snap create mode 100644 full-moon/tests/roblox_cases/pass/types_compound_precedence/ast.snap create mode 100644 full-moon/tests/roblox_cases/pass/types_compound_precedence/source.lua create mode 100644 full-moon/tests/roblox_cases/pass/types_compound_precedence/tokens.snap diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6683c6d1..fce4da5a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,43 +2,43 @@ name: Test full-moon on: push: branches: - - main + - main pull_request: branches: - - main + - main jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Test (default features) - run: | - cd full-moon - cargo test - - name: Test (roblox feature) - run: | - cd full-moon - cargo test --features roblox - - name: Test (Lua 5.2 feature) - run: | - cd full-moon - cargo test --features lua52 - - name: Test (Lua 5.3 feature) - run: | - cd full-moon - cargo test --features lua53 - - name: Test (Lua 5.4 feature) - run: | - cd full-moon - cargo test --features lua54 - - name: Test (all features) - run: | - cd full-moon - cargo test --features roblox,lua52,lua53,lua54 - - name: Test (no default features) - run: | - cd full-moon - cargo test --no-default-features --features serde - - name: Rustfmt - run: | - cargo fmt -- --check + - uses: actions/checkout@v3 + - name: Test (default features) + run: | + cd full-moon + cargo test + - name: Test (Luau feature) + run: | + cd full-moon + cargo test --features luau + - name: Test (Lua 5.2 feature) + run: | + cd full-moon + cargo test --features lua52 + - name: Test (Lua 5.3 feature) + run: | + cd full-moon + cargo test --features lua53 + - name: Test (Lua 5.4 feature) + run: | + cd full-moon + cargo test --features lua54 + - name: Test (all features) + run: | + cd full-moon + cargo test --features luau,lua52,lua53,lua54 + - name: Test (no default features) + run: | + cd full-moon + cargo test --no-default-features --features serde + - name: Rustfmt + run: | + cargo fmt -- --check diff --git a/.vscode/settings.json b/.vscode/settings.json index ca6121cc..d207103e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,3 @@ { - "rust-analyzer.cargo.features": [ - "roblox" - ], -} \ No newline at end of file + "rust-analyzer.cargo.features": ["luau", "lua52", "lua53", "lua54"] +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 87c04a9d..dc9a745a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Added +- **full-moon now has the ability to return multiple errors.** Added `parse_fallible`, which will return a struct containing the best possible AST, and a vector of errors. Read the documentation for guarantees on the partial AST. +- The Lua version used to parse is no longer strictly based on features set, and can now be configured precisely using `LuaVersion`. `LuaVersion` is a bitfield that can attempt to parse multiple versions of Lua at once, or be used to pin down a specific version. `parse` will use the most completely available set possible (`LuaVersion::new()`), but `parse_fallible` accepts a `LuaVersion`. - Added support for parsing Luau's floor division assignment `//=` +- Added `TokenizerErrorType::InvalidNumber` when a number fails to parse. + +### Changed +- **[BREAKING CHANGE]** `parse` now returns a vector of errors. +- **[BREAKING CHANGE]** `TokenType::StringLiteral::multi_line` has been replaced with `TokenType::StringLiteral::multi_line_depth`. It serves the same purpose except instead of being an `Option`, it is now a standard `usize`. It is advised to simply check `quote_type == StringLiteralQuoteType::Brackets` to get the previous behavior. +- **[BREAKING CHANGE]** Flattened `AstError` into just what used to be `AstError::UnexpectedToken`. +- **[BREAKING CHANGE]** `Symbol::PlusEqual` and friends are now only available when using Luau. +- Shebangs provide their trailing trivia more accurately to the rest of full-moon. +- Attempting to display `StringLiteralQuoteType::Brackets` now returns an error rather than being marked as unreachable. +- Significantly optimized the entire codebase, helping both time to parse and wasting less stack, especially in debug mode. +- `Punctuated` now implements `Default` for all `T`, rather than if `T: Default`. + +### Removed +- Removed `UnOp::precedence`, as unary operators do not traditionally use precedence in the same way binary operators do. +- Removed `TokenizerErrorType::UnexpectedShebang`. +- Removed `stacker` feature flag, as rewrites to the parser should make it unnecessary. + +### Fixed +- Fixed comments with Unicode characters having positions that report their `character` as bytes. ## [0.19.0] - 2023-11-10 ### Added diff --git a/benches/date.rs b/benches/date.rs index 5ef9f4da..18f05a68 100644 --- a/benches/date.rs +++ b/benches/date.rs @@ -1,19 +1,11 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use criterion::{criterion_group, criterion_main, Criterion}; use full_moon::node::Node; const DATE_SOURCE: &str = include_str!("./date.lua"); -fn tokenize(criterion: &mut Criterion) { - criterion.bench_function("tokenize date", |b| { - b.iter(|| full_moon::tokenizer::tokens(black_box(DATE_SOURCE))) - }); -} - fn parse(criterion: &mut Criterion) { - let tokens = full_moon::tokenizer::tokens(DATE_SOURCE).unwrap(); - criterion.bench_function("get ast from parsed date", move |b| { - b.iter(|| full_moon::ast::Ast::from_tokens(black_box(tokens.clone()))) + b.iter(|| full_moon::parse(DATE_SOURCE)) }); } @@ -28,7 +20,7 @@ fn range(criterion: &mut Criterion) { criterion_group! { name = benches; config = Criterion::default().sample_size(20); - targets = tokenize, parse, range + targets = parse, range } criterion_main!(benches); diff --git a/benches/t.rs b/benches/t.rs index cbc7d300..e7d8748b 100644 --- a/benches/t.rs +++ b/benches/t.rs @@ -1,19 +1,11 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use criterion::{criterion_group, criterion_main, Criterion}; use full_moon::node::Node; const T_SOURCE: &str = include_str!("./t.lua"); -fn tokenize(criterion: &mut Criterion) { - criterion.bench_function("tokenize t", |b| { - b.iter(|| full_moon::tokenizer::tokens(black_box(T_SOURCE))) - }); -} - fn parse(criterion: &mut Criterion) { - let tokens = full_moon::tokenizer::tokens(T_SOURCE).unwrap(); - criterion.bench_function("get ast from parsed t", move |b| { - b.iter(|| full_moon::ast::Ast::from_tokens(black_box(tokens.clone()))) + b.iter(|| full_moon::parse(T_SOURCE)) }); } @@ -28,7 +20,7 @@ fn range(criterion: &mut Criterion) { criterion_group! { name = benches; config = Criterion::default().sample_size(20); - targets = tokenize, parse, range + targets = parse, range } criterion_main!(benches); diff --git a/full-moon/Cargo.toml b/full-moon/Cargo.toml index d349bdd1..14b58194 100644 --- a/full-moon/Cargo.toml +++ b/full-moon/Cargo.toml @@ -11,13 +11,14 @@ keywords = ["lua", "parser", "lua51", "lua52", "luau"] edition = "2021" [package.metadata.docs.rs] -# Build Locally: RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --features roblox,lua52,lua53,lua54 --no-deps --open -features = ["roblox", "lua52", "lua53", "lua54"] +# Build Locally: RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --features luau,lua52,lua53,lua54 --no-deps --open +features = ["luau", "lua52", "lua53", "lua54"] rustdoc-args = ["--cfg", "doc_cfg"] [features] default = ["serde"] -roblox = [] +luau = ["roblox"] +roblox = ["luau"] # backwards compatibility lua52 = [] lua53 = ["lua52"] lua54 = ["lua53"] @@ -28,16 +29,17 @@ bytecount = "0.6" cfg-if = "1.0" derive_more = "0.99" full_moon_derive = { path = "../full-moon-derive", version = "=0.11.0" } -logos = "0.12.1" paste = "1.0" serde = { version = "1.0", features = ["derive", "rc"], optional = true } smol_str = { version = "0.1.23", features = ["serde"] } -stacker = { version = "0.1.15", optional = true } [dev-dependencies] +codespan = "0.11.1" +codespan-reporting = "0.11.1" criterion = "0.5.1" insta = { version = "1.26.0", features = ["glob", "yaml"] } pretty_assertions = "1.3.0" +termcolor = "1.2.0" [[bench]] name = "date" diff --git a/full-moon/fuzz/.gitignore b/full-moon/fuzz/.gitignore new file mode 100644 index 00000000..1a45eee7 --- /dev/null +++ b/full-moon/fuzz/.gitignore @@ -0,0 +1,4 @@ +target +corpus +artifacts +coverage diff --git a/full-moon/fuzz/Cargo.toml b/full-moon/fuzz/Cargo.toml new file mode 100644 index 00000000..67d472f8 --- /dev/null +++ b/full-moon/fuzz/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "full_moon_fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" +old_full_moon = { package = "full_moon", version = "0.18.1", features = [ + "stacker", +] } + +[dependencies.full_moon] +path = ".." + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[profile.release] +debug = 1 + +[[bin]] +name = "parse" +path = "fuzz_targets/parse.rs" +test = false +doc = false + +[[bin]] +name = "parse_parity" +path = "fuzz_targets/parse_parity.rs" +test = false +doc = false diff --git a/full-moon/fuzz/fuzz_targets/parse.rs b/full-moon/fuzz/fuzz_targets/parse.rs new file mode 100644 index 00000000..e156aad7 --- /dev/null +++ b/full-moon/fuzz/fuzz_targets/parse.rs @@ -0,0 +1,9 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; + +fuzz_target!(|data: &[u8]| { + if let Ok(string) = std::str::from_utf8(data) { + full_moon::parse_fallible(string, full_moon::LuaVersion::new()); + } +}); diff --git a/full-moon/fuzz/fuzz_targets/parse_parity.rs b/full-moon/fuzz/fuzz_targets/parse_parity.rs new file mode 100644 index 00000000..b427dae4 --- /dev/null +++ b/full-moon/fuzz/fuzz_targets/parse_parity.rs @@ -0,0 +1,11 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; + +fuzz_target!(|data: &[u8]| { + if let Ok(string) = std::str::from_utf8(data) { + if old_full_moon::parse(string).is_ok() { + full_moon::parse_fallible(string, full_moon::LuaVersion::new()); + } + } +}); diff --git a/full-moon/src/ast/mod.rs b/full-moon/src/ast/mod.rs index 151284ac..8f4a7338 100644 --- a/full-moon/src/ast/mod.rs +++ b/full-moon/src/ast/mod.rs @@ -1,3 +1,4 @@ +mod parser_structs; #[macro_use] mod parser_util; mod parsers; @@ -7,7 +8,7 @@ mod update_positions; mod visitors; use crate::{ - tokenizer::{Symbol, Token, TokenReference, TokenType}, + tokenizer::{Position, Symbol, Token, TokenReference, TokenType}, util::*, }; use derive_more::Display; @@ -17,19 +18,20 @@ use full_moon_derive::{Node, Visit}; use serde::{Deserialize, Serialize}; use std::{borrow::Cow, fmt}; -use parser_util::{ - InternalAstError, OneOrMore, Parser, ParserState, ZeroOrMore, ZeroOrMoreDelimited, -}; - use punctuated::{Pair, Punctuated}; use span::ContainedSpan; -#[cfg(feature = "roblox")] +pub use parser_structs::AstResult; + +mod versions; +pub use versions::*; + +#[cfg(feature = "luau")] pub mod types; -#[cfg(feature = "roblox")] +#[cfg(feature = "luau")] use types::*; -#[cfg(feature = "roblox")] +#[cfg(feature = "luau")] mod type_visitors; #[cfg(feature = "lua52")] @@ -100,6 +102,14 @@ impl Block { pub fn with_last_stmt(self, last_stmt: Option<(LastStmt, Option)>) -> Self { Self { last_stmt, ..self } } + + pub(crate) fn merge_blocks(&mut self, other: Self) { + self.stmts.extend(other.stmts); + + if self.last_stmt.is_none() { + self.last_stmt = other.last_stmt; + } + } } /// The last statement of a [`Block`] @@ -110,8 +120,8 @@ pub enum LastStmt { /// A `break` statement Break(TokenReference), /// A continue statement - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] Continue(TokenReference), /// A `return` statement Return(Return), @@ -131,7 +141,7 @@ impl Return { /// Default return token is followed by a single space pub fn new() -> Self { Self { - token: TokenReference::symbol("return ").unwrap(), + token: TokenReference::basic_symbol("return "), returns: Punctuated::new(), } } @@ -221,8 +231,8 @@ impl TableConstructor { pub fn new() -> Self { Self { braces: ContainedSpan::new( - TokenReference::symbol("{ ").unwrap(), - TokenReference::symbol(" }").unwrap(), + TokenReference::basic_symbol("{ "), + TokenReference::basic_symbol(" }"), ), fields: Punctuated::new(), } @@ -304,14 +314,14 @@ pub enum Expression { FunctionCall(FunctionCall), /// An if expression, such as `if foo then true else false`. - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] #[display(fmt = "{_0}")] IfExpression(IfExpression), /// An interpolated string, such as `` `hello {"world"}` `` - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] #[display(fmt = "{_0}")] InterpolatedString(InterpolatedString), @@ -332,8 +342,8 @@ pub enum Expression { Symbol(TokenReference), /// A value that has been asserted for a particular type, for use in Luau. - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] #[display(fmt = "{expression}{type_assertion}")] TypeAssertion { /// The expression being asserted @@ -388,17 +398,17 @@ pub enum Stmt { While(While), /// A compound assignment, such as `+=` - /// Only available when the "roblox" feature flag is enabled - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled + #[cfg(feature = "luau")] #[display(fmt = "{_0}")] CompoundAssignment(CompoundAssignment), /// An exported type declaration, such as `export type Meters = number` - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] ExportedTypeDeclaration(ExportedTypeDeclaration), /// A type declaration, such as `type Meters = number` - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] TypeDeclaration(TypeDeclaration), /// A goto statement, such as `goto label` @@ -482,6 +492,19 @@ pub enum FunctionArgs { TableConstructor(TableConstructor), } +impl FunctionArgs { + pub(crate) fn empty() -> Self { + FunctionArgs::Parentheses { + parentheses: ContainedSpan::new( + TokenReference::basic_symbol("("), + TokenReference::basic_symbol(")"), + ), + + arguments: Punctuated::new(), + } + } +} + /// A numeric for loop, such as `for index = 1, 10 do end` #[derive(Clone, Debug, PartialEq, Node)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -497,7 +520,7 @@ pub struct NumericFor { do_token: TokenReference, block: Block, end_token: TokenReference, - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] type_specifier: Option, } @@ -506,18 +529,18 @@ impl NumericFor { /// Creates a new NumericFor from the given index variable, start, and end expressions pub fn new(index_variable: TokenReference, start: Expression, end: Expression) -> Self { Self { - for_token: TokenReference::symbol("for ").unwrap(), + for_token: TokenReference::basic_symbol("for "), index_variable, - equal_token: TokenReference::symbol(" = ").unwrap(), + equal_token: TokenReference::basic_symbol(" = "), start, - start_end_comma: TokenReference::symbol(", ").unwrap(), + start_end_comma: TokenReference::basic_symbol(", "), end, end_step_comma: None, step: None, - do_token: TokenReference::symbol(" do\n").unwrap(), + do_token: TokenReference::basic_symbol(" do\n"), block: Block::new(), - end_token: TokenReference::symbol("\nend").unwrap(), - #[cfg(feature = "roblox")] + end_token: TokenReference::basic_symbol("\nend"), + #[cfg(feature = "luau")] type_specifier: None, } } @@ -584,8 +607,8 @@ impl NumericFor { /// The type specifiers of the index variable /// `for i: number = 1, 10 do` returns: /// `Some(TypeSpecifier(number))` - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] pub fn type_specifier(&self) -> Option<&TypeSpecifier> { self.type_specifier.as_ref() } @@ -658,8 +681,8 @@ impl NumericFor { } /// Returns a new NumericFor with the given type specifiers - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] pub fn with_type_specifier(self, type_specifier: Option) -> Self { Self { type_specifier, @@ -669,7 +692,7 @@ impl NumericFor { } impl fmt::Display for NumericFor { - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!( formatter, @@ -689,7 +712,7 @@ impl fmt::Display for NumericFor { ) } - #[cfg(not(feature = "roblox"))] + #[cfg(not(feature = "luau"))] fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!( formatter, @@ -720,7 +743,7 @@ pub struct GenericFor { do_token: TokenReference, block: Block, end_token: TokenReference, - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] type_specifiers: Vec>, } @@ -728,14 +751,14 @@ impl GenericFor { /// Creates a new GenericFor from the given names and expressions pub fn new(names: Punctuated, expr_list: Punctuated) -> Self { Self { - for_token: TokenReference::symbol("for ").unwrap(), + for_token: TokenReference::basic_symbol("for "), names, - in_token: TokenReference::symbol(" in ").unwrap(), + in_token: TokenReference::basic_symbol(" in "), expr_list, - do_token: TokenReference::symbol(" do\n").unwrap(), + do_token: TokenReference::basic_symbol(" do\n"), block: Block::new(), - end_token: TokenReference::symbol("\nend").unwrap(), - #[cfg(feature = "roblox")] + end_token: TokenReference::basic_symbol("\nend"), + #[cfg(feature = "luau")] type_specifiers: Vec::new(), } } @@ -780,8 +803,8 @@ impl GenericFor { /// The type specifiers of the named variables, in the order that they were assigned. /// `for i, v: string in pairs() do` returns an iterator containing: /// `None, Some(TypeSpecifier(string))` - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] pub fn type_specifiers(&self) -> impl Iterator> { self.type_specifiers.iter().map(Option::as_ref) } @@ -822,8 +845,8 @@ impl GenericFor { } /// Returns a new GenericFor with the given type specifiers - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] pub fn with_type_specifiers(self, type_specifiers: Vec>) -> Self { Self { type_specifiers, @@ -833,7 +856,7 @@ impl GenericFor { } impl fmt::Display for GenericFor { - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!( formatter, @@ -848,7 +871,7 @@ impl fmt::Display for GenericFor { ) } - #[cfg(not(feature = "roblox"))] + #[cfg(not(feature = "luau"))] fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!( formatter, @@ -894,14 +917,14 @@ impl If { /// Creates a new If from the given condition pub fn new(condition: Expression) -> Self { Self { - if_token: TokenReference::symbol("if ").unwrap(), + if_token: TokenReference::basic_symbol("if "), condition, - then_token: TokenReference::symbol(" then").unwrap(), + then_token: TokenReference::basic_symbol(" then"), block: Block::new(), else_if: None, else_token: None, r#else: None, - end_token: TokenReference::symbol("\nend").unwrap(), + end_token: TokenReference::basic_symbol("\nend"), } } @@ -1003,9 +1026,9 @@ impl ElseIf { /// Creates a new ElseIf from the given condition pub fn new(condition: Expression) -> Self { Self { - else_if_token: TokenReference::symbol("elseif ").unwrap(), + else_if_token: TokenReference::basic_symbol("elseif "), condition, - then_token: TokenReference::symbol(" then\n").unwrap(), + then_token: TokenReference::basic_symbol(" then\n"), block: Block::new(), } } @@ -1070,11 +1093,11 @@ impl While { /// Creates a new While from the given condition pub fn new(condition: Expression) -> Self { Self { - while_token: TokenReference::symbol("while ").unwrap(), + while_token: TokenReference::basic_symbol("while "), condition, - do_token: TokenReference::symbol(" do\n").unwrap(), + do_token: TokenReference::basic_symbol(" do\n"), block: Block::new(), - end_token: TokenReference::symbol("end\n").unwrap(), + end_token: TokenReference::basic_symbol("end\n"), } } @@ -1147,9 +1170,9 @@ impl Repeat { /// Creates a new Repeat from the given expression to repeat until pub fn new(until: Expression) -> Self { Self { - repeat_token: TokenReference::symbol("repeat\n").unwrap(), + repeat_token: TokenReference::basic_symbol("repeat\n"), block: Block::new(), - until_token: TokenReference::symbol("\nuntil ").unwrap(), + until_token: TokenReference::basic_symbol("\nuntil "), until, } } @@ -1215,7 +1238,7 @@ impl MethodCall { /// Returns a new MethodCall from the given name and args pub fn new(name: TokenReference, args: FunctionArgs) -> Self { Self { - colon_token: TokenReference::symbol(":").unwrap(), + colon_token: TokenReference::basic_symbol(":"), name, args, } @@ -1272,16 +1295,16 @@ pub enum Call { #[derive(Clone, Debug, PartialEq, Node)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct FunctionBody { - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] generics: Option, parameters_parentheses: ContainedSpan, parameters: Punctuated, - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] type_specifiers: Vec>, - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] return_type: Option, @@ -1293,23 +1316,23 @@ impl FunctionBody { /// Returns a new empty FunctionBody pub fn new() -> Self { Self { - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] generics: None, parameters_parentheses: ContainedSpan::new( - TokenReference::symbol("(").unwrap(), - TokenReference::symbol(")").unwrap(), + TokenReference::basic_symbol("("), + TokenReference::basic_symbol(")"), ), parameters: Punctuated::new(), - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] type_specifiers: Vec::new(), - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] return_type: None, block: Block::new(), - end_token: TokenReference::symbol("\nend").unwrap(), + end_token: TokenReference::basic_symbol("\nend"), } } @@ -1335,8 +1358,8 @@ impl FunctionBody { /// The generics declared for the function body. /// The `` part of `function x() end` - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] pub fn generics(&self) -> Option<&GenericDeclaration> { self.generics.as_ref() } @@ -1344,15 +1367,15 @@ impl FunctionBody { /// The type specifiers of the variables, in the order that they were assigned. /// `(foo: number, bar, baz: boolean)` returns an iterator containing: /// `Some(TypeSpecifier(number)), None, Some(TypeSpecifier(boolean))` - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] pub fn type_specifiers(&self) -> impl Iterator> { self.type_specifiers.iter().map(Option::as_ref) } /// The return type of the function, if one exists. - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] pub fn return_type(&self) -> Option<&TypeSpecifier> { self.return_type.as_ref() } @@ -1371,13 +1394,13 @@ impl FunctionBody { } /// Returns a new FunctionBody with the given generics declaration - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] pub fn with_generics(self, generics: Option) -> Self { Self { generics, ..self } } /// Returns a new FunctionBody with the given type specifiers - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] pub fn with_type_specifiers(self, type_specifiers: Vec>) -> Self { Self { type_specifiers, @@ -1386,7 +1409,7 @@ impl FunctionBody { } /// Returns a new FunctionBody with the given return type - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] pub fn with_return_type(self, return_type: Option) -> Self { Self { return_type, @@ -1412,7 +1435,7 @@ impl Default for FunctionBody { } impl fmt::Display for FunctionBody { - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!( formatter, @@ -1427,7 +1450,7 @@ impl fmt::Display for FunctionBody { ) } - #[cfg(not(feature = "roblox"))] + #[cfg(not(feature = "luau"))] fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!( formatter, @@ -1533,7 +1556,7 @@ impl Assignment { pub fn new(var_list: Punctuated, expr_list: Punctuated) -> Self { Self { var_list, - equal_token: TokenReference::symbol(" = ").unwrap(), + equal_token: TokenReference::basic_symbol(" = "), expr_list, } } @@ -1578,11 +1601,11 @@ impl Assignment { #[derive(Clone, Debug, Display, PartialEq, Node, Visit)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[cfg_attr( - not(feature = "roblox"), + not(feature = "luau"), display(fmt = "{local_token}{function_token}{name}{body}") )] #[cfg_attr( - feature = "roblox", + feature = "luau", display(fmt = "{local_token}{function_token}{name}{body}") )] pub struct LocalFunction { @@ -1596,8 +1619,8 @@ impl LocalFunction { /// Returns a new LocalFunction from the given name pub fn new(name: TokenReference) -> Self { LocalFunction { - local_token: TokenReference::symbol("local ").unwrap(), - function_token: TokenReference::symbol("function ").unwrap(), + local_token: TokenReference::basic_symbol("local "), + function_token: TokenReference::basic_symbol("function "), name, body: FunctionBody::new(), } @@ -1655,7 +1678,7 @@ impl LocalFunction { #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct LocalAssignment { local_token: TokenReference, - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] #[cfg_attr( feature = "serde", serde(skip_serializing_if = "empty_optional_vector") @@ -1676,8 +1699,8 @@ impl LocalAssignment { /// Returns a new LocalAssignment from the given name list pub fn new(name_list: Punctuated) -> Self { Self { - local_token: TokenReference::symbol("local ").unwrap(), - #[cfg(feature = "roblox")] + local_token: TokenReference::basic_symbol("local "), + #[cfg(feature = "luau")] type_specifiers: Vec::new(), name_list, #[cfg(feature = "lua54")] @@ -1712,8 +1735,8 @@ impl LocalAssignment { /// The type specifiers of the variables, in the order that they were assigned. /// `local foo: number, bar, baz: boolean` returns an iterator containing: /// `Some(TypeSpecifier(number)), None, Some(TypeSpecifier(boolean))` - /// Only available when the "roblox" feature flag is enabled. - #[cfg(feature = "roblox")] + /// Only available when the "luau" feature flag is enabled. + #[cfg(feature = "luau")] pub fn type_specifiers(&self) -> impl Iterator> { self.type_specifiers.iter().map(Option::as_ref) } @@ -1736,7 +1759,7 @@ impl LocalAssignment { } /// Returns a new LocalAssignment with the given type specifiers - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] pub fn with_type_specifiers(self, type_specifiers: Vec>) -> Self { Self { type_specifiers, @@ -1775,9 +1798,9 @@ impl fmt::Display for LocalAssignment { let attributes = self.attributes().chain(std::iter::repeat(None)); #[cfg(not(feature = "lua54"))] let attributes = std::iter::repeat_with(|| None::); - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] let type_specifiers = self.type_specifiers().chain(std::iter::repeat(None)); - #[cfg(not(feature = "roblox"))] + #[cfg(not(feature = "luau"))] let type_specifiers = std::iter::repeat_with(|| None::); write!( @@ -1806,9 +1829,9 @@ impl Do { /// Creates an empty Do pub fn new() -> Self { Self { - do_token: TokenReference::symbol("do\n").unwrap(), + do_token: TokenReference::basic_symbol("do\n"), block: Block::new(), - end_token: TokenReference::symbol("\nend").unwrap(), + end_token: TokenReference::basic_symbol("\nend"), } } @@ -1868,8 +1891,8 @@ impl FunctionCall { FunctionArgs::Parentheses { arguments: Punctuated::new(), parentheses: ContainedSpan::new( - TokenReference::symbol("(").unwrap(), - TokenReference::symbol(")").unwrap(), + TokenReference::basic_symbol("("), + TokenReference::basic_symbol(")"), ), }, ))], @@ -1955,8 +1978,8 @@ impl FunctionName { /// as well as complicated declarations such as `function x.y.z:a() end` #[derive(Clone, Debug, Display, PartialEq, Node, Visit)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -#[cfg_attr(not(feature = "roblox"), display(fmt = "{function_token}{name}{body}"))] -#[cfg_attr(feature = "roblox", display(fmt = "{function_token}{name}{body}"))] +#[cfg_attr(not(feature = "luau"), display(fmt = "{function_token}{name}{body}"))] +#[cfg_attr(feature = "luau", display(fmt = "{function_token}{name}{body}"))] pub struct FunctionDeclaration { function_token: TokenReference, name: FunctionName, @@ -1967,7 +1990,7 @@ impl FunctionDeclaration { /// Creates a new FunctionDeclaration from the given name pub fn new(name: FunctionName) -> Self { Self { - function_token: TokenReference::symbol("function ").unwrap(), + function_token: TokenReference::basic_symbol("function "), name, body: FunctionBody::new(), } @@ -2007,85 +2030,135 @@ impl FunctionDeclaration { } } -make_op!(BinOp, +#[doc(hidden)] +#[macro_export] +macro_rules! make_bin_op { + ($(#[$outer:meta])* { $( + $([$($version:ident)|+])? $operator:ident = $precedence:expr, + )+ }) => { + paste::paste! { + #[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit)] + #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] + #[non_exhaustive] + $(#[$outer])* + #[display(fmt = "{}")] + pub enum BinOp { + $( + #[allow(missing_docs)] + $( + #[cfg(any( + $(feature = "" $version),+ + ))] + )* + $operator(TokenReference), + )+ + } + + impl BinOp { + /// The precedence of the operator, from a scale of 1 to 10. The larger the number, the higher the precedence. + pub fn precedence_of_token(token: &TokenReference) -> Option { + match token.token_type() { + TokenType::Symbol { symbol } => match symbol { + $( + $( + #[cfg(any( + $(feature = "" $version),+ + ))] + )* + Symbol::$operator => Some($precedence), + )+ + _ => None, + }, + + _ => None + } + } + + /// The token associated with this operator + pub fn token(&self) -> &TokenReference { + match self { + $( + $( + #[cfg(any( + $(feature = "" $version),+ + ))] + )* + BinOp::$operator(token) => token, + )+ + } + } + + pub(crate) fn consume(state: &mut parser_structs::ParserState) -> Option { + match state.current().unwrap().token_type() { + TokenType::Symbol { symbol } => match symbol { + $( + $( + #[cfg(any( + $(feature = "" $version),+ + ))] + )* + Symbol::$operator => { + if !$crate::has_version!(state.lua_version(), $($($version,)+)?) { + return None; + } + + Some(BinOp::$operator(state.consume().unwrap())) + }, + )+ + + _ => None, + }, + + _ => None, + } + } + } + } + }; +} + +make_bin_op!( #[doc = "Operators that require two operands, such as X + Y or X - Y"] #[visit(skip_visit_self)] { - And, - Caret, - GreaterThan, - GreaterThanEqual, - LessThan, - LessThanEqual, - Minus, - Or, - Percent, - Plus, - Slash, - Star, - TildeEqual, - TwoDots, - TwoEqual, - #[cfg(feature = "lua53")] - Ampersand, - #[cfg(any(feature = "roblox", feature = "lua53"))] - DoubleSlash, - #[cfg(feature = "lua53")] - DoubleLessThan, - #[cfg(feature = "lua53")] - Pipe, - #[cfg(feature = "lua53")] - DoubleGreaterThan, - #[cfg(feature = "lua53")] - Tilde, + Caret = 12, + + Percent = 10, + Slash = 10, + Star = 10, + [luau | lua53] DoubleSlash = 10, + + Minus = 9, + Plus = 9, + + TwoDots = 8, + [lua53] DoubleLessThan = 7, + [lua53] DoubleGreaterThan = 7, + + [lua53] Ampersand = 6, + + [lua53] Tilde = 5, + + [lua53] Pipe = 4, + + GreaterThan = 3, + GreaterThanEqual = 3, + LessThan = 3, + LessThanEqual = 3, + TildeEqual = 3, + TwoEqual = 3, + + And = 2, + + Or = 1, } ); impl BinOp { - /// The precedence of the operator, from a scale of 1 to 8. The larger the number, the higher the precedence. + /// The precedence of the operator. The larger the number, the higher the precedence. /// See more at - #[cfg(not(feature = "lua53"))] pub fn precedence(&self) -> u8 { - match *self { - BinOp::Caret(_) => 8, - BinOp::Star(_) | BinOp::Slash(_) | BinOp::Percent(_) => 6, - #[cfg(feature = "roblox")] - BinOp::DoubleSlash(_) => 6, - BinOp::Plus(_) | BinOp::Minus(_) => 5, - BinOp::TwoDots(_) => 4, - BinOp::GreaterThan(_) - | BinOp::LessThan(_) - | BinOp::GreaterThanEqual(_) - | BinOp::LessThanEqual(_) - | BinOp::TildeEqual(_) - | BinOp::TwoEqual(_) => 3, - BinOp::And(_) => 2, - BinOp::Or(_) => 1, - } - } - - /// The precedence of the operator, from a scale of 1 to 10. The larger the number, the higher the precedence. - /// See more at - #[cfg(feature = "lua53")] - pub fn precedence(&self) -> u8 { - match *self { - BinOp::Caret(_) => 12, - BinOp::Star(_) | BinOp::Slash(_) | BinOp::DoubleSlash(_) | BinOp::Percent(_) => 10, - BinOp::Plus(_) | BinOp::Minus(_) => 9, - BinOp::TwoDots(_) => 8, - BinOp::DoubleLessThan(_) | BinOp::DoubleGreaterThan(_) => 7, - BinOp::Ampersand(_) => 6, - BinOp::Tilde(_) => 5, - BinOp::Pipe(_) => 4, - BinOp::GreaterThan(_) - | BinOp::LessThan(_) - | BinOp::GreaterThanEqual(_) - | BinOp::LessThanEqual(_) - | BinOp::TildeEqual(_) - | BinOp::TwoEqual(_) => 3, - BinOp::And(_) => 2, - BinOp::Or(_) => 1, - } + BinOp::precedence_of_token(self.token()).expect("invalid token") } /// Whether the operator is right associative. If not, it is left associative. @@ -2094,62 +2167,34 @@ impl BinOp { matches!(*self, BinOp::Caret(_) | BinOp::TwoDots(_)) } - /// The token associated with the operator - pub fn token(&self) -> &TokenReference { - match self { - BinOp::And(token) - | BinOp::Caret(token) - | BinOp::GreaterThan(token) - | BinOp::GreaterThanEqual(token) - | BinOp::LessThan(token) - | BinOp::LessThanEqual(token) - | BinOp::Minus(token) - | BinOp::Or(token) - | BinOp::Percent(token) - | BinOp::Plus(token) - | BinOp::Slash(token) - | BinOp::Star(token) - | BinOp::TildeEqual(token) - | BinOp::TwoDots(token) - | BinOp::TwoEqual(token) => token, - #[cfg(any(feature = "roblox", feature = "lua53"))] - BinOp::DoubleSlash(token) => token, - #[cfg(feature = "lua53")] - BinOp::Ampersand(token) - | BinOp::DoubleLessThan(token) - | BinOp::Pipe(token) - | BinOp::DoubleGreaterThan(token) - | BinOp::Tilde(token) => token, - } + /// Given a token, returns whether it is a right associative binary operator. + pub fn is_right_associative_token(token: &TokenReference) -> bool { + matches!( + token.token_type(), + TokenType::Symbol { + symbol: Symbol::Caret + } | TokenType::Symbol { + symbol: Symbol::TwoDots + } + ) } } -make_op!(UnOp, - #[doc = "Operators that require just one operand, such as #X"] - { - Minus, - Not, - Hash, - #[cfg(feature = "lua53")] - Tilde, - } -); - -impl UnOp { - /// The precedence of the operator, from a scale of 1 to 8. The larger the number, the higher the precedence. - /// See more at - #[cfg(not(feature = "lua53"))] - pub fn precedence(&self) -> u8 { - 7 - } - - /// The precedence of the operator, from a scale of 1 to 11. The larger the number, the higher the precedence. - /// See more at +/// Operators that require just one operand, such as #X +#[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[allow(missing_docs)] +#[non_exhaustive] +#[display(fmt = "{}")] +pub enum UnOp { + Minus(TokenReference), + Not(TokenReference), + Hash(TokenReference), #[cfg(feature = "lua53")] - pub fn precedence(&self) -> u8 { - 11 - } + Tilde(TokenReference), +} +impl UnOp { /// The token associated with the operator pub fn token(&self) -> &TokenReference { match self { @@ -2160,42 +2205,49 @@ impl UnOp { } } -/// An error that occurs when creating the ast *after* tokenizing +/// An error that occurs when creating the AST. #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -pub enum AstError { - /// There were no tokens passed, which shouldn't happen normally - Empty, - /// Tokens passed had no end of file token, which shouldn't happen normally - NoEof, - /// An unexpected token, the most likely scenario when getting an AstError - UnexpectedToken { - /// The token that caused the error - token: Token, - /// Any additional information that could be provided for debugging - additional: Option>, - }, +pub struct AstError { + /// The token that caused the error + token: Token, + + /// Any additional information that could be provided for debugging + additional: Cow<'static, str>, + + /// If set, this is the complete range of the error + #[serde(skip_serializing_if = "Option::is_none")] + range: Option<(Position, Position)>, +} + +impl AstError { + /// Returns a human readable error message + pub fn error_message(&self) -> Cow<'static, str> { + self.additional.clone() + } + + /// Returns the range of the error + pub fn range(&self) -> (Position, Position) { + self.range + .or_else(|| Some((self.token.start_position(), self.token.end_position()))) + .unwrap() + } } impl fmt::Display for AstError { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - match self { - AstError::Empty => write!(formatter, "tokens passed was empty, which shouldn't happen normally"), - AstError::NoEof => write!(formatter, "tokens passed had no eof token, which shouldn't happen normally"), - AstError::UnexpectedToken { token, additional } => write!( - formatter, - "unexpected token `{}`. (starting from line {}, character {} and ending on line {}, character {}){}", - token, - token.start_position().line(), - token.start_position().character(), - token.end_position().line(), - token.end_position().character(), - match additional { - Some(additional) => format!("\nadditional information: {additional}"), - None => String::new(), - } - ) - } + let range = self.range(); + + write!( + formatter, + "unexpected token `{}`. (starting from line {}, character {} and ending on line {}, character {})\nadditional information: {}", + self.token, + range.0.line(), + range.0.character(), + range.1.line(), + range.1.character(), + self.additional, + ) } } @@ -2210,79 +2262,6 @@ pub struct Ast { } impl Ast { - /// Create an Ast from the passed tokens. You probably want [`parse`](crate::parse) - /// - /// # Errors - /// - /// If the tokens passed are impossible to get through normal tokenization, - /// an error of Empty (if the vector is empty) or NoEof (if there is no eof token) - /// will be returned. - /// - /// More likely, if the tokens pass are invalid Lua 5.1 code, an - /// UnexpectedToken error will be returned. - #[allow(clippy::result_large_err)] - pub fn from_tokens(tokens: Vec) -> Result { - if *tokens.last().ok_or(AstError::Empty)?.token_type() != TokenType::Eof { - return Err(AstError::NoEof); - } - - let mut tokens = extract_token_references(tokens); - let mut state = ParserState::new(&tokens); - - if tokens - .iter() - .filter(|token| !token.token_type().is_trivia()) - .count() - == 1 - { - // Entirely comments/whitespace - return Ok(Ast { - nodes: Block { - stmts: Vec::new(), - last_stmt: None, - }, - eof: tokens - .pop() - .expect("(internal full-moon error) No EOF in tokens after checking for EOF."), - }); - } - - // ParserState has to have at least 2 tokens, the last being an EOF, thus unwrap() can't fail - if state.peek().token_type().is_trivia() { - state = state.advance().unwrap(); - } - - match parsers::ParseBlock.parse(state) { - Ok((state, block)) => { - if state.index == tokens.len() - 1 { - Ok(Ast { - nodes: block, - eof: tokens.pop().expect( - "(internal full-moon error) No EOF in tokens after checking for EOF.", - ), - }) - } else { - Err(AstError::UnexpectedToken { - token: state.peek().token.clone(), - additional: Some(Cow::Borrowed("leftover token")), - }) - } - } - - Err(InternalAstError::NoMatch) => Err(AstError::UnexpectedToken { - token: state.peek().token.clone(), - additional: None, - }), - - Err(InternalAstError::UnexpectedToken { token, additional }) => { - Err(AstError::UnexpectedToken { - token: token.token, - additional, - }) - } - } - } - /// Returns a new Ast with the given nodes pub fn with_nodes(self, nodes: Block) -> Self { Self { nodes, ..self } @@ -2296,7 +2275,7 @@ impl Ast { /// The entire code of the function /// /// ```rust - /// # fn main() -> Result<(), Box> { + /// # fn main() -> Result<(), Vec> { /// assert_eq!(full_moon::parse("local x = 1; local y = 2")?.nodes().stmts().count(), 2); /// # Ok(()) /// # } @@ -2316,86 +2295,10 @@ impl Ast { } } -/// Extracts leading and trailing trivia from tokens -pub(crate) fn extract_token_references(mut tokens: Vec) -> Vec { - let mut references = Vec::new(); - let (mut leading_trivia, mut trailing_trivia) = (Vec::new(), Vec::new()); - let mut tokens = tokens.drain(..).peekable(); - - while let Some(token) = tokens.next() { - if token.token_type().is_trivia() { - leading_trivia.push(token); - } else { - while let Some(token) = tokens.peek() { - if token.token_type().is_trivia() { - // Take all trivia up to and including the newline character. If we see a newline character - // we should break once we have taken it in. - let should_break = - if let TokenType::Whitespace { ref characters } = token.token_type() { - // Use contains in order to tolerate \r\n line endings and mixed whitespace tokens - characters.contains('\n') - } else { - false - }; - - trailing_trivia.push(tokens.next().unwrap()); - - if should_break { - break; - } - } else { - break; - } - } - - references.push(TokenReference { - leading_trivia: std::mem::take(&mut leading_trivia), - trailing_trivia: std::mem::take(&mut trailing_trivia), - token, - }); - } - } - - references -} - #[cfg(test)] mod tests { use super::*; - use crate::{parse, print, tokenizer::tokens, visitors::VisitorMut}; - - #[test] - fn test_extract_token_references() { - let tokens = tokens("print(1)\n-- hello world\nlocal foo -- this is the word foo").unwrap(); - - let references = extract_token_references(tokens); - assert_eq!(references.len(), 7); - - assert!(references[0].trailing_trivia.is_empty()); - assert_eq!(references[0].token.to_string(), "print"); - assert!(references[0].leading_trivia.is_empty()); - - assert!(references[1].trailing_trivia.is_empty()); - assert_eq!(references[1].token.to_string(), "("); - assert!(references[1].leading_trivia.is_empty()); - - assert!(references[2].trailing_trivia.is_empty()); - assert_eq!(references[2].token.to_string(), "1"); - assert!(references[2].leading_trivia.is_empty()); - - assert_eq!(references[3].trailing_trivia[0].to_string(), "\n"); - assert_eq!(references[3].token.to_string(), ")"); - assert!(references[3].leading_trivia.is_empty()); - - assert_eq!( - references[4].leading_trivia[0].to_string(), - "-- hello world", - ); - - assert_eq!(references[4].leading_trivia[1].to_string(), "\n"); - assert_eq!(references[4].token.to_string(), "local"); - assert_eq!(references[4].trailing_trivia[0].to_string(), " "); - } + use crate::{parse, print, visitors::VisitorMut}; #[test] fn test_with_eof_safety() { diff --git a/full-moon/src/ast/parser_structs.rs b/full-moon/src/ast/parser_structs.rs new file mode 100644 index 00000000..b70ba249 --- /dev/null +++ b/full-moon/src/ast/parser_structs.rs @@ -0,0 +1,372 @@ +use std::borrow::Cow; + +use crate::tokenizer::{Lexer, LexerResult, Symbol, TokenKind, TokenReference}; + +use super::{parsers::parse_block, Ast, Block, LuaVersion}; + +pub struct ParserState { + errors: Vec, + lexer: Lexer, + // Unused with no features enabled + #[allow(unused)] + lua_version: LuaVersion, +} + +impl ParserState { + pub fn new(lexer: Lexer) -> Self { + Self { + errors: Vec::new(), + lua_version: lexer.lua_version, + lexer, + } + } + + // Unused with no features enabled + #[allow(unused)] + pub fn lua_version(&self) -> LuaVersion { + self.lua_version + } + + pub fn current(&self) -> Result<&TokenReference, ()> { + match self.lexer.current() { + Some(LexerResult::Ok(token) | LexerResult::Recovered(token, _)) => Ok(token), + Some(LexerResult::Fatal(_)) => Err(()), + None => unreachable!("current() called past EOF"), + } + } + + pub fn peek(&self) -> Result<&TokenReference, ()> { + match self.lexer.peek() { + Some(LexerResult::Ok(token) | LexerResult::Recovered(token, _)) => Ok(token), + Some(LexerResult::Fatal(_)) => Err(()), + None => unreachable!("peek() called past EOF"), + } + } + + pub fn consume(&mut self) -> ParserResult { + let token = self.lexer.consume(); + + match token { + Some(LexerResult::Ok(token)) => ParserResult::Value(token), + + Some(LexerResult::Recovered(token, errors)) => { + for error in errors { + self.errors.push(crate::Error::TokenizerError(error)); + } + + ParserResult::Value(token) + } + + Some(LexerResult::Fatal(errors)) => { + for error in errors { + self.errors.push(crate::Error::TokenizerError(error)); + } + + ParserResult::LexerMoved + } + + None => ParserResult::NotFound, + } + } + + pub fn consume_if(&mut self, symbol: Symbol) -> Option { + match self.current() { + Ok(token) => { + if token.is_symbol(symbol) { + Some(self.consume().unwrap()) + } else { + None + } + } + + Err(()) => None, + } + } + + pub fn require(&mut self, symbol: Symbol, error: &'static str) -> Option { + match self.current() { + Ok(token) => { + if token.is_symbol(symbol) { + Some(self.consume().unwrap()) + } else { + self.token_error(token.clone(), error); + None + } + } + + Err(()) => None, + } + } + + pub fn require_with_reference_token( + &mut self, + symbol: Symbol, + error: &'static str, + reference_token: &TokenReference, + ) -> Option { + match self.current() { + Ok(token) => { + if token.is_symbol(symbol) { + Some(self.consume().unwrap()) + } else { + self.token_error(reference_token.clone(), error); + None + } + } + + Err(()) => None, + } + } + + pub fn require_with_reference_range( + &mut self, + symbol: Symbol, + error: impl MaybeLazyString, + start_token: &TokenReference, + end_token: &TokenReference, + ) -> Option { + match self.current() { + Ok(token) => { + if token.is_symbol(symbol) { + Some(self.consume().unwrap()) + } else { + self.token_error_ranged(token.clone(), error.to_str(), start_token, end_token); + None + } + } + + Err(()) => None, + } + } + + pub fn require_with_reference_range_callback( + &mut self, + symbol: Symbol, + error: impl MaybeLazyString, + tokens: impl FnOnce() -> (TokenReference, TokenReference), + ) -> Option { + match self.current() { + Ok(token) => { + if token.is_symbol(symbol) { + Some(self.consume().unwrap()) + } else { + let (start_token, end_token) = tokens(); + + self.token_error_ranged( + token.clone(), + error.to_str(), + &start_token, + &end_token, + ); + + None + } + } + + Err(()) => None, + } + } + + pub fn token_error>>( + &mut self, + token_reference: TokenReference, + error: S, + ) { + self.errors + .push(crate::Error::AstError(crate::ast::AstError { + token: token_reference.token, + additional: error.into(), + range: None, + })); + } + + // This takes start_token and end_token as owned references because otherwise, we tend to stack an immutable over mutable borrow. + pub fn token_error_ranged>>( + &mut self, + token_reference: TokenReference, + error: S, + start_token: &TokenReference, + end_token: &TokenReference, + ) { + self.errors + .push(crate::Error::AstError(crate::ast::AstError { + token: token_reference.token, + additional: error.into(), + range: Some((start_token.start_position(), end_token.end_position())), + })); + } +} + +pub trait MaybeLazyString { + fn to_str(self) -> Cow<'static, str>; +} + +impl MaybeLazyString for &'static str { + fn to_str(self) -> Cow<'static, str> { + Cow::Borrowed(self) + } +} + +impl String> MaybeLazyString for F { + fn to_str(self) -> Cow<'static, str> { + Cow::Owned(self()) + } +} + +#[derive(Debug)] +pub enum ParserResult { + // This doesn't necessarily mean that there were no errors, + // because this can sometimes be a recovered value. + Value(T), + + // Couldn't get any sort of value, but the lexer has moved. + // This should always come with an error. + LexerMoved, + + NotFound, +} + +impl ParserResult { + pub fn unwrap(self) -> T { + match self { + ParserResult::Value(value) => value, + ParserResult::LexerMoved => panic!("unwrap() called when value was LexerMoved"), + ParserResult::NotFound => panic!("unwrap() called when value was NotFound"), + } + } +} + +/// A produced [`Ast`](crate::ast::Ast), along with any errors found during parsing. +/// This Ast may not be exactly the same as the input code, as reconstruction may have occurred. +/// For more information, read the documentation for [`parse_fallible`](crate::parse_fallible). +pub struct AstResult { + ast: Ast, + errors: Vec, +} + +impl AstResult { + /// Returns a reference to the [`Ast`](crate::ast::Ast) that was parsed. + /// If there were any errors, this will not be exactly the same, + /// as reconstruction will have occurred. + /// For more information, read the documentation for [`parse_fallible`](crate::parse_fallible). + pub fn ast(&self) -> &Ast { + &self.ast + } + + /// Consumes the [`Ast`](crate::ast::Ast) that was parsed. + /// If there were any errors, this will not be exactly the same, + /// as reconstruction will have occurred. + /// For more information, read the documentation for [`parse_fallible`](crate::parse_fallible). + pub fn into_ast(self) -> Ast { + self.ast + } + + /// Returns all errors that occurred during parsing. + pub fn errors(&self) -> &[crate::Error] { + &self.errors + } + + pub(crate) fn parse_fallible(code: &str, lua_version: LuaVersion) -> Self { + const UNEXPECTED_TOKEN_ERROR: &str = "unexpected token, this needs to be a statement"; + + let lexer = Lexer::new(code, lua_version); + let mut parser_state = ParserState::new(lexer); + + let mut block = match parse_block(&mut parser_state) { + ParserResult::Value(block) => block, + _ => Block::new(), + }; + + loop { + match parser_state.lexer.current() { + Some(LexerResult::Ok(token)) if token.token_kind() == TokenKind::Eof => { + break; + } + + Some(LexerResult::Ok(_) | LexerResult::Recovered(_, _)) => { + if let ParserResult::Value(new_block) = parse_block(&mut parser_state) { + if new_block.stmts.is_empty() { + if let Ok(token) = parser_state.current() { + if token.token_kind() == TokenKind::Eof { + break; + } + } + + match parser_state.consume() { + ParserResult::Value(token) => { + if let Some(crate::Error::AstError(crate::ast::AstError { + additional, + .. + })) = parser_state.errors.last() + { + if additional == UNEXPECTED_TOKEN_ERROR { + continue; + } + } + + parser_state.token_error(token, UNEXPECTED_TOKEN_ERROR); + } + + ParserResult::LexerMoved => {} + + ParserResult::NotFound => unreachable!(), + } + + continue; + } + + block.merge_blocks(new_block); + } + } + + Some(LexerResult::Fatal(_)) => { + for error in parser_state.lexer.consume().unwrap().unwrap_errors() { + parser_state + .errors + .push(crate::Error::TokenizerError(error)); + } + } + + None => break, + } + } + + let eof = match parser_state.lexer.consume().unwrap() { + LexerResult::Ok(token) => token, + + LexerResult::Recovered(token, errors) => { + for error in errors { + parser_state + .errors + .push(crate::Error::TokenizerError(error)); + } + + token + } + + LexerResult::Fatal(error) => unreachable!("error: {error:?}"), + }; + + debug_assert_eq!(eof.token_kind(), TokenKind::Eof); + + Self { + ast: Ast { nodes: block, eof }, + errors: parser_state.errors, + } + } + + /// Consumes this AstResult, returning the [`Ast`](crate::ast::Ast) that was parsed. + pub fn into_result(self) -> Result> { + self.into() + } +} + +impl From for Result> { + fn from(ast_result: AstResult) -> Self { + if ast_result.errors.is_empty() { + Ok(ast_result.ast) + } else { + Err(ast_result.errors) + } + } +} diff --git a/full-moon/src/ast/parser_util.rs b/full-moon/src/ast/parser_util.rs index 46b57a39..509014cf 100644 --- a/full-moon/src/ast/parser_util.rs +++ b/full-moon/src/ast/parser_util.rs @@ -1,120 +1,16 @@ -// Exported macros are documented since no amount of allow(missing_docs) silenced the lint - -use super::punctuated::{Pair, Punctuated}; -use crate::{ - node::Node, - tokenizer::TokenReference, - visitors::{Visit, VisitMut}, -}; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; -use std::{borrow::Cow, fmt}; - -// This is cloned everywhere, so make sure cloning is as inexpensive as possible -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct ParserState<'a> { - pub index: usize, - pub len: usize, - pub tokens: &'a [TokenReference], -} - -impl<'a> ParserState<'a> { - pub fn new(tokens: &'a [TokenReference]) -> ParserState<'a> { - ParserState { - index: 0, - len: tokens.len(), - tokens, - } - } - - pub fn advance(self) -> Option> { - if self.index + 1 == self.len { - None - } else { - Some(ParserState { - index: self.index + 1, - ..self - }) - } - } - - pub fn peek(&self) -> &TokenReference { - assert!( - self.index < self.len, - "peek failed, when there should always be an eof" - ); - - self.tokens.get(self.index).expect("couldn't peek, no eof?") - } -} - -impl<'a> fmt::Debug for ParserState<'a> { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!( - formatter, - "ParserState {{ index: {}, current: {:?} }}", - self.index, - self.peek() - ) - } -} - -pub(crate) trait Parser: Sized { - type Item; - - #[allow(clippy::result_large_err)] - fn parse<'a>( - &self, - state: ParserState<'a>, - ) -> Result<(ParserState<'a>, Self::Item), InternalAstError>; -} - -#[doc(hidden)] -#[macro_export] -macro_rules! make_op { - ($enum:ident, $(#[$outer:meta])* { $($(#[$inner:meta])* $operator:ident,)+ }) => { - #[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit)] - #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] - #[non_exhaustive] - $(#[$outer])* - #[display(fmt = "{}")] - pub enum $enum { - $( - $(#[$inner])* - #[allow(missing_docs)] - $operator(TokenReference), - )+ - } - }; -} - +// Consumes a ParserResult into an Option. +// If the ParserResult is LexerMoved, this signifies an unrecoverable error, and +// the function exits early. +// I wish we had Try traits. #[doc(hidden)] #[macro_export] -macro_rules! define_parser { - ($parser:ty, $node:ty, |_, $state:ident| $body:expr) => { - define_parser! {$parser, $node, |_, mut $state: ParserState<'a>| $body} - }; - ($parser:ty, $node:ty, |$self:ident, $state:ident| $body:expr) => { - define_parser! {$parser, $node, |$self:&$parser, mut $state: ParserState<'a>| $body} - }; - ($parser:ty, $node:ty, $body:expr) => { - impl Parser for $parser { - type Item = $node; - - #[allow(unused_mut)] - fn parse<'a>( - &self, - state: ParserState<'a>, - ) -> Result<(ParserState<'a>, $node), InternalAstError> { - #[cfg(feature = "stacker")] - if true { - #[allow(clippy::redundant_closure_call)] - return stacker::maybe_grow(32 * 1024, 1024 * 1024, || $body(self, state)); - } - - #[allow(clippy::redundant_closure_call)] - $body(self, state) +macro_rules! try_parser { + ($result:expr) => { + match $result { + $crate::ast::parser_structs::ParserResult::Value(value) => Some(value), + $crate::ast::parser_structs::ParserResult::NotFound => None, + $crate::ast::parser_structs::ParserResult::LexerMoved => { + return $crate::ast::parser_structs::ParserResult::LexerMoved } } }; @@ -122,305 +18,21 @@ macro_rules! define_parser { #[doc(hidden)] #[macro_export] -macro_rules! parse_first_of { - ($state:ident, {$($(@#[$meta:meta])? $parser:expr => $constructor:expr,)+}) => ({ +macro_rules! version_switch { + ($lua_version:expr, { $( - $(#[$meta])? - { - let parser_result = $parser.parse($state).map(|(state, node)| (state, $constructor(node))); - if parser_result != Err(InternalAstError::NoMatch) { - return parser_result; - } - } + $($version:ident)|* => $value:expr )+ - - Err(InternalAstError::NoMatch) - }); -} - -#[doc(hidden)] -#[macro_export] -macro_rules! expect { - ($state:ident, $parsed:expr) => { - match $parsed { - Ok((state, node)) => (state, node), - Err(InternalAstError::NoMatch) => { - return Err(InternalAstError::UnexpectedToken { - token: $state.peek().clone(), - additional: None, - }); - } - Err(other) => return Err(other), - } - }; - - ($state:ident, $parsed:expr, $error:tt) => { - match $parsed { - Ok((state, node)) => (state, node), - Err(InternalAstError::NoMatch) => { - return Err(InternalAstError::UnexpectedToken { - token: $state.peek().clone(), - additional: Some(Cow::from($error)), - }); - } - Err(other) => return Err(other), - } - }; -} - -// This name is bad -#[doc(hidden)] -#[macro_export] -macro_rules! keep_going { - ($parsed:expr) => { - match $parsed { - Ok((state, node)) => Ok((state, node)), - Err(InternalAstError::NoMatch) => Err(InternalAstError::NoMatch), - Err(other) => return Err(other), - } - }; -} - -#[doc(hidden)] -#[macro_export] -#[rustfmt::skip] -macro_rules! define_roblox_parser { - ($parser:ident, $node:ty, $mock_ty:ty, |$self:ident, $state:ident| $body:expr) => { - define_roblox_parser! ($parser, $node, $mock_ty, |$self:&$parser, mut $state: ParserState<'a>| $body); - }; - ($parser:ident, $node:ty, $mock_ty:ty, $body:expr) => { - cfg_if::cfg_if! { - if #[cfg(feature = "roblox")] { - define_parser!($parser, $node, $body); - } else { - define_parser!($parser, $mock_ty, |_, _| { - Err(InternalAstError::NoMatch) - }); - } - } - }; -} - -#[doc(hidden)] -#[macro_export] -macro_rules! define_lua52_parser { - ($parser:ident, $node:ty, $mock_ty:ty, $body:expr) => { - cfg_if::cfg_if! { - if #[cfg(feature = "lua52")] { - define_parser!($parser, $node, $body); - } else { - define_parser!($parser, $mock_ty, |_, _| { - Err(InternalAstError::NoMatch) - }); - } - } - }; -} - -#[derive(Clone, Debug, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -pub enum InternalAstError { - NoMatch, - UnexpectedToken { - token: TokenReference, - additional: Option>, - }, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ZeroOrMore

(pub P); - -impl Parser for ZeroOrMore

-where - P: Parser, -{ - type Item = Vec; - - fn parse<'a>( - &self, - mut state: ParserState<'a>, - ) -> Result<(ParserState<'a>, Vec), InternalAstError> { - let mut nodes = Vec::new(); - loop { - match self.0.parse(state) { - Ok((new_state, node)) => { - state = new_state; - nodes.push(node); - } - Err(InternalAstError::NoMatch) => break, - Err(other) => return Err(other), - }; - } - Ok((state, nodes)) - } -} - -macro_rules! test_pairs_logic { - ($nodes:expr, $cause:expr) => { - if cfg!(debug_assertions) { - let len = $nodes.len(); - for (index, node) in $nodes.pairs().enumerate() { - if index + 1 == len && node.punctuation().is_some() { - panic!( - "{} pairs illogical: last node has punctuation: {:?}", - $cause, - node.punctuation().unwrap() - ); - } else if index + 1 != len && node.punctuation().is_none() { - panic!( - "{} pairs illogical: non-last node ({}) has no punctuation", - $cause, index - ); - } - } - } - }; -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ZeroOrMoreDelimited( - pub ItemParser, // What items to parse, what is actually returned in a vec - pub Delimiter, // Delimiter parser between one item and another - pub bool, // Allow trailing delimiter? -); - -// False positive clippy lints -#[allow(clippy::blocks_in_if_conditions)] -#[allow(clippy::nonminimal_bool)] -impl Parser for ZeroOrMoreDelimited -where - ItemParser: Parser, - Delimiter: Parser, - T: Node + Visit + VisitMut, -{ - type Item = Punctuated; - - fn parse<'a>( - &self, - mut state: ParserState<'a>, - ) -> Result<(ParserState<'a>, Punctuated), InternalAstError> { - let mut nodes = Punctuated::new(); - - if let Ok((new_state, node)) = keep_going!(self.0.parse(state)) { - state = new_state; - nodes.push(Pair::End(node)); - } else { - return Ok((state, Punctuated::new())); - } - - while let Ok((new_state, delimiter)) = keep_going!(self.1.parse(state)) { - let last_value = nodes.pop().unwrap().into_value(); - nodes.push(Pair::Punctuated(last_value, delimiter)); - - state = new_state; - - match self.0.parse(state) { - Ok((new_state, node)) => { - state = new_state; - nodes.push(Pair::End(node)); - } - - Err(InternalAstError::NoMatch) => { - if self.2 { - break; - } - - return Err(InternalAstError::UnexpectedToken { - token: state.peek().clone(), - additional: Some(Cow::from("trailing character")), - }); - } - - Err(other) => { - return Err(other); - } - } - } - - if !self.2 { - test_pairs_logic!(nodes, "ZeroOrMoreDelimited"); - } - - Ok((state, nodes)) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct OneOrMore( - pub ItemParser, // What items to parse, what is actually returned in a vec - pub Delimiter, // Delimiter parser between one item and another - pub bool, // Allow trailing delimiter? -); - -// False positive clippy lints -#[allow(clippy::blocks_in_if_conditions)] -#[allow(clippy::nonminimal_bool)] -impl Parser for OneOrMore -where - ItemParser: Parser, - Delimiter: Parser, - T: Node + Visit + VisitMut, -{ - type Item = Punctuated; - - fn parse<'a>( - &self, - state: ParserState<'a>, - ) -> Result<(ParserState<'a>, Punctuated), InternalAstError> { - let mut nodes = Punctuated::new(); - let (mut state, node) = self.0.parse(state)?; - nodes.push(Pair::End(node)); - - while let Ok((new_state, delimiter)) = self.1.parse(state) { - let last_value = nodes.pop().unwrap().into_value(); - nodes.push(Pair::Punctuated(last_value, delimiter)); - - match self.0.parse(new_state) { - Ok((new_state, node)) => { - state = new_state; - nodes.push(Pair::End(node)); - } - - Err(InternalAstError::NoMatch) => { - if self.2 { - state = new_state; + }) => { + paste::paste! { + $( + $( + #[cfg(feature = "" $version)] + if $lua_version.[]() { + $value } - - break; - } - - Err(other) => { - return Err(other); - } - } - } - - if !self.2 { - let last_value = nodes.pop().unwrap().into_value(); - nodes.push(Pair::End(last_value)); - - test_pairs_logic!(nodes, "OneOrMore"); + )* + )+ } - - Ok((state, nodes)) - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct NoDelimiter; - -define_parser!(NoDelimiter, (), |_, state| Ok((state, ()))); - -pub struct ParseIntoBox

(pub P); - -impl Parser for ParseIntoBox

{ - type Item = Box; - - fn parse<'a>( - &self, - state: ParserState<'a>, - ) -> Result<(ParserState<'a>, Box), InternalAstError> { - let (state, item) = self.0.parse(state)?; - Ok((state, Box::new(item))) - } + }; } diff --git a/full-moon/src/ast/parsers.rs b/full-moon/src/ast/parsers.rs index e2ea12bb..e7f8e250 100644 --- a/full-moon/src/ast/parsers.rs +++ b/full-moon/src/ast/parsers.rs @@ -1,2367 +1,3288 @@ +// actually, it might but only because the last token isn't an eof. parser is going to have to throw out those tokens +// and then read another block and merge them or something? wow that sounds awful because it won't work inside if's. good luck +// maybe keep parsing until there's an `end`???? but then global blocks...aaa + use super::{ - parser_util::{InternalAstError, ParseIntoBox, Parser}, + parser_structs::{ParserResult, ParserState}, + punctuated::{Pair, Punctuated}, span::ContainedSpan, - *, + Expression, FunctionBody, Parameter, +}; +use crate::{ + ast, + node::Node, + tokenizer::{Symbol, Token, TokenKind, TokenReference, TokenType}, }; -#[cfg(feature = "roblox")] -use super::types::*; +#[cfg(feature = "luau")] +use crate::tokenizer::InterpolatedStringKind; + +#[cfg(feature = "luau")] +static PARSE_NAME_ERROR: &str = "%error-id%"; + +#[cfg(feature = "luau")] +fn error_token() -> TokenReference { + TokenReference::new( + Vec::new(), + Token::new(TokenType::Identifier { + identifier: PARSE_NAME_ERROR.into(), + }), + Vec::new(), + ) +} -#[cfg(feature = "roblox")] -use crate::tokenizer_luau::InterpolatedStringKind; +pub fn parse_block(state: &mut ParserState) -> ParserResult { + let mut stmts = Vec::new(); -#[cfg(feature = "lua52")] -use super::lua52::*; + loop { + match parse_stmt(state) { + ParserResult::Value(StmtVariant::Stmt(stmt)) => { + let semicolon = state.consume_if(Symbol::Semicolon); + stmts.push((stmt, semicolon)); + } + ParserResult::Value(StmtVariant::LastStmt(last_stmt)) => { + let semicolon = state.consume_if(Symbol::Semicolon); + let last_stmt = Some((last_stmt, semicolon)); + return ParserResult::Value(ast::Block { stmts, last_stmt }); + } -use crate::tokenizer::{TokenKind, TokenReference, TokenType}; + ParserResult::NotFound => break, + ParserResult::LexerMoved => { + if stmts.is_empty() { + return ParserResult::LexerMoved; + } else { + break; + } + } + } + } -use std::borrow::Cow; + let last_stmt = match parse_last_stmt(state) { + ParserResult::Value(stmt) => Some(stmt), + ParserResult::LexerMoved | ParserResult::NotFound => None, + }; -#[derive(Clone, Debug, PartialEq)] -struct ParseSymbol(Symbol); + ParserResult::Value(ast::Block { stmts, last_stmt }) +} -define_parser!(ParseSymbol, TokenReference, |this, state| { - let expecting = TokenType::Symbol { symbol: this.0 }; - let token = state.peek(); +// Blocks in general are not very fallible. This means, for instance, not finishing `function()` +// will result in a completely ignored function body. +// This is an opinionated choice because I believe selene is going to produce terrible outputs if we don't. +fn expect_block_with_end( + state: &mut ParserState, + name: &str, + start_for_errors: &TokenReference, +) -> Result<(ast::Block, TokenReference), ()> { + let block = match parse_block(state) { + ParserResult::Value(block) => block, + ParserResult::NotFound => unreachable!("parse_block should always return a value"), + ParserResult::LexerMoved => return Err(()), + }; - if *token.token_type() == expecting { - Ok(( - state.advance().ok_or(InternalAstError::NoMatch)?, - token.clone(), - )) + let (start, end) = if let Some(last_stmt) = block.last_stmt() { + let mut tokens = last_stmt.tokens(); + let start = tokens.next().unwrap(); + let end = tokens.last().unwrap_or(start); + (start, end) + } else if let Some(the_last_of_the_stmts) = block.stmts().last() { + let mut tokens = the_last_of_the_stmts.tokens(); + let start = tokens.next().unwrap(); + let end = tokens.last().unwrap_or(start); + (start, end) } else { - Err(InternalAstError::NoMatch) - } -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseNumber; - -define_parser!(ParseNumber, TokenReference, |_, state| { - let token = state.peek(); - if token.token_kind() == TokenKind::Number { - Ok(( - state.advance().ok_or(InternalAstError::NoMatch)?, - token.clone(), - )) - } else { - Err(InternalAstError::NoMatch) - } -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseStringLiteral; - -define_parser!(ParseStringLiteral, TokenReference, |_, state| { - let token = state.peek(); - if token.token_kind() == TokenKind::StringLiteral { - Ok(( - state.advance().ok_or(InternalAstError::NoMatch)?, - token.clone(), - )) - } else { - Err(InternalAstError::NoMatch) - } -}); + (start_for_errors, start_for_errors) + }; -#[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct ParseBlock; -define_parser!(ParseBlock, Block, |_, state| { - let mut stmts = Vec::new(); - while let Ok((new_state, stmt)) = keep_going!(ParseStmt.parse(state)) { - state = new_state; - let mut semicolon = None; + let Some(end_token) = state.require_with_reference_range( + Symbol::End, + || format!("expected `end` to close {} block", name), + start, + end, + ) else { + return Ok((block, TokenReference::basic_symbol("end"))); + }; - if let Ok((new_state, new_semicolon)) = ParseSymbol(Symbol::Semicolon).parse(state) { - state = new_state; - semicolon = Some(new_semicolon); - } + Ok((block, end_token)) +} - stmts.push((stmt, semicolon)); - } +enum StmtVariant { + Stmt(ast::Stmt), - if let Ok((mut state, last_stmt)) = keep_going!(ParseLastStmt.parse(state)) { - let mut semicolon = None; + // Used for things like Luau's `continue`, but nothing constructs it in Lua 5.1 alone. + #[allow(unused)] + LastStmt(ast::LastStmt), +} - if let Ok((new_state, new_semicolon)) = ParseSymbol(Symbol::Semicolon).parse(state) { - state = new_state; - semicolon = Some(new_semicolon) - } +fn parse_stmt(state: &mut ParserState) -> ParserResult { + let Ok(current_token) = state.current() else { + return ParserResult::NotFound; + }; - Ok(( - state, - Block { - stmts, - last_stmt: Some((last_stmt, semicolon)), - }, - )) - } else { - Ok(( - state, - Block { - stmts, - last_stmt: None, - }, - )) - } -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseLastStmt; -define_parser!( - ParseLastStmt, - LastStmt, - |_, state| if let Ok((state, token)) = ParseSymbol(Symbol::Return).parse(state) { - let (state, returns) = expect!( - state, - ZeroOrMoreDelimited(ParseExpression, ParseSymbol(Symbol::Comma), false).parse(state), - "return values" - ); + match current_token.token_type() { + TokenType::Symbol { + symbol: Symbol::Local, + } => { + let local_token = state.consume().unwrap(); + let next_token = match state.current() { + Ok(token) => token, + Err(()) => return ParserResult::LexerMoved, + }; - Ok((state, LastStmt::Return(Return { token, returns }))) - } else if let Ok((state, token)) = ParseSymbol(Symbol::Break).parse(state) { - Ok((state, LastStmt::Break(token))) - } else { - cfg_if::cfg_if! { - if #[cfg(feature = "roblox")] { - let (state, continue_token) = ParseIdentifier.parse(state)?; - if continue_token.token().to_string() == "continue" { - Ok((state, LastStmt::Continue(continue_token))) - } else { - Err(InternalAstError::NoMatch) + match next_token.token_type() { + TokenType::Identifier { .. } => ParserResult::Value(StmtVariant::Stmt( + ast::Stmt::LocalAssignment(match expect_local_assignment(state, local_token) { + Ok(local_assignment) => local_assignment, + Err(()) => return ParserResult::LexerMoved, + }), + )), + + TokenType::Symbol { + symbol: Symbol::Function, + } => { + let function_token = state.consume().unwrap(); + + let function_name = match state.current() { + Ok(token) if token.token_kind() == TokenKind::Identifier => { + state.consume().unwrap() + } + + Ok(token) => { + state.token_error(token.clone(), "expected a function name"); + return ParserResult::LexerMoved; + } + + Err(()) => return ParserResult::LexerMoved, + }; + + let function_body = match parse_function_body(state) { + ParserResult::Value(function_body) => function_body, + ParserResult::NotFound => { + state.token_error(function_token, "expected a function body"); + return ParserResult::LexerMoved; + } + ParserResult::LexerMoved => return ParserResult::LexerMoved, + }; + + ParserResult::Value(StmtVariant::Stmt(ast::Stmt::LocalFunction( + ast::LocalFunction { + local_token, + function_token, + name: function_name, + body: function_body, + }, + ))) + } + + _ => { + state.token_error( + next_token.clone(), + "expected either a variable name or `function`", + ); + + ParserResult::LexerMoved } - } else { - Err(InternalAstError::NoMatch) } } - } -); - -#[derive(Clone, Debug, PartialEq)] -struct ParseField; -define_parser!(ParseField, Field, |_, state| { - if let Ok((state, start_bracket)) = ParseSymbol(Symbol::LeftBracket).parse(state) { - let (state, key) = expect!(state, ParseExpression.parse(state), "expected key"); - let (state, end_bracket) = expect!( - state, - ParseSymbol(Symbol::RightBracket).parse(state), - "expected ']'" - ); - let (state, equal) = expect!( - state, - ParseSymbol(Symbol::Equal).parse(state), - "expected '='" - ); - let (state, value) = expect!(state, ParseExpression.parse(state), "expected value"); - return Ok(( - state, - Field::ExpressionKey { - brackets: ContainedSpan::new(start_bracket, end_bracket), - key, - equal, - value, - }, - )); - } else if let Ok((state, key)) = keep_going!(ParseIdentifier.parse(state)) { - if let Ok((state, equal)) = ParseSymbol(Symbol::Equal).parse(state) { - let (state, value) = expect!(state, ParseExpression.parse(state), "expected value"); + TokenType::Symbol { + symbol: Symbol::For, + } => { + let for_token = state.consume().unwrap(); - return Ok((state, Field::NameKey { key, equal, value })); + ParserResult::Value(StmtVariant::Stmt(match expect_for_stmt(state, for_token) { + Ok(for_stmt) => for_stmt, + Err(()) => return ParserResult::LexerMoved, + })) } - } - - if let Ok((state, expr)) = keep_going!(ParseExpression.parse(state)) { - return Ok((state, Field::NoKey(expr))); - } - Err(InternalAstError::NoMatch) -}); + TokenType::Symbol { symbol: Symbol::Do } => { + let do_token = state.consume().unwrap(); + let (block, end_token) = match expect_block_with_end(state, "do", &do_token) { + Ok(block) => block, + Err(()) => return ParserResult::LexerMoved, + }; -struct ParseTableConstructor; -define_parser!(ParseTableConstructor, TableConstructor, |_, state| { - let (mut state, start_brace) = ParseSymbol(Symbol::LeftBrace).parse(state)?; - let mut fields = Punctuated::new(); + ParserResult::Value(StmtVariant::Stmt(ast::Stmt::Do(ast::Do { + do_token, + block, + end_token, + }))) + } - while let Ok((new_state, field)) = keep_going!(ParseField.parse(state)) { - let field_sep = if let Ok((new_state, separator)) = - ParseSymbol(Symbol::Comma).parse(new_state) - { - state = new_state; - Some(separator) - } else if let Ok((new_state, separator)) = ParseSymbol(Symbol::Semicolon).parse(new_state) { - state = new_state; - Some(separator) - } else { - state = new_state; - None - }; + TokenType::Symbol { symbol: Symbol::If } => { + let if_token = state.consume().unwrap(); - let is_end = field_sep.is_none(); - fields.push(Pair::new(field, field_sep)); - if is_end { - break; + ParserResult::Value(StmtVariant::Stmt(ast::Stmt::If( + match expect_if_stmt(state, if_token) { + Ok(if_stmt) => if_stmt, + Err(()) => return ParserResult::LexerMoved, + }, + ))) } - } - let (state, end_brace) = expect!( - state, - ParseSymbol(Symbol::RightBrace).parse(state), - "expected '}'" - ); + TokenType::Symbol { + symbol: Symbol::Function, + } => { + let function_token = state.consume().unwrap(); - Ok(( - state, - TableConstructor { - braces: ContainedSpan::new(start_brace, end_brace), - fields, - }, - )) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseUnaryExpression; -define_parser!(ParseUnaryExpression, Expression, |_, state| { - let (state, unop) = keep_going!(ParseUnOp.parse(state))?; - let (state, expression) = expect!( - state, - ParseExpressionAtPrecedence(unop.precedence()).parse(state), - "expected expression" - ); - let expression = Box::new(expression); - - Ok((state, Expression::UnaryOperator { unop, expression })) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseParenExpression; -define_parser!(ParseParenExpression, Expression, |_, state| { - let (state, left_paren) = ParseSymbol(Symbol::LeftParen).parse(state)?; - let (state, expression) = expect!(state, ParseExpression.parse(state), "expected expression"); - - let (state, right_paren) = expect!( - state, - ParseSymbol(Symbol::RightParen).parse(state), - "expected ')'" - ); - - Ok(( - state, - Expression::Parentheses { - contained: ContainedSpan::new(left_paren, right_paren), - expression: Box::new(expression), - }, - )) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParsePartExpression; - -// This looks really stupid because we save 66% of the stack allocation cost -// by doing this. -define_parser!(ParsePartExpression, Expression, |_, state| { - #[allow(clippy::result_large_err)] - fn parse_unary_expression( - state: ParserState, - ) -> Result<(ParserState, Expression), InternalAstError> { - ParseUnaryExpression.parse(state) - } + let function_declaration = match expect_function_declaration(state, function_token) { + Ok(function_declaration) => function_declaration, + Err(()) => return ParserResult::LexerMoved, + }; - #[allow(clippy::result_large_err)] - fn parse_value(state: ParserState) -> Result<(ParserState, Expression), InternalAstError> { - ParseValue.parse(state) - } + ParserResult::Value(StmtVariant::Stmt(ast::Stmt::FunctionDeclaration( + function_declaration, + ))) + } - #[allow(clippy::result_large_err)] - fn parse_paren_expression( - state: ParserState, - ) -> Result<(ParserState, Expression), InternalAstError> { - ParseParenExpression.parse(state) - } + TokenType::Symbol { + symbol: Symbol::Repeat, + } => { + let repeat_token = state.consume().unwrap(); - let (state, expression) = keep_going!(parse_unary_expression(state)).or_else(|_| { - keep_going!(parse_value(state)).or_else(|_| keep_going!(parse_paren_expression(state))) - })?; - - #[cfg(feature = "roblox")] - #[allow(clippy::result_large_err)] - fn maybe_type_assertion( - state: ParserState, - expression: Expression, - ) -> Result<(ParserState, Expression), InternalAstError> { - if let Ok((state, type_assertion)) = keep_going!(ParseTypeAssertion.parse(state)) { - return Ok(( - state, - Expression::TypeAssertion { - expression: Box::new(expression), - type_assertion, + ParserResult::Value(StmtVariant::Stmt( + match expect_repeat_stmt(state, repeat_token) { + Ok(repeat_stmt) => repeat_stmt, + Err(()) => return ParserResult::LexerMoved, }, - )); + )) } - Ok((state, expression)) - } - - #[cfg(not(feature = "roblox"))] - #[allow(clippy::result_large_err)] - fn maybe_type_assertion( - state: ParserState, - expression: Expression, - ) -> Result<(ParserState, Expression), InternalAstError> { - Ok((state, expression)) - } - - maybe_type_assertion(state, expression) -}); + TokenType::Symbol { + symbol: Symbol::While, + } => { + let while_token = state.consume().unwrap(); -#[derive(Clone, Debug, PartialEq)] -struct ParseExpressionAtPrecedence(u8); -define_parser!(ParseExpressionAtPrecedence, Expression, |this, state| { - let min_precedence = this.0; - let (mut state, mut current_expr) = ParsePartExpression.parse(state)?; + ParserResult::Value(StmtVariant::Stmt(ast::Stmt::While( + match expect_while_stmt(state, while_token) { + Ok(while_stmt) => while_stmt, + Err(()) => return ParserResult::LexerMoved, + }, + ))) + } - // See if we can find a Binary Operator - while let Ok((next_state, operator)) = ParseBinOp.parse(state) { - if operator.precedence() < min_precedence { - break; + TokenType::Symbol { + symbol: Symbol::LeftParen, } + | TokenType::Identifier { .. } => { + // unwrap() because we're always starting on the right path + let (prefix, suffixes) = try_parser!(parse_prefix_and_suffixes(state)).unwrap(); + + let var = match suffixes.last() { + Some(ast::Suffix::Call(_)) => { + return ParserResult::Value(StmtVariant::Stmt(ast::Stmt::FunctionCall( + ast::FunctionCall { prefix, suffixes }, + ))); + } - let next_min_precedence = if operator.is_right_associative() { - operator.precedence() - } else { - operator.precedence() + 1 - }; + Some(ast::Suffix::Index(_)) => { + ast::Var::Expression(Box::new(ast::VarExpression { prefix, suffixes })) + } - let (next_state, rhs) = expect!( - next_state, - ParseExpressionAtPrecedence(next_min_precedence).parse(next_state), - "expected expression" - ); - state = next_state; - current_expr = Expression::BinaryOperator { - lhs: Box::new(current_expr), - binop: operator, - rhs: Box::new(rhs), - }; - } + None => match prefix { + ast::Prefix::Name(name) => ast::Var::Name(name), - Ok((state, current_expr)) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseExpression; -define_parser!(ParseExpression, Expression, |_, state| { - ParseExpressionAtPrecedence(1).parse(state) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseTypeAssertion; - -#[rustfmt::skip] -define_roblox_parser!( - ParseTypeAssertion, - TypeAssertion, - TokenReference, - |_, state| { - let (state, assertion_op) = ParseSymbol(Symbol::TwoColons).parse(state)?; - let (state, cast_to) = expect!( - state, - ParseTypeInfo(TypeInfoContext::None).parse(state), - "expected type in type assertion" - ); + // I think this only happens in error cases + prefix @ ast::Prefix::Expression(_) => { + ast::Var::Expression(Box::new(ast::VarExpression { prefix, suffixes })) + } + }, + }; - Ok((state, TypeAssertion { assertion_op, cast_to })) - } -); - -#[derive(Clone, Debug, PartialEq)] -struct ParseValue; -define_parser!(ParseValue, Expression, |_, state| parse_first_of!(state, { - ParseSymbol(Symbol::Nil) => Expression::Symbol, - ParseSymbol(Symbol::False) => Expression::Symbol, - ParseSymbol(Symbol::True) => Expression::Symbol, - ParseNumber => Expression::Number, - ParseStringLiteral => Expression::String, - ParseSymbol(Symbol::Ellipse) => Expression::Symbol, - ParseFunction => Expression::Function, - ParseTableConstructor => Expression::TableConstructor, - ParseFunctionCall => Expression::FunctionCall, - ParseVar => Expression::Var, - @#[cfg(feature = "roblox")] - ParseIfExpression => Expression::IfExpression, - @#[cfg(feature = "roblox")] - ParseInterpolatedString => Expression::InterpolatedString, -})); - -#[derive(Clone, Debug, Default, PartialEq)] -struct ParseStmt; -define_parser!(ParseStmt, Stmt, |_, state| parse_first_of!(state, { - ParseAssignment => Stmt::Assignment, - ParseFunctionCall => Stmt::FunctionCall, - ParseDo => Stmt::Do, - ParseWhile => Stmt::While, - ParseRepeat => Stmt::Repeat, - ParseIf => Stmt::If, - ParseNumericFor => Stmt::NumericFor, - ParseGenericFor => Stmt::GenericFor, - ParseFunctionDeclaration => Stmt::FunctionDeclaration, - ParseLocalFunction => Stmt::LocalFunction, - ParseLocalAssignment => Stmt::LocalAssignment, - @#[cfg(feature = "roblox")] - ParseCompoundAssignment => Stmt::CompoundAssignment, - @#[cfg(feature = "roblox")] - ParseExportedTypeDeclaration => Stmt::ExportedTypeDeclaration, - @#[cfg(feature = "roblox")] - ParseTypeDeclaration => Stmt::TypeDeclaration, - @#[cfg(feature = "lua52")] - ParseGoto => Stmt::Goto, - @#[cfg(feature = "lua52")] - ParseLabel => Stmt::Label, -})); - -#[derive(Clone, Debug, PartialEq)] -struct ParsePrefix; -define_parser!(ParsePrefix, Prefix, |_, state| parse_first_of!(state, { - ParseIntoBox(ParseParenExpression) => Prefix::Expression, - ParseIdentifier => Prefix::Name, -})); - -struct ParseIndex; -define_parser!( - ParseIndex, - Index, - |_, state| if let Ok((state, start_bracket)) = ParseSymbol(Symbol::LeftBracket).parse(state) { - let (state, expression) = - expect!(state, ParseExpression.parse(state), "expected expression"); - let (state, end_bracket) = expect!( - state, - ParseSymbol(Symbol::RightBracket).parse(state), - "expected ']'" - ); - Ok(( - state, - Index::Brackets { - brackets: ContainedSpan::new(start_bracket, end_bracket), - expression, - }, - )) - } else if let Ok((state, dot)) = ParseSymbol(Symbol::Dot).parse(state) { - let (state, name) = expect!(state, ParseIdentifier.parse(state), "expected name"); - Ok((state, Index::Dot { dot, name })) - } else { - Err(InternalAstError::NoMatch) - } -); - -#[derive(Clone, Debug, PartialEq)] -struct ParseFunctionArgs; -define_parser!( - ParseFunctionArgs, - FunctionArgs, - |_, state| if let Ok((state, left_paren)) = - keep_going!(ParseSymbol(Symbol::LeftParen).parse(state)) - { - let (state, arguments) = expect!( - state, - ZeroOrMoreDelimited(ParseExpression, ParseSymbol(Symbol::Comma), false).parse(state), - "expected arguments" - ); - let (state, right_paren) = expect!( - state, - ParseSymbol(Symbol::RightParen).parse(state), - "expected ')'" - ); - Ok(( - state, - FunctionArgs::Parentheses { - arguments, - parentheses: ContainedSpan::new(left_paren, right_paren), - }, - )) - } else if let Ok((state, table_constructor)) = keep_going!(ParseTableConstructor.parse(state)) { - Ok((state, FunctionArgs::TableConstructor(table_constructor))) - } else if let Ok((state, string)) = keep_going!(ParseStringLiteral.parse(state)) { - Ok((state, FunctionArgs::String(string))) - } else { - Err(InternalAstError::NoMatch) - } -); - -#[derive(Clone, Debug, PartialEq)] -struct ParseNumericFor; -define_parser!(ParseNumericFor, NumericFor, |_, state| { - let (mut state, for_token) = ParseSymbol(Symbol::For).parse(state)?; - - #[cfg(not(feature = "roblox"))] - let (state, index_variable) = expect!(state, ParseIdentifier.parse(state), "expected names"); - - #[cfg(feature = "roblox")] - let (state, (index_variable, type_specifier)) = - expect!(state, ParseNameWithType.parse(state), "expected names"); - - let (state, equal_token) = ParseSymbol(Symbol::Equal).parse(state)?; // Numeric fors run before generic fors, so we can't guarantee this - let (state, start) = expect!( - state, - ParseExpression.parse(state), - "expected start expression" - ); - let (state, start_end_comma) = expect!( - state, - ParseSymbol(Symbol::Comma).parse(state), - "expected comma" - ); - let (state, end) = expect!( - state, - ParseExpression.parse(state), - "expected end expression" - ); - let (state, step, end_step_comma) = - if let Ok((state, comma)) = ParseSymbol(Symbol::Comma).parse(state) { - let (state, expression) = expect!( - state, - ParseExpression.parse(state), - "expected limit expression" - ); - (state, Some(expression), Some(comma)) - } else { - (state, None, None) - }; - let (state, do_token) = expect!(state, ParseSymbol(Symbol::Do).parse(state), "expected 'do'"); - let (state, block) = expect!(state, ParseBlock.parse(state), "expected block"); - let (state, end_token) = expect!( - state, - ParseSymbol(Symbol::End).parse(state), - "expected 'end'" - ); - - Ok(( - state, - NumericFor { - for_token, - index_variable, - equal_token, - start, - start_end_comma, - end, - end_step_comma, - step, - do_token, - block, - end_token, - #[cfg(feature = "roblox")] - type_specifier, - }, - )) -}); + match state.current() { + #[cfg(feature = "luau")] + // Compound Assignment + Ok(token) + if state.lua_version().has_luau() + && (token.is_symbol(Symbol::PlusEqual) + || token.is_symbol(Symbol::MinusEqual) + || token.is_symbol(Symbol::StarEqual) + || token.is_symbol(Symbol::SlashEqual) + || token.is_symbol(Symbol::DoubleSlashEqual) + || token.is_symbol(Symbol::PercentEqual) + || token.is_symbol(Symbol::CaretEqual) + || token.is_symbol(Symbol::TwoDotsEqual)) => + { + let compound_operator = state.consume().unwrap(); -#[derive(Clone, Debug, PartialEq)] -struct ParseGenericFor; -define_parser!(ParseGenericFor, GenericFor, |_, state| { - let (mut state, for_token) = ParseSymbol(Symbol::For).parse(state)?; + let ParserResult::Value(expr) = parse_expression(state) else { + state.token_error(compound_operator, "expected expression to set to"); + return ParserResult::LexerMoved; + }; - let mut names; - let mut type_specifiers = Vec::new(); + return ParserResult::Value(StmtVariant::Stmt(ast::Stmt::CompoundAssignment( + ast::CompoundAssignment { + lhs: var, + compound_operator: ast::CompoundOp::from_token(compound_operator), + rhs: expr, + }, + ))); + } - if cfg!(feature = "roblox") { - names = Punctuated::new(); + Ok(token) if token.is_symbol(Symbol::Comma) || token.is_symbol(Symbol::Equal) => {} + + Ok(token) => { + // Check if the consumed token is a potential context-sensitive keyword + #[cfg(feature = "luau")] + if state.lua_version().has_luau() { + if let ast::Var::Name(token) = var { + match token.token_type() { + TokenType::Identifier { identifier } + if identifier.as_str() == "export" => + { + let export_token = token; + + let type_token = match state.current() { + Ok(token) if matches!(token.token_type(), TokenType::Identifier { identifier } if identifier.as_str() == "type") => { + state.consume().unwrap() + } + + Ok(token) => { + state.token_error_ranged( + token.clone(), + "expected `type` after `export`", + &export_token, + &token.clone(), + ); + + return ParserResult::LexerMoved; + } + + Err(()) => return ParserResult::LexerMoved, + }; + + return ParserResult::Value(StmtVariant::Stmt( + ast::Stmt::ExportedTypeDeclaration( + ast::ExportedTypeDeclaration { + export_token, + type_declaration: match expect_type_declaration( + state, type_token, + ) { + Ok(type_declaration) => type_declaration, + Err(()) => return ParserResult::LexerMoved, + }, + }, + ), + )); + } + TokenType::Identifier { identifier } + if identifier.as_str() == "type" => + { + let type_token = token; + + return ParserResult::Value(StmtVariant::Stmt( + ast::Stmt::TypeDeclaration( + match expect_type_declaration(state, type_token) { + Ok(type_declaration) => type_declaration, + Err(()) => return ParserResult::LexerMoved, + }, + ), + )); + } + TokenType::Identifier { identifier } + if identifier.as_str() == "continue" => + { + let continue_token = token; + return ParserResult::Value(StmtVariant::LastStmt( + ast::LastStmt::Continue(continue_token), + )); + } + _ => (), + } + } + } - let (new_state, full_name_list) = expect!( - state, - OneOrMore(ParseNameWithType, ParseSymbol(Symbol::Comma), false).parse(state), - "expected names" - ); + state.token_error( + token.clone(), + "unexpected expression when looking for a statement", + ); - for mut pair in full_name_list.into_pairs() { - type_specifiers.push(pair.value_mut().1.take()); - names.push(pair.map(|(name, _)| name)); - } + return ParserResult::LexerMoved; + } - state = new_state; - } else { - let (new_state, new_names) = expect!( - state, - OneOrMore(ParseIdentifier, ParseSymbol(Symbol::Comma), false).parse(state), - "expected names" - ); + Err(()) => return ParserResult::LexerMoved, + }; - state = new_state; - names = new_names; - } + let mut var_list = Punctuated::new(); + var_list.push(Pair::End(var)); - let (state, in_token) = expect!(state, ParseSymbol(Symbol::In).parse(state), "expected 'in'"); // Numeric fors run before here, so there has to be an in - let (state, expr_list) = expect!( - state, - OneOrMore(ParseExpression, ParseSymbol(Symbol::Comma), false).parse(state), - "expected expression" - ); - let (state, do_token) = expect!(state, ParseSymbol(Symbol::Do).parse(state), "expected 'do'"); - let (state, block) = expect!(state, ParseBlock.parse(state), "expected block"); - let (state, end_token) = expect!( - state, - ParseSymbol(Symbol::End).parse(state), - "expected 'end'" - ); - Ok(( - state, - GenericFor { - for_token, - names, - in_token, - expr_list, - do_token, - block, - end_token, - #[cfg(feature = "roblox")] - type_specifiers, - }, - )) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseIf; -define_parser!(ParseIf, If, |_, state| { - let (state, if_token) = ParseSymbol(Symbol::If).parse(state)?; - let (state, condition) = expect!(state, ParseExpression.parse(state), "expected condition"); - let (state, then_token) = expect!( - state, - ParseSymbol(Symbol::Then).parse(state), - "expected 'then'" - ); - let (mut state, block) = expect!(state, ParseBlock.parse(state), "expected block"); - - let mut else_ifs = Vec::new(); - while let Ok((new_state, else_if_token)) = ParseSymbol(Symbol::ElseIf).parse(state) { - let (new_state, condition) = expect!( - state, - ParseExpression.parse(new_state), - "expected condition" - ); - let (new_state, then_token) = expect!( - state, - ParseSymbol(Symbol::Then).parse(new_state), - "expected 'then'" - ); - let (new_state, block) = expect!(state, ParseBlock.parse(new_state), "expected block"); - state = new_state; - else_ifs.push(ElseIf { - else_if_token, - condition, - then_token, - block, - }); - } + loop { + let next_comma = match state.current() { + Ok(token) if token.is_symbol(Symbol::Comma) => state.consume().unwrap(), + Ok(_) => break, + Err(()) => return ParserResult::LexerMoved, + }; - let (state, else_token, r#else) = - if let Ok((state, else_token)) = ParseSymbol(Symbol::Else).parse(state) { - let (state, block) = expect!(state, ParseBlock.parse(state), "expected block"); - (state, Some(else_token), Some(block)) - } else { - (state, None, None) - }; + let (next_prefix, next_suffixes) = match parse_prefix_and_suffixes(state) { + ParserResult::Value((prefix, suffixes)) => (prefix, suffixes), - let (state, end_token) = expect!( - state, - ParseSymbol(Symbol::End).parse(state), - "expected 'end'" - ); + ParserResult::LexerMoved => { + break; + } - Ok(( - state, - If { - if_token, - condition, - then_token, - block, - else_token, - r#else, - else_if: if else_ifs.is_empty() { - None - } else { - Some(else_ifs) - }, - end_token, - }, - )) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseWhile; -define_parser!(ParseWhile, While, |_, state| { - let (state, while_token) = ParseSymbol(Symbol::While).parse(state)?; - let (state, condition) = expect!(state, ParseExpression.parse(state), "expected condition"); - let (state, do_token) = expect!(state, ParseSymbol(Symbol::Do).parse(state), "expected 'do'"); - let (state, block) = expect!(state, ParseBlock.parse(state), "expected block"); - let (state, end_token) = expect!( - state, - ParseSymbol(Symbol::End).parse(state), - "expected 'end'" - ); - Ok(( - state, - While { - while_token, - condition, - do_token, - block, - end_token, - }, - )) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseRepeat; -define_parser!(ParseRepeat, Repeat, |_, state| { - let (state, repeat_token) = ParseSymbol(Symbol::Repeat).parse(state)?; - let (state, block) = expect!(state, ParseBlock.parse(state), "expected block"); - let (state, until_token) = expect!( - state, - ParseSymbol(Symbol::Until).parse(state), - "expected 'until'" - ); - let (state, until) = expect!(state, ParseExpression.parse(state), "expected condition"); - Ok(( - state, - Repeat { - repeat_token, - block, - until_token, - until, - }, - )) -}); - -struct ParseMethodCall; -define_parser!(ParseMethodCall, MethodCall, |_, state| { - let (state, colon_token) = ParseSymbol(Symbol::Colon).parse(state)?; - let (state, name) = expect!(state, ParseIdentifier.parse(state), "expected method"); - let (state, args) = expect!(state, ParseFunctionArgs.parse(state), "expected args"); - Ok(( - state, - MethodCall { - colon_token, - name, - args, - }, - )) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseCall; -define_parser!(ParseCall, Call, |_, state| parse_first_of!(state, { - ParseFunctionArgs => Call::AnonymousCall, - ParseMethodCall => Call::MethodCall, -})); - -#[derive(Clone, Debug, PartialEq)] -struct ParseFunctionBody; -#[rustfmt::skip] -define_parser!(ParseFunctionBody, FunctionBody, |_, state| { - #[cfg(feature = "roblox")] - let (state, generics) = - if let Ok((state, generics)) = keep_going!(ParseGenericDeclaration.parse(state)) { - (state, Some(generics)) - } else { - (state, None) - }; + ParserResult::NotFound => { + state.token_error(next_comma, "expected another variable"); + break; + } + }; - let (mut state, start_parenthese) = expect!( - state, - ParseSymbol(Symbol::LeftParen).parse(state), - "expected '('" - ); + match next_suffixes.last() { + Some(ast::Suffix::Call(call)) => { + state.token_error( + call.tokens().last().unwrap().clone(), + "can't assign to the result of a call", + ); + break; + } - let mut parameters = Punctuated::new(); - let mut name_list = None; - let mut type_specifiers = Vec::new(); + Some(ast::Suffix::Index(_)) => { + var_list.push_punctuated( + ast::Var::Expression(Box::new(ast::VarExpression { + prefix: next_prefix, + suffixes: next_suffixes, + })), + next_comma, + ); + } - if cfg!(feature = "roblox") { - if let Ok((new_state, full_name_list)) = keep_going!( - OneOrMore(ParseNameWithType, ParseSymbol(Symbol::Comma), false).parse(state) - ) { - let mut new_name_list = Punctuated::new(); + None => match next_prefix { + ast::Prefix::Name(name) => { + var_list.push_punctuated(ast::Var::Name(name), next_comma); + } - for mut pair in full_name_list.into_pairs() { - type_specifiers.push(pair.value_mut().1.take()); - new_name_list.push(pair.map(|(name, _)| name)); + prefix @ ast::Prefix::Expression(_) => var_list.push_punctuated( + ast::Var::Expression(Box::new(ast::VarExpression { + prefix, + suffixes: next_suffixes, + })), + next_comma, + ), + }, + } } - state = new_state; - name_list = Some(new_name_list); - } - } else if let Ok((new_state, new_name_list)) = keep_going!( - OneOrMore(ParseIdentifier, ParseSymbol(Symbol::Comma), false).parse(state) - ) { - state = new_state; - name_list = Some(new_name_list); - } + let Some(equal_token) = state.require(Symbol::Equal, "expected `=` after name") else { + return ParserResult::LexerMoved; + }; - if let Some(names) = name_list { - parameters.extend(names.into_pairs().map(|pair| { - let tuple = pair.into_tuple(); - Pair::new(Parameter::Name(tuple.0), tuple.1) - })); + let expr_list = match parse_expression_list(state) { + ParserResult::Value(expr_list) => expr_list, - if let Ok((new_state, comma)) = ParseSymbol(Symbol::Comma).parse(state) { - if let Ok((new_state, ellipse)) = ParseSymbol(Symbol::Ellipse).parse(new_state) { - state = new_state; + ParserResult::NotFound => { + state.token_error(equal_token.clone(), "expected values to set to"); + Punctuated::new() + } - let mut last_parameter = parameters.pop().expect("comma parsed and accepted, but no arguments before it?"); - last_parameter = Pair::new(last_parameter.into_value(), Some(comma)); - parameters.push(last_parameter); + ParserResult::LexerMoved => Punctuated::new(), + }; - parameters.push(Pair::new(Parameter::Ellipse(ellipse), None)); + ParserResult::Value(StmtVariant::Stmt(ast::Stmt::Assignment(ast::Assignment { + var_list, + equal_token, + expr_list, + }))) + } - // Parse ellipse type if in Luau - if cfg!(feature = "roblox") { - if let Ok((new_state, type_specifier)) = ParseTypeSpecifier(TypeInfoContext::VarArgSpecifier).parse(state) { - state = new_state; - type_specifiers.push(Some(type_specifier)); - } else { - type_specifiers.push(None); - } + #[cfg(feature = "lua52")] + TokenType::Symbol { + symbol: Symbol::Goto, + } => { + debug_assert!(state.lua_version().has_lua52()); + + let goto_token = state.consume().unwrap(); + + match state.current() { + Ok(token) if matches!(token.token_type(), TokenType::Identifier { .. }) => { + let label_name = state.consume().unwrap(); + ParserResult::Value(StmtVariant::Stmt(ast::Stmt::Goto(ast::Goto { + goto_token, + label_name, + }))) } - } - } - } else if let Ok((new_state, ellipse)) = ParseSymbol(Symbol::Ellipse).parse(state) { - state = new_state; - parameters.push(Pair::new(Parameter::Ellipse(ellipse), None)); - // Parse ellipse type if in Luau - if cfg!(feature = "roblox") { - if let Ok((new_state, type_specifier)) = ParseTypeSpecifier(TypeInfoContext::VarArgSpecifier).parse(state) { - state = new_state; - type_specifiers.push(Some(type_specifier)); - } else { - type_specifiers.push(None); + Ok(token) => { + state.token_error_ranged( + token.clone(), + "expected label name after `goto`", + &goto_token, + &token.clone(), + ); + + ParserResult::LexerMoved + } + + Err(()) => { + state.token_error(goto_token, "expected label name after `goto`"); + ParserResult::LexerMoved + } } } - } - let (state, end_parenthese) = expect!( - state, - ParseSymbol(Symbol::RightParen).parse(state), - "expected ')'" - ); + #[cfg(feature = "lua52")] + TokenType::Symbol { + symbol: Symbol::TwoColons, + } if state.lua_version().has_lua52() => { + let left_colons = state.consume().unwrap(); - #[cfg_attr(not(feature = "roblox"), allow(unused_variables))] - let (state, return_type) = if let Ok((state, return_type)) = ParseTypeSpecifier(TypeInfoContext::ReturnType).parse(state) { - (state, Some(return_type)) - } else { - (state, None) - }; - - let (state, block) = expect!(state, ParseBlock.parse(state), "expected block"); - let (state, end_token) = expect!( - state, - ParseSymbol(Symbol::End).parse(state), - "expected 'end'" - ); - Ok(( - state, - FunctionBody { - #[cfg(feature = "roblox")] - generics, - parameters_parentheses: ContainedSpan::new(start_parenthese, end_parenthese), - parameters, - block, - end_token, - #[cfg(feature = "roblox")] - type_specifiers, - #[cfg(feature = "roblox")] - return_type, - }, - )) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseFunction; -define_parser!(ParseFunction, (TokenReference, FunctionBody), |_, state| { - let (state, token) = ParseSymbol(Symbol::Function).parse(state)?; - let (state, body) = expect!( - state, - ParseFunctionBody.parse(state), - "expected function body" - ); - Ok((state, (token, body))) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseSuffix; -define_parser!(ParseSuffix, Suffix, |_, state| parse_first_of!(state, { - ParseCall => Suffix::Call, - ParseIndex => Suffix::Index, -})); - -#[derive(Clone, Debug, PartialEq)] -struct ParseVarExpression; -define_parser!(ParseVarExpression, Box, |_, state| { - let (state, prefix) = ParsePrefix.parse(state)?; - let (state, suffixes) = ZeroOrMore(ParseSuffix).parse(state)?; - - if let Some(Suffix::Index(_)) = suffixes.last() { - Ok((state, Box::new(VarExpression { prefix, suffixes }))) - } else { - Err(InternalAstError::NoMatch) - } -}); - -#[derive(Clone, Debug, Default, PartialEq)] -struct ParseVar; -define_parser!(ParseVar, Var, |_, state| parse_first_of!(state, { - ParseVarExpression => Var::Expression, - ParseIdentifier => Var::Name, -})); - -#[derive(Clone, Debug, Default, PartialEq)] -struct ParseAssignment; -define_parser!(ParseAssignment, Assignment, |_, state| { - let (state, var_list) = OneOrMore(ParseVar, ParseSymbol(Symbol::Comma), false).parse(state)?; - let (state, equal_token) = ParseSymbol(Symbol::Equal).parse(state)?; - let (state, expr_list) = expect!( - state, - OneOrMore(ParseExpression, ParseSymbol(Symbol::Comma), false).parse(state), - "expected values" - ); - - Ok(( - state, - Assignment { - var_list, - equal_token, - expr_list, - }, - )) -}); - -#[derive(Clone, Debug, Default, PartialEq)] -struct ParseLocalFunction; -define_parser!(ParseLocalFunction, LocalFunction, |_, state| { - let (state, local_token) = ParseSymbol(Symbol::Local).parse(state)?; - let (state, function_token) = ParseSymbol(Symbol::Function).parse(state)?; - let (state, name) = expect!(state, ParseIdentifier.parse(state), "expected name"); - let (state, body) = ParseFunctionBody.parse(state)?; - Ok(( - state, - LocalFunction { - local_token, - function_token, - name, - body, - }, - )) -}); + let name = match state.current() { + Ok(token) if matches!(token.token_type(), TokenType::Identifier { .. }) => { + state.consume().unwrap() + } -#[derive(Clone, Debug, Default, PartialEq)] -struct ParseLocalAssignment; -define_parser!(ParseLocalAssignment, LocalAssignment, |_, state| { - let (mut state, local_token) = ParseSymbol(Symbol::Local).parse(state)?; + Ok(token) => { + state.token_error_ranged( + token.clone(), + "expected label name after `::`", + &left_colons, + &token.clone(), + ); - let mut name_list = Punctuated::new(); - #[cfg(feature = "lua54")] - let mut attributes = Vec::new(); - #[cfg(feature = "roblox")] - let mut type_specifiers = Vec::new(); + return ParserResult::LexerMoved; + } - loop { - let (new_state, name) = expect!(state, ParseIdentifier.parse(state), "expected name"); - state = new_state; + Err(()) => return ParserResult::LexerMoved, + }; - #[cfg(feature = "lua54")] - if let Ok((new_state, attribute)) = keep_going!(ParseAttribute.parse(state)) { - attributes.push(Some(attribute)); - state = new_state; - } else { - attributes.push(None); + let right_colons = match state.require(Symbol::TwoColons, "expected `::` after label") { + Some(token) => token, + None => TokenReference::symbol("::").unwrap(), + }; + + ParserResult::Value(StmtVariant::Stmt(ast::Stmt::Label(ast::Label { + left_colons, + name, + right_colons, + }))) } - #[cfg(feature = "roblox")] - if let Ok((new_state, type_specifier)) = - keep_going!(ParseTypeSpecifier(TypeInfoContext::None).parse(state)) - { - type_specifiers.push(Some(type_specifier)); - state = new_state; - } else { - type_specifiers.push(None); + _ => ParserResult::NotFound, + } +} + +fn parse_last_stmt( + state: &mut ParserState, +) -> ParserResult<(ast::LastStmt, Option)> { + let last_stmt = match state.current() { + Ok(token) if token.is_symbol(Symbol::Return) => { + let return_token = state.consume().unwrap(); + + let expr_list = match parse_expression_list(state) { + ParserResult::Value(expr_list) => expr_list, + ParserResult::LexerMoved | ParserResult::NotFound => Punctuated::new(), + }; + + ast::LastStmt::Return(ast::Return { + token: return_token, + returns: expr_list, + }) } - if let Ok((new_state, comma)) = ParseSymbol(Symbol::Comma).parse(state) { - name_list.push(Pair::Punctuated(name, comma)); - state = new_state; - } else { - name_list.push(Pair::End(name)); - break; + Ok(token) if token.is_symbol(Symbol::Break) => { + let break_token = state.consume().unwrap(); + ast::LastStmt::Break(break_token) } - } - let ((state, expr_list), equal_token) = match ParseSymbol(Symbol::Equal).parse(state) { - Ok((state, equal_token)) => ( - OneOrMore(ParseExpression, ParseSymbol(Symbol::Comma), false) - .parse(state) - .map_err(|_| InternalAstError::UnexpectedToken { - token: (*state.peek()).to_owned(), - additional: Some(Cow::from("expected expression")), - })?, - Some(equal_token), - ), - Err(InternalAstError::NoMatch) => ((state, Punctuated::new()), None), - Err(other) => return Err(other), - }; - - Ok(( - state, - LocalAssignment { - local_token, - #[cfg(feature = "roblox")] - type_specifiers, - name_list, - #[cfg(feature = "lua54")] - attributes, - equal_token, - expr_list, - }, - )) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseDo; -define_parser!(ParseDo, Do, |_, state| { - let (state, do_token) = ParseSymbol(Symbol::Do).parse(state)?; - let (state, block) = expect!(state, ParseBlock.parse(state), "expected block"); - let (state, end_token) = expect!( - state, - ParseSymbol(Symbol::End).parse(state), - "expected 'end'" - ); - - Ok(( - state, - Do { - do_token, - block, - end_token, - }, - )) -}); + _ => return ParserResult::NotFound, + }; -#[derive(Clone, Debug, PartialEq)] -struct ParseFunctionCall; -define_parser!(ParseFunctionCall, FunctionCall, |_, state| { - let (state, prefix) = ParsePrefix.parse(state)?; - let (state, suffixes) = ZeroOrMore(ParseSuffix).parse(state)?; + let semicolon = state.consume_if(Symbol::Semicolon); - if let Some(Suffix::Call(_)) = suffixes.last() { - Ok((state, FunctionCall { prefix, suffixes })) - } else { - Err(InternalAstError::NoMatch) - } -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseFunctionName; -define_parser!(ParseFunctionName, FunctionName, |_, state| { - let (state, names) = - OneOrMore(ParseIdentifier, ParseSymbol(Symbol::Dot), false).parse(state)?; - let (state, colon_name) = if let Ok((state, colon)) = ParseSymbol(Symbol::Colon).parse(state) { - let (state, colon_name) = - expect!(state, ParseIdentifier.parse(state), "expected method name"); - (state, Some((colon, colon_name))) - } else { - (state, None) - }; - - Ok((state, FunctionName { names, colon_name })) -}); - -#[derive(Clone, Debug, Default, PartialEq)] -struct ParseFunctionDeclaration; -define_parser!(ParseFunctionDeclaration, FunctionDeclaration, |_, state| { - let (state, function_token) = ParseSymbol(Symbol::Function).parse(state)?; - let (state, name) = expect!( - state, - ParseFunctionName.parse(state), - "expected function name" - ); - let (state, body) = expect!( - state, - ParseFunctionBody.parse(state), - "expected function body" - ); - Ok(( - state, - FunctionDeclaration { - function_token, - name, - body, - }, - )) -}); - -#[derive(Clone, Debug, Default, PartialEq)] -struct ParseIdentifier; -#[rustfmt::skip] -define_parser!(ParseIdentifier, TokenReference, |_, state| { - let next_token = state.peek(); - match next_token.token_kind() { - TokenKind::Identifier => Ok(( - state.advance().ok_or(InternalAstError::NoMatch)?, - next_token.clone(), - )), - _ => Err(InternalAstError::NoMatch), - } -}); - -#[derive(Clone, Copy, Debug, PartialEq)] -enum TypeInfoContext { - /// A standard type info, with no context - #[cfg(feature = "roblox")] - None, - /// A type inside of parentheses, either for the parameters in a `TypeInfo::Callback`, or for a `TypeInfo::Tuple` - /// Variadic type infos are only permitted inside of here - #[cfg(feature = "roblox")] - ParenthesesType, - /// The return type of a function declaration or callback type, such as `function foo(bar) -> number`. - /// In addition to standard types, type packs/variadic type packs are allowed here - ReturnType, - /// A type specifier for the variadic argument `...` in a function definition parameter list - /// In these cases, we are allowed a generic variadic pack `T...` to be specified - VarArgSpecifier, - /// An argument passed into a generic type, e.g. `string` or `...number` in `type X = Foo`. - /// In these cases, generic type packs, variadic type packs, and explicit type packs (using parentheses) are allowed - #[cfg(feature = "roblox")] - GenericArgument, + ParserResult::Value((last_stmt, semicolon)) } -// Roblox Types -#[derive(Clone, Debug, PartialEq)] -struct ParseNameWithType; -define_roblox_parser!( - ParseNameWithType, - (TokenReference, Option), - (TokenReference, Option), - |_, state| { - let (state, name) = ParseIdentifier.parse(state)?; - let (state, type_specifier) = if let Ok((state, type_specifier)) = - keep_going!(ParseTypeSpecifier(TypeInfoContext::None).parse(state)) - { - (state, Some(type_specifier)) - } else { - (state, None) - }; +fn expect_function_name(state: &mut ParserState) -> ParserResult { + let mut names = Punctuated::new(); - Ok((state, (name, type_specifier))) - } -); - -#[derive(Clone, Debug, PartialEq)] -struct ParseTypeSpecifier(TypeInfoContext); -define_roblox_parser!( - ParseTypeSpecifier, - TypeSpecifier, - TokenReference, - |this, state| { - let (state, punctuation) = ParseSymbol(Symbol::Colon).parse(state)?; - let (state, type_info) = expect!( - state, - ParseTypeInfo(this.0).parse(state), - "expected type after colon" - ); + let name = match state.current() { + Ok(token) if matches!(token.token_type(), TokenType::Identifier { .. }) => { + state.consume().unwrap() + } - Ok(( - state, - TypeSpecifier { - punctuation, - type_info, - }, - )) - } -); - -#[derive(Clone, Debug, PartialEq)] -struct ParseGenericDeclaration; -define_roblox_parser!( - ParseGenericDeclaration, - GenericDeclaration, - TokenReference, - |_, state| { - let (state, start_arrow) = ParseSymbol(Symbol::LessThan).parse(state)?; - let mut generics: Punctuated = Punctuated::new(); - - let mut have_seen_pack = false; // We have seen a generic type pack parameter. We can only now accept generic type pack parameters - let mut have_seen_default = false; // We have seen a default type, all future parameters must define a default type - - let mut loop_state = state; - loop { - let (state, name) = expect!( - loop_state, - ParseIdentifier.parse(loop_state), - "expected name" - ); + Ok(token) => { + state.token_error(token.clone(), "expected function name"); + return ParserResult::NotFound; + } - // Look to see if is a type pack - let (state, ellipse) = if let Ok((state, ellipse)) = - keep_going!(ParseSymbol(Symbol::Ellipse).parse(state)) - { - have_seen_pack = true; - (state, Some(ellipse)) - } else { - // Must only be type packs after we have seen one - if have_seen_pack { - return Err(InternalAstError::UnexpectedToken { - token: state.peek().clone(), - additional: Some("generic types come before generic type packs".into()), - }); - }; + Err(()) => return ParserResult::NotFound, + }; - (state, None) - }; + names.push(Pair::End(name)); - // Look to see if a default type has been specified - let (state, default) = - if let Ok((state, equals)) = keep_going!(ParseSymbol(Symbol::Equal).parse(state)) { - have_seen_default = true; + loop { + let middle_token = match state.current() { + Ok(token) if token.is_symbol(Symbol::Colon) || token.is_symbol(Symbol::Dot) => { + state.consume().unwrap() + } + Ok(_) => break, + Err(()) => return ParserResult::LexerMoved, + }; - // If we are parsing a type pack, allow type pack default types - let parse_context = if ellipse.is_some() { - TypeInfoContext::GenericArgument - } else { - TypeInfoContext::None - }; + let name = match state.current() { + Ok(token) if matches!(token.token_type(), TokenType::Identifier { .. }) => { + state.consume().unwrap() + } - let (state, type_info) = expect!( - state, - ParseTypeInfo(parse_context).parse(state), - "expected type after `=`" - ); + Ok(token) => { + state.token_error( + token.clone(), + format!("expected name after `{}`", middle_token.token()), + ); + return ParserResult::NotFound; + } - (state, Some((equals, type_info))) - } else { - // Defaults must always be specified once one has been - if have_seen_default { - return Err(InternalAstError::UnexpectedToken { - token: state.peek().clone(), - additional: Some("expected default type after type name".into()), - }); - } - (state, None) - }; + Err(()) => { + return ParserResult::LexerMoved; + } + }; - let parameter = match ellipse { - Some(ellipse) => GenericParameterInfo::Variadic { name, ellipse }, - None => GenericParameterInfo::Name(name), - }; - let declaration_parameter = GenericDeclarationParameter { parameter, default }; + if middle_token.is_symbol(Symbol::Dot) { + names.push_punctuated(name, middle_token); + } else if middle_token.is_symbol(Symbol::Colon) { + return ParserResult::Value(ast::FunctionName { + names, + colon_name: Some((middle_token, name)), + }); + } else { + unreachable!(); + } + } - if let Ok((state, punctuation)) = keep_going!(ParseSymbol(Symbol::Comma).parse(state)) { - generics.push(Pair::Punctuated(declaration_parameter, punctuation)); - loop_state = state; - } else { - generics.push(Pair::End(declaration_parameter)); - loop_state = state; - break; - } + ParserResult::Value(ast::FunctionName { + names, + colon_name: None, + }) +} + +fn expect_function_declaration( + state: &mut ParserState, + function_token: TokenReference, +) -> Result { + let function_name = match expect_function_name(state) { + ParserResult::Value(name) => name, + ParserResult::NotFound | ParserResult::LexerMoved => return Err(()), + }; + + let function_body = match parse_function_body(state) { + ParserResult::Value(body) => body, + + ParserResult::LexerMoved => ast::FunctionBody::new(), + + ParserResult::NotFound => { + state.token_error(function_token.clone(), "expected a function body"); + ast::FunctionBody::new() } + }; - let (state, end_arrow) = expect!( - loop_state, - ParseSymbol(Symbol::GreaterThan).parse(loop_state), - "expected `>` to match `<`" - ); + Ok(ast::FunctionDeclaration { + function_token, + name: function_name, + body: function_body, + }) +} - Ok(( +fn expect_for_stmt(state: &mut ParserState, for_token: TokenReference) -> Result { + let name_list = match parse_name_list(state) { + ParserResult::Value(name_list) => name_list, + ParserResult::NotFound => { + state.token_error(for_token, "expected name after `for`"); + return Err(()); + } + ParserResult::LexerMoved => return Err(()), + }; + + let current_token = match state.current() { + Ok(token) => token, + Err(()) => return Err(()), + }; + + debug_assert!(!name_list.is_empty()); + + if name_list.len() == 1 && current_token.is_symbol(Symbol::Equal) { + return Ok(ast::Stmt::NumericFor(expect_numeric_for_stmt( state, - GenericDeclaration { - arrows: ContainedSpan::new(start_arrow, end_arrow), - generics, - }, - )) + for_token, + name_list.into_iter().next().unwrap(), + )?)); } -); -// Outside of cfg_if for formatting...:( -#[cfg(feature = "roblox")] -#[allow(clippy::result_large_err)] -fn parse_interpolated_string( - state: ParserState<'_>, -) -> Result<(ParserState<'_>, InterpolatedString), InternalAstError> { - let mut current = state.peek().clone(); + let in_token = match current_token { + token if token.is_symbol(Symbol::In) => state.consume().unwrap(), + token => { + state.token_error(token.clone(), "expected `in` after name list"); + return Err(()); + } + }; - let (mut state, kind) = match ¤t.token_type { - TokenType::InterpolatedString { kind, .. } => ( - state.advance().expect( - "we just peeked an interpolated string literal, and now can't advance to it", - ), - kind, - ), + let expressions = match parse_expression_list(state) { + ParserResult::Value(expressions) => expressions, + ParserResult::NotFound => { + state.token_error(in_token, "expected expressions after `in`"); + return Err(()); + } + ParserResult::LexerMoved => return Err(()), + }; - _ => return Err(InternalAstError::NoMatch), + let Some(do_token) = state.require(Symbol::Do, "expected `do` after expression list") else { + return Ok(ast::Stmt::GenericFor(ast::GenericFor { + for_token, + names: name_list + .clone() + .into_pairs() + .map(|pair| pair.map(|name| name.name)) + .collect(), + #[cfg(feature = "luau")] + type_specifiers: name_list + .into_iter() + .map(|name| name.type_specifier) + .collect(), + in_token, + expr_list: expressions, + do_token: TokenReference::basic_symbol("do"), + block: ast::Block::new(), + end_token: TokenReference::basic_symbol("end"), + })); }; - match kind { - InterpolatedStringKind::Simple => Ok(( - state, - InterpolatedString { - segments: Vec::new(), - last_string: current, - }, - )), + let (block, end) = match expect_block_with_end(state, "for loop", &do_token) { + Ok(block) => block, + Err(()) => (ast::Block::new(), TokenReference::basic_symbol("end")), + }; - InterpolatedStringKind::Begin => { - let mut segments = Vec::new(); - let last_string; + Ok(ast::Stmt::GenericFor(ast::GenericFor { + for_token, + names: name_list + .clone() + .into_pairs() + .map(|pair| pair.map(|name| name.name)) + .collect(), + #[cfg(feature = "luau")] + type_specifiers: name_list + .into_iter() + .map(|name| name.type_specifier) + .collect(), + in_token, + expr_list: expressions, + do_token, + block, + end_token: end, + })) +} - loop { - // Could be done in the tokenizer, but our error tooling there is a lot worse - if current.trailing_trivia.is_empty() - && matches!( - state.peek().token_type, - TokenType::Symbol { - symbol: Symbol::LeftBrace - } - ) - { - return Err(InternalAstError::UnexpectedToken { - token: state.peek().clone(), - additional: Some("unexpected double brace for interpolated string. try \\{ if you meant to escape".into()), - }); - } +fn expect_numeric_for_stmt( + state: &mut ParserState, + for_token: TokenReference, + index_variable: Name, +) -> Result { + let equal_token = state.consume().unwrap(); + debug_assert!(equal_token.is_symbol(Symbol::Equal)); + + let start = match parse_expression(state) { + ParserResult::Value(start) => start, + ParserResult::NotFound => { + state.token_error(equal_token, "expected start expression after `=`"); + return Err(()); + } + ParserResult::LexerMoved => return Err(()), + }; - let expression; - (state, expression) = expect!( - state, - ParseExpression.parse(state), - "expected expression in interpolated string" - ); + let Some(start_end_comma) = state.require(Symbol::Comma, "expected `,` after start expression") + else { + return Err(()); + }; - segments.push(InterpolatedStringSegment { - expression, - literal: current.clone(), - }); + let end = match parse_expression(state) { + ParserResult::Value(end) => end, + ParserResult::NotFound => { + state.token_error(start_end_comma, "expected end expression after `,`"); + return Err(()); + } + ParserResult::LexerMoved => return Err(()), + }; - current = state.peek().clone(); + // rewrite todo: this can recover into a numeric for loop with no step (or simulate the do..end) + let (end_step_comma, step) = match state.consume_if(Symbol::Comma) { + Some(end_step_comma) => match parse_expression(state) { + ParserResult::Value(step) => (Some(end_step_comma), Some(step)), + ParserResult::NotFound => { + state.token_error(start_end_comma, "expected step expression after `,`"); + return Err(()); + } + ParserResult::LexerMoved => return Err(()), + }, - if matches!( - current.token_type, - TokenType::InterpolatedString { - kind: InterpolatedStringKind::End, - .. - } - ) { - last_string = current; - return Ok(( - state.advance().expect( - "we just peeked an interpolated string literal to end the formatted string, and now can't advance to it", - ), - InterpolatedString { - segments, - last_string, - }, - )); - } + None => (None, None), + }; - // `hello {"world" "wait"}` - if current.token_kind() != TokenKind::InterpolatedString { - return Err(InternalAstError::UnexpectedToken { - additional: Some( - "interpolated string parameter can only contain an expression".into(), - ), - token: current.clone(), - }); - } + let Some(do_token) = state.require(Symbol::Do, "expected `do` after step expression") else { + return Err(()); + }; - state = match state.advance() { - Some(state) => state, - None => { - return Err(InternalAstError::UnexpectedToken { - token: current, - additional: Some("expected `}` to end interpolated string".into()), - }) - } - }; - } + let (block, end_token) = match expect_block_with_end(state, "numeric for loop", &do_token) { + Ok(block) => block, + Err(()) => (ast::Block::new(), TokenReference::basic_symbol("end")), + }; + + Ok(ast::NumericFor { + for_token, + index_variable: index_variable.name, + #[cfg(feature = "luau")] + type_specifier: index_variable.type_specifier, + equal_token, + start, + start_end_comma, + end, + end_step_comma, + step, + do_token, + block, + end_token, + }) +} + +fn expect_if_stmt(state: &mut ParserState, if_token: TokenReference) -> Result { + let condition = match parse_expression(state) { + ParserResult::Value(condition) => condition, + ParserResult::NotFound => { + state.token_error(if_token, "expected condition after `if`"); + return Err(()); } + ParserResult::LexerMoved => return Err(()), + }; - other => { - unreachable!("unexpected interpolated string kind: {other:?} ({current:#?})") + let Some(then_token) = state.require(Symbol::Then, "expected `then` after condition") else { + return Err(()); + }; + + let then_block = match parse_block(state) { + ParserResult::Value(block) => block, + ParserResult::NotFound => { + state.token_error(then_token, "expected block after `then`"); + return Ok(ast::If::new(condition)); } - } -} + ParserResult::LexerMoved => { + return Ok(ast::If::new(condition)); + } + }; -cfg_if::cfg_if! { - if #[cfg(feature = "roblox")] { - // Roblox Compound Assignment - #[derive(Clone, Debug, Default, PartialEq)] - struct ParseCompoundAssignment; - define_parser!( - ParseCompoundAssignment, - CompoundAssignment, - |_, state| { - let (state, lhs) = ParseVar.parse(state)?; - let (state, compound_operator) = ParseCompoundOp.parse(state)?; - let (state, rhs) = expect!( - state, - ParseExpression.parse(state), - "expected value" - ); + let mut else_if = Vec::new(); - Ok(( - state, - CompoundAssignment { - lhs, - compound_operator, - rhs, - }, - )) - } - ); + let else_if_optional = |else_if: Vec| { + if else_if.is_empty() { + None + } else { + Some(else_if) + } + }; - // Roblox If Expression - #[derive(Clone, Debug, Default, PartialEq)] - struct ParseIfExpression; - define_parser!( - ParseIfExpression, - IfExpression, - |_, state| { - let (state, if_token) = ParseSymbol(Symbol::If).parse(state)?; - let (state, condition) = expect!(state, ParseExpression.parse(state), "expected condition"); - let (state, then_token) = expect!(state, ParseSymbol(Symbol::Then).parse(state), "expected `then`"); - let (mut state, if_expression) = expect!(state, ParseExpression.parse(state), "expected expression"); - - let mut else_if_expressions = Vec::new(); - while let Ok((new_state, else_if_token)) = ParseSymbol(Symbol::ElseIf).parse(state) { - let (new_state, condition) = expect!( - state, - ParseExpression.parse(new_state), - "expected condition" - ); - let (new_state, then_token) = expect!( - state, - ParseSymbol(Symbol::Then).parse(new_state), - "expected 'then'" - ); - let (new_state, expression) = expect!(state, ParseExpression.parse(new_state), "expected expression"); - state = new_state; - else_if_expressions.push(ElseIfExpression { - else_if_token, - condition, - then_token, - expression, - }); - } + let unfinished_if = + |condition, else_if| Ok(ast::If::new(condition).with_else_if(else_if_optional(else_if))); - let (state, else_token) = expect!(state, ParseSymbol(Symbol::Else).parse(state), "expected `else` in if expression"); - let (state, else_expression) = expect!(state, ParseExpression.parse(state), "expected expression"); - - Ok(( - state, - IfExpression { - if_token, - condition: Box::new(condition), - then_token, - if_expression: Box::new(if_expression), - else_if_expressions: if else_if_expressions.is_empty() { None } else { Some(else_if_expressions) }, - else_token, - else_expression: Box::new(else_expression), - }, - )) + loop { + let else_if_token = match state.current() { + Ok(else_if_token) if else_if_token.is_symbol(Symbol::ElseIf) => { + state.consume().unwrap() } - ); - #[derive(Clone, Debug, PartialEq)] - struct ParseInterpolatedString; - define_parser!( - ParseInterpolatedString, - InterpolatedString, - |_, state| { - parse_interpolated_string(state) + Ok(_) => break, + + Err(()) => { + return unfinished_if(condition, else_if); } - ); + }; - #[derive(Clone, Debug, PartialEq)] - struct ParseTypeDeclaration; - define_parser!( - ParseTypeDeclaration, - TypeDeclaration, - |_, state| { - let (state, type_token) = ParseIdentifier.parse(state)?; - if type_token.token().to_string() != "type" { - return Err(InternalAstError::NoMatch); - } + let condition = match parse_expression(state) { + ParserResult::Value(condition) => condition, + ParserResult::NotFound => { + state.token_error(else_if_token, "expected condition after `elseif`"); + return unfinished_if(condition, else_if); + } + ParserResult::LexerMoved => { + return unfinished_if(condition, else_if); + } + }; - let (state, base) = ParseIdentifier.parse(state)?; + let Some(then_token) = state.require(Symbol::Then, "expected `then` after condition") + else { + return unfinished_if(condition, else_if); + }; - let (state, generics) = if let Ok((state, generics)) = - keep_going!(ParseGenericDeclaration.parse(state)) - { - (state, Some(generics)) - } else { - (state, None) - }; + let then_block = match parse_block(state) { + ParserResult::Value(block) => block, + ParserResult::NotFound => { + state.token_error(then_token, "expected block after `then`"); + return unfinished_if(condition, else_if); + } + ParserResult::LexerMoved => { + return unfinished_if(condition, else_if); + } + }; - let (state, equal_token) = expect!( - state, - ParseSymbol(Symbol::Equal).parse(state), - "expected `=` while parsing type alias" - ); + else_if.push(ast::ElseIf { + else_if_token, + condition, + then_token, + block: then_block, + }); + } - let (state, declare_as) = - expect!(state, ParseTypeInfo(TypeInfoContext::None).parse(state), "expected type"); - - Ok(( - state, - TypeDeclaration { - type_token, - base, - generics, - equal_token, - declare_as, - }, - )) + let (else_block, else_token) = match state.consume_if(Symbol::Else) { + Some(else_token) => match parse_block(state) { + ParserResult::Value(block) => (Some(block), Some(else_token)), + ParserResult::NotFound => { + state.token_error(else_token.clone(), "expected block after `else`"); + (Some(ast::Block::new()), Some(else_token)) } - ); + ParserResult::LexerMoved => (Some(ast::Block::new()), Some(else_token)), + }, - #[derive(Clone, Debug, PartialEq)] - struct ParseExportedTypeDeclaration; - define_parser!( - ParseExportedTypeDeclaration, - ExportedTypeDeclaration, - |_, state| { - let (state, export_token) = ParseIdentifier.parse(state)?; - if export_token.token().to_string() != "export" { - return Err(InternalAstError::NoMatch); - } + None => (None, None), + }; - let (state, type_declaration) = - expect!(state, ParseTypeDeclaration.parse(state), "expected type declaration"); + let end_token = match state.current() { + Ok(token) if token.is_symbol(Symbol::End) => state.consume().unwrap(), + Ok(token) => { + state.token_error(token.clone(), "expected `end` to conclude `if`"); + TokenReference::basic_symbol("end") + } - Ok(( - state, - ExportedTypeDeclaration { - export_token, - type_declaration - }, - )) - } - ); + Err(()) => TokenReference::basic_symbol("end"), + }; - #[derive(Clone, Debug, PartialEq)] - struct ParseIndexedTypeInfo; - define_parser!(ParseIndexedTypeInfo, IndexedTypeInfo, |_, state| { - let (state, base_type) = if let Ok((state, identifier)) = { - ParseIdentifier.parse(state) - } { - if let Ok((state, start_arrow)) = ParseSymbol(Symbol::LessThan).parse(state) - { - let (state, generics) = expect!( - state, - OneOrMore(ParseTypeInfo(TypeInfoContext::GenericArgument), ParseSymbol(Symbol::Comma), false).parse(state), - "expected type parameters" - ); + Ok(ast::If { + if_token, + condition, + then_token, + block: then_block, + else_if: else_if_optional(else_if), + else_token, + r#else: else_block, + end_token, + }) +} - let (state, end_arrow) = expect!( - state, - ParseSymbol(Symbol::GreaterThan).parse(state), - "expected `>` to close `<`" - ); +fn expect_local_assignment( + state: &mut ParserState, + local_token: TokenReference, +) -> Result { + let names = match one_or_more(state, parse_name_with_attributes, Symbol::Comma) { + ParserResult::Value(names) => names, + ParserResult::NotFound => { + unreachable!("expect_local_assignment called without upcoming identifier"); + } + ParserResult::LexerMoved => return Err(()), + }; - ( - state, - IndexedTypeInfo::Generic { - base: identifier, - arrows: ContainedSpan::new(start_arrow, end_arrow), - generics, - }, - ) - } else { - (state, IndexedTypeInfo::Basic(identifier)) - } - } else { - return Err(InternalAstError::NoMatch); - }; + let mut name_list = Punctuated::new(); - Ok((state, base_type)) - }); + #[cfg(feature = "luau")] + let mut type_specifiers = Vec::new(); + #[cfg(feature = "lua54")] + let mut attributes = Vec::new(); - #[derive(Clone, Debug, PartialEq)] - /// A parentheses type info atom, such as `(string)` in `type Foo = (string)?`. This excludes parentheses used to indicate - /// a return type, or arguments in a callback type. An opening parentheses should have already been consumed, - /// and is passed to this struct. - struct ParseParenthesesTypeInfo(TokenReference); - define_parser!(ParseParenthesesTypeInfo, TypeInfo, |this, state| { - let (state, type_info) = expect!(state, ParseTypeInfo(TypeInfoContext::None).parse(state), "expected type within parentheses"); - let (state, end_parenthese) = expect!(state, ParseSymbol(Symbol::RightParen).parse(state), "expected `)`"); - - // TODO: should we separate out a single type inside parentheses into a TypeInfo::Parentheses? - let mut types = Punctuated::new(); - types.push(Pair::new(type_info, None)); - - Ok((state, TypeInfo::Tuple { - parentheses: ContainedSpan::new(this.0.clone(), end_parenthese), - types, - })) - }); + for name in names.into_pairs() { + let (name, punctuation) = name.into_tuple(); - #[derive(Clone, Debug, PartialEq)] - /// A tuple type info, such as `(string, foo)` in `(string) -> (string, foo)`. - /// This is only used for return types. An opening parentheses should have already been consumed, - /// and is passed to this struct. - struct ParseTupleTypeInfo(TokenReference); - define_parser!(ParseTupleTypeInfo, TypeInfo, |this, state| { - let (state, types) = expect!( - state, - ZeroOrMoreDelimited(ParseTypeInfo(TypeInfoContext::ParenthesesType), ParseSymbol(Symbol::Comma), false) - .parse(state), - "expected types within parentheses" - ); - let (state, end_parenthese) = expect!(state, ParseSymbol(Symbol::RightParen).parse(state), "expected `)`"); + #[cfg(feature = "lua54")] + attributes.push(name.attribute); - Ok((state, TypeInfo::Tuple { - parentheses: ContainedSpan::new(this.0.clone(), end_parenthese), - types, - })) + #[cfg(feature = "luau")] + type_specifiers.push(name.type_specifier); + + name_list.push(match punctuation { + Some(punctuation) => Pair::Punctuated(name.name, punctuation), + None => Pair::End(name.name), }); + } - /// A type array atom, such as `{ string }`. - /// An opening brace should have already been consumed, and is passed to this struct. - #[derive(Clone, Debug, PartialEq)] - struct ParseTypeArray(TokenReference); - define_parser!(ParseTypeArray, TypeInfo, |this, state| { - let (state, type_info) = expect!( - state, - ParseTypeInfo(TypeInfoContext::None).parse(state), - "expected type in array" - ); + let mut local_assignment = ast::LocalAssignment { + local_token, + name_list, + #[cfg(feature = "luau")] + type_specifiers, + equal_token: None, + expr_list: Punctuated::new(), + #[cfg(feature = "lua54")] + attributes, + }; + + local_assignment.equal_token = match state.consume_if(Symbol::Equal) { + Some(equal_token) => Some(equal_token), + None => return Ok(local_assignment), + }; - let (state, end_brace) = expect!( - state, - ParseSymbol(Symbol::RightBrace).parse(state), - "expected `}` to match `{`" + match parse_expression_list(state) { + ParserResult::Value(expr_list) => local_assignment.expr_list = expr_list, + + ParserResult::NotFound => { + state.token_error( + local_assignment.equal_token.clone().unwrap(), + "expected an expression", ); + } - Ok(( - state, - TypeInfo::Array { - braces: ContainedSpan::new(this.0.clone(), end_brace), - type_info: Box::new(type_info) - }, - )) - }); + ParserResult::LexerMoved => {} + }; - #[derive(Clone, Debug, PartialEq)] - struct ParseTypeArgument; - define_parser!(ParseTypeArgument, TypeArgument, |_, state| { - // Attempt to parse an identifier and then a `:` - if let Ok((new_state, identifier)) = ParseIdentifier.parse(state) { - if let Ok((state, colon)) = ParseSymbol(Symbol::Colon).parse(new_state) { - let (state, type_info) = expect!(state, ParseTypeInfo(TypeInfoContext::None).parse(state), "expected type"); - return Ok(( - state, - TypeArgument { - name: Some((identifier, colon)), - type_info - } - )) - } - }; + Ok(local_assignment) +} - // If failed, fall back to original state and parse a type_info normally - let (state, type_info) = ParseTypeInfo(TypeInfoContext::ParenthesesType).parse(state)?; - Ok(( - state, - TypeArgument { - name: None, - type_info, - } - )) - }); +fn expect_expression_key( + state: &mut ParserState, + left_bracket: TokenReference, +) -> Result { + let expression = match parse_expression(state) { + ParserResult::Value(expression) => expression, - #[derive(Clone, Debug, PartialEq)] - /// A callback type info atom, such as `(count: number) -> string` in `type Foo = (count: number) -> string`. - /// An opening parentheses should have already been consumed, and is passed to this struct. - struct ParseCallbackTypeInfo(TokenReference, Option); - define_parser!(ParseCallbackTypeInfo, TypeInfo, |this, state| { - let (state, types) = expect!( - state, - ZeroOrMoreDelimited(ParseTypeArgument, ParseSymbol(Symbol::Comma), false) - .parse(state), - "expected types within parentheses" - ); + ParserResult::NotFound => { + state.token_error(left_bracket, "expected an expression after `[`"); - let (state, end_parenthese) = expect!( - state, - ParseSymbol(Symbol::RightParen).parse(state), - "expected `)` to match `(`" - ); + return Err(()); + } - let (state, arrow) = expect!(state, ParseSymbol(Symbol::ThinArrow).parse(state), "expected `->` after `()` when parsing function type"); - let (state, return_value) = expect!( - state, - ParseTypeInfo(TypeInfoContext::ReturnType).parse(state), - "expected return type after `->`" - ); + ParserResult::LexerMoved => { + return Err(()); + } + }; - Ok(( - state, - TypeInfo::Callback { - generics: this.1.clone(), - arguments: types, - parentheses: ContainedSpan::new(this.0.clone(), end_parenthese), - arrow, - return_type: Box::new(return_value), - }, - )) - }); + let Some(right_bracket) = state.require_with_reference_range_callback( + Symbol::RightBracket, + "expected `]` after expression", + || { + ( + left_bracket.clone(), + expression.tokens().last().unwrap().clone(), + ) + }, + ) else { + return Err(()); + }; - /// A type table atom, such as `{ foo: string, bar: number }`. - /// An opening brace should have already been consumed, and is passed to this struct. - #[derive(Clone, Debug, PartialEq)] - struct ParseTypeTable(TokenReference); - define_parser!(ParseTypeTable, TypeInfo, |this, state| { - let mut state = state; - let mut fields = Punctuated::new(); - - while let Ok((new_state, field)) = keep_going!(ParseTypeField.parse(state)) { - let field_sep = if let Ok((new_state, separator)) = - ParseSymbol(Symbol::Comma).parse(new_state) - { - state = new_state; - Some(separator) - } else if let Ok((new_state, separator)) = ParseSymbol(Symbol::Semicolon).parse(new_state) { - state = new_state; - Some(separator) - } else { - state = new_state; - None - }; + // rewrite todo: we can realistically construct a field in error recovery + // rewrite todo: this should also be range + let Some(equal_token) = state.require_with_reference_range( + Symbol::Equal, + "expected `=` after expression", + &left_bracket, + &right_bracket, + ) else { + return Err(()); + }; - let is_end = field_sep.is_none(); - fields.push(Pair::new(field, field_sep)); - if is_end { - break; - } - } + let value = match parse_expression(state) { + ParserResult::Value(expression) => expression, - let (state, end_brace) = expect!( - state, - ParseSymbol(Symbol::RightBrace).parse(state), - "expected `}` to match `{`" - ); + ParserResult::NotFound => { + state.token_error(equal_token, "expected an expression after `=`"); - Ok((state, TypeInfo::Table { - braces: ContainedSpan::new(this.0.clone(), end_brace), - fields, - })) - }); + return Err(()); + } - // A type info atom, excluding compound types such as Union and Intersection - #[derive(Clone, Debug, PartialEq)] - struct ParseSingleTypeInfo(TypeInfoContext); - define_parser!(ParseSingleTypeInfo, TypeInfo, |this, state| { - // Singleton type info: `"yes" | "no"` in `(string) -> "yes" | "no"`, `"$$typeof"` in `{ ["$$typeof"]: number }`, - let (state, base_type) = if let Ok((state, string_singleton)) = ParseStringLiteral.parse(state) { - (state, TypeInfo::String(string_singleton)) - // Singleton type info: `true` in `type X = Error & { handled: true }` - } else if let Ok((state, true_singleton)) = ParseSymbol(Symbol::True).parse(state) { - (state, TypeInfo::Boolean(true_singleton)) - } else if let Ok((state, false_singleton)) = ParseSymbol(Symbol::False).parse(state) { - (state, TypeInfo::Boolean(false_singleton)) - // Singleton type info: `nil` in `local function get(x: string, y: nil) end` - } else if let Ok((state, nil_singleton)) = ParseSymbol(Symbol::Nil).parse(state) { - (state, TypeInfo::Basic(nil_singleton)) - } else if let Ok((state, identifier)) = ParseIdentifier - .parse(state) - { - if identifier.token().to_string() == "typeof" { - let (state, start_parenthese) = expect!( - state, - ParseSymbol(Symbol::LeftParen).parse(state), - "expected '(' when parsing typeof type" - ); + ParserResult::LexerMoved => { + return Err(()); + } + }; - let (state, expression) = expect!( - state, - ParseExpression.parse(state), - "expected expression when parsing typeof type" - ); + Ok(ast::Field::ExpressionKey { + brackets: ContainedSpan::new(left_bracket, right_bracket), + key: expression, + equal: equal_token, + value, + }) +} - let (state, end_parenthese) = expect!( - state, - ParseSymbol(Symbol::RightParen).parse(state), - "expected ')' when parsing typeof type" - ); +fn force_table_constructor( + state: &mut ParserState, + left_brace: TokenReference, +) -> ast::TableConstructor { + let mut fields = Punctuated::new(); - ( - state, - TypeInfo::Typeof { - typeof_token: identifier, - parentheses: ContainedSpan::new(start_parenthese, end_parenthese), - inner: Box::new(expression), - }, - ) - } else if let Ok((state, punctuation)) = ParseSymbol(Symbol::Dot).parse(state) - { - let (state, type_info) = expect!( - state, - ParseIndexedTypeInfo.parse(state), - "expected type when parsing type index" - ); + let unfinished_table = + |left_brace: TokenReference, fields: Punctuated| ast::TableConstructor { + braces: ContainedSpan::new(left_brace, TokenReference::basic_symbol("}")), + fields, + }; - ( - state, - TypeInfo::Module { - module: identifier, - punctuation, - type_info: Box::new(type_info), - }, - ) - } else if let Ok((state, start_arrow)) = ParseSymbol(Symbol::LessThan).parse(state) - { - let (state, generics) = expect!( - state, - ZeroOrMoreDelimited(ParseTypeInfo(TypeInfoContext::GenericArgument), ParseSymbol(Symbol::Comma), false).parse(state), - "expected type parameters" - ); + loop { + let Ok(current_token) = state.current() else { + return unfinished_table(left_brace, fields); + }; - let (state, end_arrow) = expect!( - state, - ParseSymbol(Symbol::GreaterThan).parse(state), - "expected `>` to close `<`" - ); + let field = match current_token.token_type() { + TokenType::Symbol { + symbol: Symbol::RightBrace, + } => { + return ast::TableConstructor { + braces: ContainedSpan::new(left_brace, state.consume().unwrap()), + fields, + }; + } - ( - state, - TypeInfo::Generic { - base: identifier, - arrows: ContainedSpan::new(start_arrow, end_arrow), - generics, - }, - ) - } else if matches!(this.0, TypeInfoContext::ParenthesesType | TypeInfoContext::ReturnType | TypeInfoContext::VarArgSpecifier | TypeInfoContext::GenericArgument) { - // Check for a generic type pack - if let Ok((state, ellipse)) = ParseSymbol(Symbol::Ellipse).parse(state) { - (state, TypeInfo::GenericPack { - name: identifier, - ellipse - }) - } else { - (state, TypeInfo::Basic(identifier)) + TokenType::Symbol { + symbol: Symbol::LeftBracket, + } => { + let left_bracket = state.consume().unwrap(); + + match expect_expression_key(state, left_bracket) { + Ok(field) => field, + Err(()) => { + return unfinished_table(left_brace, fields); } - } else { - (state, TypeInfo::Basic(identifier)) } - } else if let Ok((state, generics)) = ParseGenericDeclaration.parse(state) { - // Callback with a generic type - let (state, start_parenthese) = ParseSymbol(Symbol::LeftParen).parse(state)?; - ParseCallbackTypeInfo(start_parenthese, Some(generics)).parse(state)? - } else if let Ok((state, start_parenthese)) = - ParseSymbol(Symbol::LeftParen).parse(state) + } + + TokenType::Identifier { .. } if matches!(state.peek(), Ok(peek_token) if peek_token.is_symbol(Symbol::Equal)) => { - // Parse types encapsulated in parentheses as an atom. If we are allowing type packs (i.e. as a return type or a generic type argument), - // this could be a tuple, otherwise this can only be a singular type specified within parentheses. - let atom = - if matches!(this.0, TypeInfoContext::ReturnType | TypeInfoContext::GenericArgument) { - ParseTupleTypeInfo(start_parenthese.clone()).parse(state) - } else { - ParseParenthesesTypeInfo(start_parenthese.clone()).parse(state) - }; + let key = state.consume().unwrap(); - if let Ok((state, parentheses_type)) = atom { - // Single token lookahead: see if we have a `->` ahead. If we do, we need to parse this - // as a callback type, using what we already have from the parentheses type - if let Ok((state, arrow)) = ParseSymbol(Symbol::ThinArrow).parse(state) { - // Unwrap the parsed parentheses type into its parentheses and its enclosed type - let (parentheses, arguments) = match parentheses_type { - TypeInfo::Tuple { parentheses, types } => { - // `types` is currently `Punctuated`, but we need to map it to `Punctuated` - // where each argument has no name. - let arguments = types.into_pairs().map(|pair| pair.map(|type_info| TypeArgument { - name: None, - type_info - })).collect::>(); - (parentheses, arguments) - }, - _ => unreachable!("parsed a non-tuple as a parentheses type"), - }; + let equal_token = state.consume().unwrap(); - let (state, return_value) = expect!( - state, - ParseTypeInfo(TypeInfoContext::ReturnType).parse(state), - "expected return type after `->`" - ); + let value = match parse_expression(state) { + ParserResult::Value(expression) => expression, - ( - state, - TypeInfo::Callback { - generics: None, - arguments, - parentheses, - arrow, - return_type: Box::new(return_value), - }, - ) - } else { - (state, parentheses_type) + ParserResult::NotFound => { + state.token_error(equal_token, "expected an expression after `=`"); + + return unfinished_table(left_brace, fields); } - } else { - ParseCallbackTypeInfo(start_parenthese, None).parse(state)? - } - } else if let Ok((state, start_brace)) = ParseSymbol(Symbol::LeftBrace).parse(state) { - if let Ok((state, type_array)) = ParseTypeArray(start_brace.clone()).parse(state) { - (state, type_array) - } else { - ParseTypeTable(start_brace).parse(state)? - } - } else if matches!(this.0, TypeInfoContext::GenericArgument) { - // Only allowed variadic type packs as a generic argument - // Note, this is `...T`, but `T` is a token, not a type info (e.g. `...string` is allowed but `...{}` is not) - if let Ok((state, ellipse)) = ParseSymbol(Symbol::Ellipse).parse(state) { - let (state, name) = expect!( - state, - ParseIdentifier.parse(state), - "expected name after `...`" + + ParserResult::LexerMoved => { + return unfinished_table(left_brace, fields); + } + }; + + ast::Field::NameKey { + key, + equal: equal_token, + value, + } + } + + _ => { + let value = match parse_expression(state) { + ParserResult::Value(expression) => expression, + + ParserResult::NotFound => { + state.token_error( + match fields.last() { + Some(Pair::End(field)) => field.tokens().last().unwrap().clone(), + Some(Pair::Punctuated(field, _)) => { + field.tokens().last().unwrap().clone() + } + None => left_brace.clone(), + }, + "expected a field", + ); + + return unfinished_table(left_brace, fields); + } + + ParserResult::LexerMoved => { + return unfinished_table(left_brace, fields); + } + }; + + ast::Field::NoKey(value) + } + }; + + match state.current() { + Ok(token) => { + if token.is_symbol(Symbol::Comma) || token.is_symbol(Symbol::Semicolon) { + fields.push(Pair::Punctuated(field, state.consume().unwrap())) + } else { + fields.push(Pair::End(field)); + break; + } + } + + Err(()) => { + fields.push(Pair::End(field)); + break; + } + }; + } + + let right_brace = match state.require(Symbol::RightBrace, "expected `}` after last field") { + Some(right_brace) => right_brace, + None => TokenReference::basic_symbol("}"), + }; + + ast::TableConstructor { + braces: ContainedSpan::new(left_brace, right_brace), + fields, + } +} + +fn expect_repeat_stmt( + state: &mut ParserState, + repeat_token: TokenReference, +) -> Result { + let block = match parse_block(state) { + ParserResult::Value(block) => block, + + ParserResult::NotFound => { + state.token_error(repeat_token, "expected a block after `repeat`"); + + return Err(()); + } + + ParserResult::LexerMoved => { + return Err(()); + } + }; + + let Some(until_token) = state.require(Symbol::Until, "expected `until` after block") else { + return Ok(ast::Stmt::Do(ast::Do::new().with_block(block))); + }; + + let condition = match parse_expression(state) { + ParserResult::Value(expression) => expression, + + ParserResult::NotFound => { + state.token_error(until_token, "expected a condition after `until`"); + return Ok(ast::Stmt::Do(ast::Do::new().with_block(block))); + } + + ParserResult::LexerMoved => { + return Ok(ast::Stmt::Do(ast::Do::new().with_block(block))); + } + }; + + Ok(ast::Stmt::Repeat(ast::Repeat { + repeat_token, + block, + until: condition, + until_token, + })) +} + +fn expect_while_stmt( + state: &mut ParserState, + while_token: TokenReference, +) -> Result { + let condition = match parse_expression(state) { + ParserResult::Value(expression) => expression, + + ParserResult::NotFound => { + state.token_error(while_token, "expected a condition after `while`"); + + return Err(()); + } + + ParserResult::LexerMoved => { + return Err(()); + } + }; + + let Some(do_token) = state.require(Symbol::Do, "expected `do` after condition") else { + return Ok(ast::While::new(condition)); + }; + + let (block, end_token) = match expect_block_with_end(state, "while loop", &do_token) { + Ok((block, end_token)) => (block, end_token), + + Err(()) => { + return Ok(ast::While::new(condition)); + } + }; + + Ok(ast::While { + while_token, + condition, + do_token, + block, + end_token, + }) +} + +#[cfg(feature = "luau")] +fn expect_type_declaration( + state: &mut ParserState, + type_token: TokenReference, +) -> Result { + let base = match state.current()? { + token if token.token_kind() == TokenKind::Identifier => state.consume().unwrap(), + token => { + state.token_error(token.clone(), "expected type name"); + // rewrite todo (in future if needed): maybe we can add an error name here to continue parsing? + return Err(()); + } + }; + + let generics = match parse_generic_type_list(state, TypeListStyle::WithDefaults) { + ParserResult::Value(generics) => Some(generics), + ParserResult::NotFound => None, + _ => return Err(()), + }; + + let equal_token = state + .require(Symbol::Equal, "expected `=` after type name") + .unwrap_or_else(|| TokenReference::basic_symbol("=")); + + let ParserResult::Value(declare_as) = parse_type(state) else { + return Err(()); + }; + + Ok(ast::TypeDeclaration { + type_token, + base, + generics, + equal_token, + declare_as, + }) +} + +fn parse_prefix(state: &mut ParserState) -> ParserResult { + let current_token = match state.current() { + Ok(token) => token, + Err(()) => return ParserResult::NotFound, + }; + + match current_token.token_type() { + TokenType::Symbol { + symbol: Symbol::LeftParen, + } => { + let left_parenthesis = state.consume().unwrap(); + + let expression = Box::new(match try_parser!(parse_expression(state)) { + Some(expression) => expression, + + None => { + state.token_error(left_parenthesis, "expected an expression after `(`"); + return ParserResult::LexerMoved; + } + }); + + let Some(right_parenthesis) = + state.require(Symbol::RightParen, "expected `)` after expression") + else { + return ParserResult::Value(ast::Prefix::Expression(Box::new( + ast::Expression::Parentheses { + contained: ContainedSpan::new( + left_parenthesis, + TokenReference::basic_symbol(")"), + ), + expression, + }, + ))); + }; + + ParserResult::Value(ast::Prefix::Expression(Box::new( + ast::Expression::Parentheses { + contained: ContainedSpan::new(left_parenthesis, right_parenthesis), + expression, + }, + ))) + } + + TokenType::Identifier { .. } => { + ParserResult::Value(ast::Prefix::Name(state.consume().unwrap())) + } + + _ => ParserResult::NotFound, + } +} + +fn parse_arguments(state: &mut ParserState) -> ParserResult { + let current = match state.current() { + Ok(token) => token, + Err(()) => return ParserResult::NotFound, + }; + + match current.token_type() { + TokenType::Symbol { + symbol: Symbol::LeftParen, + } => { + let left_parenthesis = state.consume().unwrap(); + let arguments = try_parser!(parse_expression_list(state)).unwrap_or_default(); + let right_parenthesis = match state.require_with_reference_token( + Symbol::RightParen, + "expected `)` to close function call", + &left_parenthesis, + ) { + Some(token) => token, + + None => TokenReference::basic_symbol(")"), + }; + + ParserResult::Value(ast::FunctionArgs::Parentheses { + parentheses: ContainedSpan::new(left_parenthesis, right_parenthesis), + arguments, + }) + } + + TokenType::Symbol { + symbol: Symbol::LeftBrace, + } => { + let left_brace = state.consume().unwrap(); + + ParserResult::Value(ast::FunctionArgs::TableConstructor( + force_table_constructor(state, left_brace), + )) + } + + TokenType::StringLiteral { .. } => { + ParserResult::Value(ast::FunctionArgs::String(state.consume().unwrap())) + } + + _ => ParserResult::NotFound, + } +} + +fn parse_suffix(state: &mut ParserState) -> ParserResult { + let Ok(current) = state.current() else { + return ParserResult::NotFound; + }; + + match current.token_type() { + TokenType::Symbol { + symbol: Symbol::Dot, + } => { + let dot = state.consume().unwrap(); + let name = match state.current() { + Ok(token) if token.token_kind() == TokenKind::Identifier => { + state.consume().unwrap() + } + + Ok(_) => { + state.token_error(dot, "expected identifier after `.`"); + return ParserResult::LexerMoved; + } + + Err(()) => return ParserResult::LexerMoved, + }; + + ParserResult::Value(ast::Suffix::Index(ast::Index::Dot { dot, name })) + } + + TokenType::Symbol { + symbol: Symbol::LeftBracket, + } => { + let left_bracket = state.consume().unwrap(); + + let expression = match parse_expression(state) { + ParserResult::Value(expression) => expression, + ParserResult::LexerMoved => return ParserResult::LexerMoved, + ParserResult::NotFound => { + state.token_error(left_bracket, "expected expression after `[`"); + return ParserResult::LexerMoved; + } + }; + + let right_bracket = match state.require_with_reference_range( + Symbol::RightBracket, + "expected `]` to close index expression", + &left_bracket, + expression.tokens().last().unwrap(), + ) { + Some(right_bracket) => right_bracket, + + None => TokenReference::basic_symbol("]"), + }; + + ParserResult::Value(ast::Suffix::Index(ast::Index::Brackets { + brackets: ContainedSpan::new(left_bracket, right_bracket), + expression, + })) + } + + TokenType::Symbol { + symbol: Symbol::LeftParen | Symbol::LeftBrace, + } + | TokenType::StringLiteral { .. } => { + let arguments = try_parser!(parse_arguments(state)).unwrap(); + ParserResult::Value(ast::Suffix::Call(ast::Call::AnonymousCall(arguments))) + } + + TokenType::Symbol { + symbol: Symbol::Colon, + } => { + let colon_token = state.consume().unwrap(); + + let name = match state.current() { + Ok(token) if token.token_kind() == TokenKind::Identifier => { + state.consume().unwrap() + } + + Ok(_) => { + state.token_error(colon_token, "expected identifier after `:`"); + return ParserResult::LexerMoved; + } + + Err(()) => return ParserResult::LexerMoved, + }; + + let args = match parse_arguments(state) { + ParserResult::Value(args) => args, + ParserResult::LexerMoved => ast::FunctionArgs::empty(), + ParserResult::NotFound => { + state.token_error(name.clone(), "expected arguments after `:`"); + ast::FunctionArgs::empty() + } + }; + + ParserResult::Value(ast::Suffix::Call(ast::Call::MethodCall(ast::MethodCall { + colon_token, + name, + args, + }))) + } + + _ => ParserResult::NotFound, + } +} + +fn parse_prefix_and_suffixes( + state: &mut ParserState, +) -> ParserResult<(ast::Prefix, Vec)> { + let prefix = match parse_prefix(state) { + ParserResult::Value(prefix) => prefix, + ParserResult::LexerMoved => return ParserResult::LexerMoved, + ParserResult::NotFound => return ParserResult::NotFound, + }; + + let mut suffixes = Vec::new(); + + loop { + match parse_suffix(state) { + ParserResult::Value(suffix) => { + suffixes.push(suffix); + } + + ParserResult::LexerMoved => { + break; + } + + ParserResult::NotFound => { + break; + } + }; + } + + ParserResult::Value((prefix, suffixes)) +} + +fn parse_expression(state: &mut ParserState) -> ParserResult { + let primary_expression = match parse_primary_expression(state) { + ParserResult::Value(expression) => expression, + ParserResult::NotFound => return ParserResult::NotFound, + ParserResult::LexerMoved => return ParserResult::LexerMoved, + }; + + parse_expression_with_precedence(state, primary_expression, 0) +} + +fn parse_primary_expression(state: &mut ParserState) -> ParserResult { + let current_token = match state.current() { + Ok(token) => token, + Err(()) => return ParserResult::NotFound, + }; + + let expression = match current_token.token_type() { + TokenType::Symbol { + symbol: Symbol::Function, + } => { + let function_token = state.consume().unwrap(); + let function_body = match parse_function_body(state) { + ParserResult::Value(body) => body, + ParserResult::LexerMoved => return ParserResult::LexerMoved, + ParserResult::NotFound => { + state.token_error(function_token, "expected a function body"); + return ParserResult::LexerMoved; + } + }; + + ParserResult::Value(Expression::Function((function_token, function_body))) + } + + TokenType::Symbol { + symbol: Symbol::True | Symbol::False | Symbol::Nil | Symbol::Ellipse, + } => ParserResult::Value(Expression::Symbol(state.consume().unwrap())), + + TokenType::StringLiteral { .. } => { + let string_token = state.consume().unwrap(); + ParserResult::Value(Expression::String(string_token)) + } + + TokenType::Number { .. } => { + let number_token = state.consume().unwrap(); + ParserResult::Value(Expression::Number(number_token)) + } + + TokenType::Identifier { .. } + | TokenType::Symbol { + symbol: Symbol::LeftParen, + } => { + let (prefix, suffixes) = match parse_prefix_and_suffixes(state) { + ParserResult::Value(value) => value, + ParserResult::LexerMoved => return ParserResult::LexerMoved, + ParserResult::NotFound => { + unreachable!("identifier found but parse_prefix_and_suffixes didn't even move"); + } + }; + + if suffixes.is_empty() { + match prefix { + ast::Prefix::Expression(expression) => ParserResult::Value(*expression), + ast::Prefix::Name(name) => { + ParserResult::Value(Expression::Var(ast::Var::Name(name))) + } + } + } else if matches!(suffixes.last().unwrap(), ast::Suffix::Call(_)) { + ParserResult::Value(Expression::FunctionCall(ast::FunctionCall { + prefix, + suffixes, + })) + } else { + ParserResult::Value(Expression::Var(ast::Var::Expression(Box::new( + ast::VarExpression { prefix, suffixes }, + )))) + } + } + + #[cfg(feature = "lua53")] + TokenType::Symbol { + symbol: Symbol::Minus | Symbol::Not | Symbol::Hash | Symbol::Tilde, + } => { + let unary_operator_token = state.consume().unwrap(); + parse_unary_expression(state, unary_operator_token) + } + + #[cfg(not(feature = "lua53"))] + TokenType::Symbol { + symbol: Symbol::Minus | Symbol::Not | Symbol::Hash, + } => { + let unary_operator_token = state.consume().unwrap(); + parse_unary_expression(state, unary_operator_token) + } + + TokenType::Symbol { + symbol: Symbol::LeftBrace, + } => { + let left_brace = state.consume().unwrap(); + ParserResult::Value(ast::Expression::TableConstructor(force_table_constructor( + state, left_brace, + ))) + } + + #[cfg(feature = "luau")] + TokenType::Symbol { symbol: Symbol::If } if state.lua_version().has_luau() => { + let if_token = state.consume().unwrap(); + match expect_if_else_expression(state, if_token) { + Ok(if_expression) => { + ParserResult::Value(ast::Expression::IfExpression(if_expression)) + } + Err(_) => ParserResult::LexerMoved, + } + } + + #[cfg(feature = "luau")] + TokenType::InterpolatedString { kind, .. } if state.lua_version().has_luau() => { + let kind = *kind; + let interpolated_string_begin = state.consume().unwrap(); + + match kind { + InterpolatedStringKind::Simple => ParserResult::Value( + ast::Expression::InterpolatedString(ast::InterpolatedString { + segments: Vec::new(), + last_string: interpolated_string_begin, + }), + ), + + InterpolatedStringKind::Begin => { + ParserResult::Value(ast::Expression::InterpolatedString( + expect_interpolated_string(state, interpolated_string_begin), + )) + } + + other => unreachable!("unexpected interpolated string kind: {other:?}"), + } + } + + _ => ParserResult::NotFound, + }; + + match expression { + #[cfg(feature = "luau")] + ParserResult::Value(expression) if state.lua_version().has_luau() => { + if let Some(assertion_op) = state.consume_if(Symbol::TwoColons) { + let ParserResult::Value(cast_to) = parse_type(state) else { + return ParserResult::LexerMoved; + }; + + ParserResult::Value(ast::Expression::TypeAssertion { + expression: Box::new(expression), + type_assertion: ast::TypeAssertion { + assertion_op, + cast_to, + }, + }) + } else { + ParserResult::Value(expression) + } + } + _ => expression, + } +} + +// rewrite todo: i think this should be iterative instead of recursive +fn parse_expression_with_precedence( + state: &mut ParserState, + mut lhs: Expression, + precedence: u8, +) -> ParserResult { + loop { + let Some(bin_op_precedence) = ast::BinOp::precedence_of_token(match state.current() { + Ok(token) => token, + Err(()) => return ParserResult::Value(lhs), + }) else { + return ParserResult::Value(lhs); + }; + + if bin_op_precedence < precedence { + return ParserResult::Value(lhs); + } + + let bin_op = ast::BinOp::consume(state).unwrap(); + + let mut rhs = match parse_primary_expression(state) { + ParserResult::Value(expression) => expression, + ParserResult::NotFound => { + state.token_error( + bin_op.token().clone(), + "expected expression after binary operator", + ); + return ParserResult::Value(lhs); + } + ParserResult::LexerMoved => return ParserResult::LexerMoved, + }; + + while let Ok(next_bin_op_token) = state.current() { + let Some(next_bin_op_precedence) = ast::BinOp::precedence_of_token(next_bin_op_token) + else { + break; + }; + + let precedence_to_search; + + if next_bin_op_precedence > bin_op_precedence { + precedence_to_search = bin_op_precedence + 1; + } else if ast::BinOp::is_right_associative_token(next_bin_op_token) + && next_bin_op_precedence == bin_op_precedence + { + precedence_to_search = bin_op_precedence; + } else { + break; + } + + rhs = match parse_expression_with_precedence(state, rhs, precedence_to_search) { + ParserResult::Value(expression) => expression, + ParserResult::NotFound => { + state.token_error( + bin_op.token().clone(), + "expected expression after binary operator", + ); + return ParserResult::Value(lhs); + } + ParserResult::LexerMoved => return ParserResult::Value(lhs), + }; + } + + lhs = Expression::BinaryOperator { + lhs: Box::new(lhs), + binop: bin_op, + rhs: Box::new(rhs), + }; + } +} + +fn parse_unary_expression( + state: &mut ParserState, + unary_operator_token: ast::TokenReference, +) -> ParserResult { + let unary_operator = match unary_operator_token.token_type() { + TokenType::Symbol { symbol } => match symbol { + Symbol::Minus => ast::UnOp::Minus(unary_operator_token), + Symbol::Not => ast::UnOp::Not(unary_operator_token), + Symbol::Hash => ast::UnOp::Hash(unary_operator_token), + #[cfg(feature = "lua53")] + Symbol::Tilde if state.lua_version().has_lua53() => { + ast::UnOp::Tilde(unary_operator_token) + } + _ => unreachable!(), + }, + + _ => unreachable!(), + }; + + let expression = match parse_expression(state) { + ParserResult::Value(expression) => expression, + ParserResult::LexerMoved => return ParserResult::LexerMoved, + ParserResult::NotFound => { + state.token_error( + unary_operator.token().clone(), + format!( + "expected an expression after {}", + unary_operator.token().token() + ), + ); + return ParserResult::LexerMoved; + } + }; + + ParserResult::Value(Expression::UnaryOperator { + unop: unary_operator, + expression: Box::new(expression), + }) +} + +fn parse_function_body(state: &mut ParserState) -> ParserResult { + const NO_TRAILING_COMMAS_ERROR: &str = "trailing commas in arguments are not allowed"; + + #[cfg(feature = "luau")] + let generics = match parse_generic_type_list(state, TypeListStyle::Plain) { + ParserResult::Value(generic_declaration) => Some(generic_declaration), + ParserResult::NotFound => None, + ParserResult::LexerMoved => return ParserResult::LexerMoved, + }; + + let Some(left_parenthesis) = state.consume_if(Symbol::LeftParen) else { + return ParserResult::NotFound; + }; + + let mut parameters = Punctuated::new(); + #[cfg(feature = "luau")] + let mut type_specifiers = Vec::new(); + let right_parenthesis; + + let unfinished_function_body = + |left_parenthesis: TokenReference, mut parameters: Punctuated| { + if matches!(parameters.last(), Some(Pair::Punctuated(..))) { + let last_parameter = parameters.pop().unwrap(); + parameters.push(Pair::End(last_parameter.into_value())); + } + + // rewrite todo: we should appropriately recover the parsed generics/type_specifiers here + // but it becomes messy with cfg feature toggles and moves. + ParserResult::Value(FunctionBody { + #[cfg(feature = "luau")] + generics: None, // rewrite todo: fix + parameters_parentheses: ContainedSpan::new( + left_parenthesis, + TokenReference::basic_symbol(")"), + ), + parameters, + #[cfg(feature = "luau")] + type_specifiers: Vec::new(), // rewrite todo: fix + #[cfg(feature = "luau")] + return_type: None, + block: ast::Block::new(), + end_token: TokenReference::basic_symbol("end"), + }) + }; + + loop { + match state.current() { + Ok(token) if token.is_symbol(Symbol::RightParen) => { + right_parenthesis = state.consume().unwrap(); + break; + } + + Ok(token) if token.is_symbol(Symbol::Ellipse) => { + let ellipse = state.consume().unwrap(); + parameters.push(Pair::End(ast::Parameter::Ellipse(ellipse))); + + #[cfg(feature = "luau")] + if state.lua_version().has_luau() { + let type_specifier = if let Some(colon) = state.consume_if(Symbol::Colon) { + // varargs can also be annotated using generic packs: T... + let type_info = if matches!(state.current(), Ok(token) if token.token_kind() == TokenKind::Identifier) + && matches!(state.peek(), Ok(token) if token.is_symbol(Symbol::Ellipse)) + { + let name = match parse_name(state) { + ParserResult::Value(name) => name.name, + _ => unreachable!(), + }; + + let Some(ellipse) = + state.require(Symbol::Ellipse, "expected `...` after type name") + else { + unreachable!() + }; + + ast::TypeInfo::GenericPack { name, ellipse } + } else { + match parse_type(state) { + ParserResult::Value(type_info) => type_info, + _ => return unfinished_function_body(left_parenthesis, parameters), + } + }; + + Some(ast::TypeSpecifier { + punctuation: colon, + type_info, + }) + } else { + None + }; + type_specifiers.push(type_specifier); + } + + right_parenthesis = match state.require(Symbol::RightParen, "expected a `)`") { + Some(right_parenthesis) => right_parenthesis, + None => return unfinished_function_body(left_parenthesis, parameters), + }; + + break; + } + + Ok(TokenReference { + token: + Token { + token_type: TokenType::Identifier { .. }, + .. + }, + .. + }) => { + let name_parameter = match parse_name_with_type_specifiers(state) { + ParserResult::Value(name) => { + #[cfg(feature = "luau")] + type_specifiers.push(name.type_specifier); + ast::Parameter::Name(name.name) + } + _ => unreachable!(), + }; + + let Some(comma) = state.consume_if(Symbol::Comma) else { + parameters.push(Pair::End(name_parameter)); + + match state.require(Symbol::RightParen, "expected a `)`") { + Some(new_right_parenthesis) => { + right_parenthesis = new_right_parenthesis; + break; + } + + None => return unfinished_function_body(left_parenthesis, parameters), + }; + }; + + parameters.push(Pair::Punctuated(name_parameter, comma)); + } + + Ok(token) => { + state.token_error(token.clone(), "expected a parameter name or `)`"); + + return unfinished_function_body(left_parenthesis, parameters); + } + + Err(()) => { + return unfinished_function_body(left_parenthesis, parameters); + } + } + } + + if matches!(parameters.last(), Some(Pair::Punctuated(..))) { + let last_parameter = parameters.pop().unwrap(); + + state.token_error( + last_parameter.punctuation().unwrap().clone(), + NO_TRAILING_COMMAS_ERROR, + ); + + parameters.push(Pair::End(last_parameter.into_value())); + } + + #[cfg(feature = "luau")] + let return_type = if state.lua_version().has_luau() { + if let Some(punctuation) = state.consume_if(Symbol::Colon) { + match parse_return_type(state) { + ParserResult::Value(type_info) => Some(ast::TypeSpecifier { + punctuation, + type_info, + }), + _ => return ParserResult::LexerMoved, + } + } else if let Some(punctuation) = state.consume_if(Symbol::ThinArrow) { + state.token_error( + punctuation.clone(), + "function return type annotations should use `:` instead of `->`", + ); + match parse_return_type(state) { + ParserResult::Value(type_info) => Some(ast::TypeSpecifier { + punctuation, + type_info, + }), + _ => return ParserResult::LexerMoved, + } + } else { + None + } + } else { + None + }; + + let (block, end) = match expect_block_with_end(state, "function body", &right_parenthesis) { + Ok((block, end)) => (block, end), + Err(()) => return ParserResult::LexerMoved, + }; + + ParserResult::Value(FunctionBody { + #[cfg(feature = "luau")] + generics, + parameters_parentheses: ContainedSpan::new(left_parenthesis, right_parenthesis), + parameters, + #[cfg(feature = "luau")] + type_specifiers, + #[cfg(feature = "luau")] + return_type, + block, + end_token: end, + }) +} + +#[cfg(feature = "luau")] +fn expect_if_else_expression( + state: &mut ParserState, + if_token: TokenReference, +) -> Result { + let ParserResult::Value(condition) = parse_expression(state) else { + return Err(()); + }; + + let Some(then_token) = state.require(Symbol::Then, "expected `then` after condition") else { + return Err(()); + }; + + let ParserResult::Value(if_expression) = parse_expression(state) else { + return Err(()); + }; + + let mut else_if_expressions = Vec::new(); + while let Some(else_if_token) = state.consume_if(Symbol::ElseIf) { + let ParserResult::Value(condition) = parse_expression(state) else { + return Err(()); + }; + + let Some(then_token) = state.require(Symbol::Then, "expected `then` after condition") + else { + return Err(()); + }; + let ParserResult::Value(expression) = parse_expression(state) else { + return Err(()); + }; + else_if_expressions.push(ast::ElseIfExpression { + else_if_token, + condition, + then_token, + expression, + }) + } + + let Some(else_token) = state.require(Symbol::Else, "expected `else` to end if-else expression") + else { + return Err(()); + }; + + let ParserResult::Value(else_expression) = parse_expression(state) else { + return Err(()); + }; + + Ok(ast::IfExpression { + if_token, + condition: Box::new(condition), + then_token, + if_expression: Box::new(if_expression), + else_if_expressions: if else_if_expressions.is_empty() { + None + } else { + Some(else_if_expressions) + }, + else_token, + else_expression: Box::new(else_expression), + }) +} + +#[cfg(feature = "luau")] +fn expect_interpolated_string( + state: &mut ParserState, + mut current: TokenReference, +) -> ast::InterpolatedString { + use crate::ShortString; + + use super::types::InterpolatedStringSegment; + + let mut segments = Vec::new(); + let first_string = current.clone(); + + loop { + let has_double_brace = if current.trailing_trivia.is_empty() { + if let Some(double_brace) = state.consume_if(Symbol::LeftBrace) { + state.token_error( + double_brace, + "unexpected double brace, try \\{ if you meant to escape", + ); + + true + } else { + false + } + } else { + false + }; + + let expression = match parse_expression(state) { + ParserResult::Value(expression) => expression, + ParserResult::NotFound => { + state.token_error(current, "expected expression after `{`"); + break; + } + ParserResult::LexerMoved => break, + }; + + segments.push(InterpolatedStringSegment { + expression, + literal: current, + }); + + // If incorrectly using `x = {{y}}`, provide a better error message by ignoring the right brace + if has_double_brace { + state.consume_if(Symbol::RightBrace); + } + + let Ok(next) = state.current() else { + break; + }; + + if matches!( + next.token_type(), + TokenType::InterpolatedString { + kind: InterpolatedStringKind::End, + .. + } + ) { + return ast::InterpolatedString { + segments, + last_string: state.consume().unwrap(), + }; + } + + // `hello {"world" "wait"}` + if next.token_kind() != TokenKind::InterpolatedString { + state.token_error( + next.clone(), + "interpolated string parameter can only contain an expression", + ); + break; + } + + current = match state.consume() { + ParserResult::Value(token) => token, + ParserResult::NotFound | ParserResult::LexerMoved => break, + } + } + + ast::InterpolatedString { + last_string: if segments.is_empty() { + first_string + } else { + TokenReference::new( + Vec::new(), + Token::new(TokenType::InterpolatedString { + literal: ShortString::default(), + kind: InterpolatedStringKind::End, + }), + Vec::new(), + ) + }, + + segments, + } +} + +#[cfg(feature = "luau")] +fn parse_type(state: &mut ParserState) -> ParserResult { + let ParserResult::Value(simple_type) = parse_simple_type(state, SimpleTypeStyle::Default) + else { + return ParserResult::LexerMoved; + }; + + parse_type_suffix(state, simple_type) +} + +#[cfg(feature = "luau")] +fn parse_type_or_pack(state: &mut ParserState) -> ParserResult { + let ParserResult::Value(simple_type) = parse_simple_type(state, SimpleTypeStyle::AllowPack) + else { + return ParserResult::LexerMoved; + }; + + // type packs cannot have suffixes + match simple_type { + ast::TypeInfo::Tuple { ref types, .. } if types.len() != 1 => { + ParserResult::Value(simple_type) + } + ast::TypeInfo::VariadicPack { .. } | ast::TypeInfo::GenericPack { .. } => unreachable!(), + _ => parse_type_suffix(state, simple_type), + } +} + +#[cfg(feature = "luau")] +fn parse_type_pack(state: &mut ParserState) -> ParserResult { + let Ok(current_token) = state.current() else { + return ParserResult::NotFound; + }; + + if current_token.is_symbol(Symbol::Ellipse) { + let ellipse = state.consume().unwrap(); + let ParserResult::Value(type_info) = parse_type(state) else { + return ParserResult::LexerMoved; + }; + + ParserResult::Value(ast::TypeInfo::Variadic { + ellipse, + type_info: Box::new(type_info), + }) + } else if current_token.token_kind() == TokenKind::Identifier + && matches!(state.peek(), Ok(token) if token.is_symbol(Symbol::Ellipse)) + { + let name = match parse_name(state) { + ParserResult::Value(name) => name.name, + _ => unreachable!(), + }; + + let Some(ellipse) = state.require(Symbol::Ellipse, "expected `...` after type name") else { + unreachable!() + }; + + ParserResult::Value(ast::TypeInfo::GenericPack { name, ellipse }) + } else { + // rewrite todo: should we be returning this? or should this be unreachable + ParserResult::NotFound + } +} + +#[cfg(feature = "luau")] +#[derive(PartialEq, Eq)] +enum SimpleTypeStyle { + Default, + AllowPack, +} + +#[cfg(feature = "luau")] +fn parse_simple_type( + state: &mut ParserState, + style: SimpleTypeStyle, +) -> ParserResult { + let Ok(current_token) = state.current() else { + return ParserResult::NotFound; + }; + + match current_token.token_type() { + TokenType::Symbol { + symbol: Symbol::Nil, + } => { + let nil_token = state.consume().unwrap(); + ParserResult::Value(ast::TypeInfo::Basic(nil_token)) + } + TokenType::Symbol { + symbol: Symbol::True, + } + | TokenType::Symbol { + symbol: Symbol::False, + } => { + let token = state.consume().unwrap(); + ParserResult::Value(ast::TypeInfo::Boolean(token)) + } + TokenType::StringLiteral { .. } => { + let token = state.consume().unwrap(); + ParserResult::Value(ast::TypeInfo::String(token)) + } + // Interpolated strings cannot be used as types + TokenType::InterpolatedString { .. } => { + let token = state.consume().unwrap(); + state.token_error( + token, + "interpolated string literals cannot be used as types", + ); + ParserResult::LexerMoved + } + TokenType::Identifier { .. } => { + let name = state.consume().unwrap(); + + if name.to_string() == "typeof" { + let left_parenthesis = + match state.require(Symbol::LeftParen, "expected `(` after `typeof`") { + Some(token) => token, + None => TokenReference::basic_symbol("("), + }; + + let ParserResult::Value(expression) = parse_expression(state) else { + return ParserResult::LexerMoved; + }; + + let right_parenthesis = match state.require_with_reference_token( + Symbol::RightParen, + "expected `)` to close typeof call", + &left_parenthesis, + ) { + Some(token) => token, + None => TokenReference::basic_symbol(")"), + }; + + ParserResult::Value(ast::TypeInfo::Typeof { + typeof_token: name, + parentheses: ContainedSpan::new(left_parenthesis, right_parenthesis), + inner: Box::new(expression), + }) + } else { + match state.current() { + Ok(token) if token.is_symbol(Symbol::Dot) => { + let punctuation = state.consume().unwrap(); + + let type_base = match parse_name(state) { + ParserResult::Value(name) => name.name, + ParserResult::NotFound => { + state.token_error( + state.current().unwrap().clone(), + "expected identifier after `.`", + ); + return ParserResult::LexerMoved; + } + ParserResult::LexerMoved => return ParserResult::LexerMoved, + }; + + let type_info = if let Some(left_arrow) = state.consume_if(Symbol::LessThan) + { + let Ok(generics) = expect_generic_type_params(state, left_arrow) else { + return ParserResult::LexerMoved; + }; + ast::IndexedTypeInfo::Generic { + base: type_base, + arrows: generics.arrows, + generics: generics.generics, + } + } else { + ast::IndexedTypeInfo::Basic(type_base) + }; + + ParserResult::Value(ast::TypeInfo::Module { + module: name, + punctuation, + type_info: Box::new(type_info), + }) + } + Ok(token) if token.is_symbol(Symbol::LessThan) => { + let left_arrow = state.consume().unwrap(); + let Ok(generics) = expect_generic_type_params(state, left_arrow) else { + return ParserResult::LexerMoved; + }; + ParserResult::Value(ast::TypeInfo::Generic { + base: name, + arrows: generics.arrows, + generics: generics.generics, + }) + } + _ => ParserResult::Value(ast::TypeInfo::Basic(name)), + } + } + } + TokenType::Symbol { + symbol: Symbol::LeftBrace, + } => { + let left_brace = state.consume().unwrap(); + + match expect_type_table(state, left_brace) { + Ok(table) => ParserResult::Value(table), + Err(_) => ParserResult::LexerMoved, + } + } + TokenType::Symbol { + symbol: Symbol::LeftParen, + } + | TokenType::Symbol { + symbol: Symbol::LessThan, + } => match expect_function_type(state, style) { + Ok(type_info) => ParserResult::Value(type_info), + Err(_) => ParserResult::LexerMoved, + }, + _ => ParserResult::NotFound, + } +} + +#[cfg(feature = "luau")] +fn parse_type_suffix( + state: &mut ParserState, + simple_type: ast::TypeInfo, +) -> ParserResult { + let mut is_union = false; + let mut is_intersection = false; + + let mut current_type = simple_type; + + loop { + let Ok(current_token) = state.current() else { + return ParserResult::NotFound; + }; + + match current_token.token_type() { + TokenType::Symbol { + symbol: Symbol::Pipe, + } => { + if is_intersection { + state.token_error( + current_token.clone(), + "cannot mix union and intersection types", + ); + return ParserResult::LexerMoved; + } + + let pipe = state.consume().unwrap(); + + let ParserResult::Value(right) = parse_simple_type(state, SimpleTypeStyle::Default) + else { + return ParserResult::LexerMoved; + }; + + current_type = ast::TypeInfo::Union { + left: Box::new(current_type), + pipe, + right: Box::new(right), + }; + is_union = true; + } + TokenType::Symbol { + symbol: Symbol::QuestionMark, + } => { + if is_intersection { + state.token_error( + current_token.clone(), + "cannot mix union and intersection types", + ); + return ParserResult::LexerMoved; + } + + let question_mark = state.consume().unwrap(); + current_type = ast::TypeInfo::Optional { + base: Box::new(current_type), + question_mark, + }; + is_union = true; + } + TokenType::Symbol { + symbol: Symbol::Ampersand, + } => { + if is_union { + state.token_error( + current_token.clone(), + "cannot mix union and intersection types", + ); + return ParserResult::LexerMoved; + } + + let ampersand = state.consume().unwrap(); + + let ParserResult::Value(right) = parse_simple_type(state, SimpleTypeStyle::Default) + else { + return ParserResult::LexerMoved; + }; + + current_type = ast::TypeInfo::Intersection { + left: Box::new(current_type), + ampersand, + right: Box::new(right), + }; + is_intersection = true; + } + _ => break, + } + } + + ParserResult::Value(current_type) +} + +#[cfg(feature = "luau")] +fn expect_type_table( + state: &mut ParserState, + left_brace: TokenReference, +) -> Result { + let mut fields = Punctuated::new(); + + let mut has_indexer = false; + let mut array_type = None; + + loop { + let current_token = state.current()?; + + let field = if current_token.is_symbol(Symbol::RightBrace) { + debug_assert!( + array_type.is_none(), + "consuming right brace in loop but have seen array type" + ); + let braces = ContainedSpan::new(left_brace, state.consume().unwrap()); + return Ok(ast::TypeInfo::Table { braces, fields }); + } else if current_token.is_symbol(Symbol::LeftBracket) + && matches!(state.peek(), Ok(token) if token.token_kind() == TokenKind::StringLiteral) + { + let left_brace = state.consume().unwrap(); + let property = state.consume().unwrap(); + let Some(right_brace) = state.require( + Symbol::RightBracket, + "expected `]` to close `[` for type table field", + ) else { + return Err(()); + }; + let Some(colon) = state.require(Symbol::Colon, "expected `:` after type field key") + else { + return Err(()); + }; + + let value = match parse_type(state) { + ParserResult::Value(value) => value, + ParserResult::LexerMoved | ParserResult::NotFound => { + state.token_error( + state.current().unwrap().clone(), + "expected type after type field key", + ); + return Err(()); + } + }; + + ast::TypeField { + key: ast::TypeFieldKey::IndexSignature { + brackets: ContainedSpan::new(left_brace, right_brace), + inner: ast::TypeInfo::String(property), + }, + colon, + value, + } + } else if current_token.is_symbol(Symbol::LeftBracket) { + let left_brace = state.consume().unwrap(); + let key = match parse_type(state) { + ParserResult::Value(value) => value, + ParserResult::NotFound => { + state.token_error( + state.current().unwrap().clone(), + "expected type for type field key", + ); + return Err(()); + } + ParserResult::LexerMoved => return Err(()), + }; + let Some(right_brace) = state.require( + Symbol::RightBracket, + "expected `]` to close `[` for type table field", + ) else { + return Err(()); + }; + let Some(colon) = state.require(Symbol::Colon, "expected `:` after type field key") + else { + return Err(()); + }; + + let value = match parse_type(state) { + ParserResult::Value(value) => value, + ParserResult::NotFound => { + state.token_error( + state.current().unwrap().clone(), + "expected type after type field key", + ); + return Err(()); + } + ParserResult::LexerMoved => return Err(()), + }; + + if has_indexer { + state.token_error_ranged( + left_brace.clone(), + "cannot have more than one table indexer", + &left_brace, + value.tokens().last().unwrap(), + ); + } + has_indexer = true; + + ast::TypeField { + key: ast::TypeFieldKey::IndexSignature { + brackets: ContainedSpan::new(left_brace, right_brace), + inner: key, + }, + colon, + value, + } + } else if fields.is_empty() + && !has_indexer + && !(current_token.token_kind() == TokenKind::Identifier + && matches!(state.peek(), Ok(token) if token.is_symbol(Symbol::Colon))) + { + array_type = Some(match parse_type(state) { + ParserResult::Value(value) => value, + ParserResult::NotFound => { + state.token_error( + state.current().unwrap().clone(), + "expected type for table array", ); + return Err(()); + } + ParserResult::LexerMoved => return Err(()), + }); + break; + } else { + match parse_name(state) { + ParserResult::Value(name) => { + let Some(colon) = + state.require(Symbol::Colon, "expected `:` after type field key") + else { + return Err(()); + }; + let value = match parse_type(state) { + ParserResult::Value(value) => value, + ParserResult::NotFound => { + state.token_error( + state.current().unwrap().clone(), + "expected type after type field key", + ); + return Err(()); + } + ParserResult::LexerMoved => return Err(()), + }; + + ast::TypeField { + key: ast::TypeFieldKey::Name(name.name), + colon, + value, + } + } + ParserResult::NotFound => break, + ParserResult::LexerMoved => return Err(()), + } + }; - (state, TypeInfo::VariadicPack { ellipse, name }) + match state.current() { + Ok(token) => { + if token.is_symbol(Symbol::Comma) || token.is_symbol(Symbol::Semicolon) { + fields.push(Pair::Punctuated(field, state.consume().unwrap())) } else { - return Err(InternalAstError::NoMatch); + fields.push(Pair::End(field)); + break; } - } else if matches!(this.0, TypeInfoContext::ParenthesesType | TypeInfoContext::ReturnType) { - // Only allow variadic type annotation for a return type or a tuple type - if let Ok((state, ellipse)) = ParseSymbol(Symbol::Ellipse).parse(state) { - let (state, type_info) = expect!( - state, - ParseSingleTypeInfo(TypeInfoContext::None).parse(state), - "expected type info after `...`" - ); + } - ( - state, - TypeInfo::Variadic { - ellipse, - type_info: Box::new(type_info), + Err(()) => { + fields.push(Pair::End(field)); + break; + } + }; + } + + let right_brace = state + .require(Symbol::RightBrace, "expected `}` to close type table") + .unwrap_or_else(|| TokenReference::basic_symbol("}")); + + let braces = ContainedSpan::new(left_brace, right_brace); + + if let Some(type_info) = array_type { + Ok(ast::TypeInfo::Array { + braces, + type_info: Box::new(type_info), + }) + } else { + Ok(ast::TypeInfo::Table { braces, fields }) + } +} + +#[cfg(feature = "luau")] +fn expect_function_type( + state: &mut ParserState, + style: SimpleTypeStyle, +) -> Result { + let mut force_function_type = + matches!(state.current(), Ok(token) if token.is_symbol(Symbol::LessThan)); + + let generics = match parse_generic_type_list(state, TypeListStyle::Plain) { + ParserResult::Value(generics) => Some(generics), + ParserResult::NotFound => None, + ParserResult::LexerMoved => return Err(()), + }; + + let mut arguments = Punctuated::new(); + + let Some(left_paren) = state.require(Symbol::LeftParen, "expected `(`") else { + return Err(()); + }; + + while !matches!(state.current(), Ok(token) if token.is_symbol(Symbol::RightParen)) { + // vararg annotation + match parse_type_pack(state) { + ParserResult::Value(type_info) => { + arguments.push(Pair::End(ast::TypeArgument { + name: None, + type_info, + })); + break; + } + ParserResult::LexerMoved => return Err(()), + ParserResult::NotFound => (), + } + + let Ok(current_token) = state.current() else { + return Err(()); + }; + + let name = if current_token.token_kind() == TokenKind::Identifier + && matches!(state.peek(), Ok(token) if token.is_symbol(Symbol::Colon)) + { + Some((state.consume().unwrap(), state.consume().unwrap())) + } else { + None + }; + + let ParserResult::Value(type_info) = parse_type(state) else { + return Err(()); + }; + + let type_argument = ast::TypeArgument { name, type_info }; + + if !matches!(state.current(), Ok(token) if token.is_symbol(Symbol::Comma)) { + arguments.push(Pair::End(type_argument)); + break; + } + + let punctuation = state.consume().unwrap(); + arguments.push(Pair::Punctuated(type_argument, punctuation)); + + if matches!(state.current(), Ok(token) if token.is_symbol(Symbol::RightParen)) { + state.token_error( + state.current().unwrap().clone(), + "expected type after `,` but got `)` instead", + ); + break; + } + } + + let Some(right_paren) = state.require(Symbol::RightParen, "expected `)` to close `(`") else { + return Err(()); + }; + + let parentheses = ContainedSpan::new(left_paren, right_paren); + + if arguments + .iter() + .any(|arg: &ast::TypeArgument| arg.name().is_some()) + { + force_function_type = true; + } + + if !force_function_type + && !matches!(state.current(), Ok(token) if token.is_symbol(Symbol::ThinArrow)) + { + // Simple type wrapped in parentheses (not allowed to be a vararg type), or an allowed type pack + if (arguments.len() == 1 + && !matches!( + arguments.iter().next().unwrap().type_info, + ast::TypeInfo::Variadic { .. } + )) + || style == SimpleTypeStyle::AllowPack + { + return Ok(ast::TypeInfo::Tuple { + parentheses, + types: arguments + .into_pairs() + .map(|pair| pair.map(|argument| argument.type_info)) + .collect(), + }); + } + } + + let Some(arrow) = state.require( + Symbol::ThinArrow, + "expected `->` after `()` for function type", + ) else { + // rewrite todo: luau recovers from this, using an AstTypeError return type + return Err(()); + }; + + let return_type = match parse_return_type(state) { + ParserResult::Value(return_type) => return_type, + ParserResult::LexerMoved | ParserResult::NotFound => return Err(()), + }; + + Ok(ast::TypeInfo::Callback { + generics, + parentheses, + arguments, + arrow, + return_type: Box::new(return_type), + }) +} + +#[cfg(feature = "luau")] +fn expect_type_specifier( + state: &mut ParserState, + punctuation: TokenReference, +) -> Result { + let ParserResult::Value(type_info) = parse_type(state) else { + state.token_error(punctuation, "expected type info after `:`"); + return Err(()); + }; + + Ok(ast::TypeSpecifier { + punctuation, + type_info, + }) +} + +#[cfg(feature = "luau")] +fn parse_return_type(state: &mut ParserState) -> ParserResult { + // rewrite todo: should this be gated behind a check? + match parse_type_pack(state) { + ParserResult::Value(type_info) => ParserResult::Value(type_info), + ParserResult::NotFound => parse_type_or_pack(state), + ParserResult::LexerMoved => ParserResult::LexerMoved, + } +} + +#[cfg(feature = "luau")] +#[derive(PartialEq, Eq)] +enum TypeListStyle { + Plain, + WithDefaults, +} + +#[cfg(feature = "luau")] +fn parse_generic_type_list( + state: &mut ParserState, + style: TypeListStyle, +) -> ParserResult { + if !state.lua_version().has_luau() { + return ParserResult::NotFound; + } + + let Some(left_angle_bracket) = state.consume_if(Symbol::LessThan) else { + return ParserResult::NotFound; + }; + + let mut generics = Punctuated::new(); + + let mut seen_pack = false; + let mut seen_default = false; + + loop { + let name = match state.current() { + Ok(token) if token.token_kind() == TokenKind::Identifier => state.consume().unwrap(), + + Ok(token) => { + state.token_error(token.clone(), "expected a generic type name"); + error_token() + } + + Err(()) => return ParserResult::LexerMoved, + }; + + let Ok(current_token) = state.current() else { + return ParserResult::NotFound; + }; + + let (parameter, default) = if seen_pack || current_token.is_symbol(Symbol::Ellipse) { + seen_pack = true; + + let ellipse = match state.consume_if(Symbol::Ellipse) { + Some(token) => token, + None => { + state.token_error(name.clone(), "generic types come before generic type packs"); + TokenReference::basic_symbol("...") + } + }; + + let default = if style == TypeListStyle::WithDefaults + && matches!(state.current(), Ok(token) if token.is_symbol(Symbol::Equal)) + { + seen_default = true; + let equal_token = state.consume().unwrap(); + + // rewrite todo: behind check? is this backtracking? + let default_type = match parse_type_pack(state) { + ParserResult::Value(type_info) => type_info, + ParserResult::NotFound => match parse_type_or_pack(state) { + ParserResult::Value(type_info) + if matches!(type_info, ast::TypeInfo::Tuple { .. }) => + { + type_info + } + ParserResult::Value(type_info) => { + state.token_error_ranged( + equal_token.clone(), + "expected type pack after `=` but got type instead", + type_info.tokens().next().unwrap(), + type_info.tokens().last().unwrap(), + ); + type_info } + _ => return ParserResult::LexerMoved, + }, + ParserResult::LexerMoved => return ParserResult::LexerMoved, + }; + + Some((equal_token, default_type)) + } else { + if seen_default { + state.token_error( + state.current().unwrap().clone(), + "expected default type after type name", ) - } else { - return Err(InternalAstError::NoMatch); } - } else { - return Err(InternalAstError::NoMatch); + + None }; - Ok((state, base_type)) - }); + ( + ast::GenericParameterInfo::Variadic { name, ellipse }, + default, + ) + } else { + let default = if style == TypeListStyle::WithDefaults + && matches!(state.current(), Ok(token) if token.is_symbol(Symbol::Equal)) + { + seen_default = true; + let equal_token = state.consume().unwrap(); + let default_type = match parse_type(state) { + ParserResult::Value(default_type) => default_type, + _ => return ParserResult::LexerMoved, + }; - #[derive(Clone, Debug, PartialEq)] - struct ParseSingleTypeInfoAtom(TypeInfoContext); - define_parser!(ParseSingleTypeInfoAtom, TypeInfo, |this, state| { - let (mut state, mut base_type) = ParseSingleTypeInfo(this.0).parse(state)?; + Some((equal_token, default_type)) + } else { + if seen_default { + state.token_error( + state.current().unwrap().clone(), + "expected default type after type name", + ) + } - if let Ok((new_state, question_mark)) = ParseSymbol(Symbol::QuestionMark).parse(state) { - base_type = TypeInfo::Optional { - base: Box::new(base_type), - question_mark, - }; + None + }; + + (ast::GenericParameterInfo::Name(name), default) + }; - state = new_state; + match state.current() { + Ok(token) if token.is_symbol(Symbol::Comma) => { + let punctuation = state.consume().unwrap(); + generics.push(Pair::Punctuated( + ast::GenericDeclarationParameter { parameter, default }, + punctuation, + )); + + if let Ok(token) = state.current() { + if token.is_symbol(Symbol::GreaterThan) { + state.token_error( + token.clone(), + "expected type after `,` but got `>` instead", + ); + } + } } + Ok(_) => { + generics.push(Pair::End(ast::GenericDeclarationParameter { + parameter, + default, + })); + break; + } + Err(()) => return ParserResult::LexerMoved, + }; + } - Ok((state, base_type)) - }); + let right_angle_bracket = state + .require(Symbol::GreaterThan, "expected `>` to close generic list") + .unwrap_or_else(|| TokenReference::basic_symbol(">")); - #[derive(Clone, Debug, PartialEq)] - struct ParseTypeInfo(TypeInfoContext); - define_parser!(ParseTypeInfo, TypeInfo, |this, state| { - let (state, base_type) = ParseSingleTypeInfoAtom(this.0).parse(state)?; + ParserResult::Value(ast::GenericDeclaration { + arrows: ContainedSpan::new(left_angle_bracket, right_angle_bracket), + generics, + }) +} - if let Ok((state, pipe)) = ParseSymbol(Symbol::Pipe).parse(state) { - let (state, right) = expect!( - state, - ParseTypeInfo(this.0).parse(state), - "expected type after `|` for union type" - ); - Ok(( - state, - TypeInfo::Union { - left: Box::new(base_type), - right: Box::new(right), - pipe, - }, - )) - } else if let Ok((state, ampersand)) = ParseSymbol(Symbol::Ampersand).parse(state) { - let (state, right) = expect!( - state, - ParseTypeInfo(this.0).parse(state), - "expected type after `&` for intersection type" +#[cfg(feature = "luau")] +struct GenericTypeParams { + arrows: ContainedSpan, + generics: Punctuated, +} + +#[cfg(feature = "luau")] +fn expect_generic_type_params( + state: &mut ParserState, + left_arrow: TokenReference, +) -> Result { + let mut generics = Punctuated::new(); + + loop { + if state.current()?.is_symbol(Symbol::GreaterThan) { + break; + } + + let type_info = match parse_type_pack(state) { + ParserResult::Value(type_info) => type_info, + ParserResult::NotFound => match parse_type_or_pack(state) { + ParserResult::Value(type_info) => type_info, + _ => return Err(()), + }, + ParserResult::LexerMoved => return Err(()), + }; + + if let Some(punctuation) = state.consume_if(Symbol::Comma) { + generics.push(Pair::Punctuated(type_info, punctuation)); + if state.current()?.is_symbol(Symbol::GreaterThan) { + state.token_error( + state.current()?.clone(), + "expected type after ',' but got '>' instead", ); - Ok(( - state, - TypeInfo::Intersection { - left: Box::new(base_type), - right: Box::new(right), - ampersand, - }, - )) - } else { - Ok((state, base_type)) + break; } - }); + } else { + generics.push(Pair::End(type_info)); + break; + } + } - #[derive(Clone, Debug, PartialEq)] - struct ParseTypeField; - define_parser!( - ParseTypeField, - TypeField, - |_, state| { - let (state, key) = ParseTypeFieldKey.parse(state)?; - - let (state, colon) = expect!( - state, - ParseSymbol(Symbol::Colon).parse(state), - "expected `:` after key" - ); + let Some(right_arrow) = state.require( + Symbol::GreaterThan, + "expected '>' to close generic type parameter list", + ) else { + return Err(()); + }; - let (state, value) = expect!( - state, - ParseTypeInfo(TypeInfoContext::None).parse(state), - "expected value type for key" - ); + Ok(GenericTypeParams { + arrows: ContainedSpan::new(left_arrow, right_arrow), + generics, + }) +} + +#[derive(Clone)] +struct Name { + name: TokenReference, + #[cfg(feature = "lua54")] + attribute: Option, + #[cfg(feature = "luau")] + type_specifier: Option, +} + +#[cfg(feature = "luau")] +fn parse_name(state: &mut ParserState) -> ParserResult { + let Ok(current_token) = state.current() else { + return ParserResult::NotFound; + }; + + match current_token.token_type() { + TokenType::Identifier { .. } => { + let name_token = state.consume().unwrap(); + ParserResult::Value(force_name(state, name_token)) + } + + _ => ParserResult::NotFound, + } +} + +fn parse_name_with_attributes(state: &mut ParserState) -> ParserResult { + let Ok(current_token) = state.current() else { + return ParserResult::NotFound; + }; + + match current_token.token_type() { + TokenType::Identifier { .. } => { + let name_token = state.consume().unwrap(); + ParserResult::Value(force_name_with_attributes(state, name_token)) + } + + _ => ParserResult::NotFound, + } +} + +fn parse_name_with_type_specifiers(state: &mut ParserState) -> ParserResult { + let Ok(current_token) = state.current() else { + return ParserResult::NotFound; + }; + + match current_token.token_type() { + TokenType::Identifier { .. } => { + let name_token = state.consume().unwrap(); + ParserResult::Value(force_name_with_type_specifiers(state, name_token)) + } + + _ => ParserResult::NotFound, + } +} + +fn force_name(_state: &mut ParserState, name: TokenReference) -> Name { + Name { + name, + #[cfg(feature = "lua54")] + attribute: None, + #[cfg(feature = "luau")] + type_specifier: None, + } +} + +#[cfg(feature = "lua54")] +fn force_name_with_attributes(state: &mut ParserState, name: TokenReference) -> Name { + // NOTE: whenever attributes can be parsed, type specifiers are possible + // so we should fall back to parsing type specifiers if an attribute is not found. + // NOTE: we do not attempt to parse both type specifiers and attributes at the same time + if !state.lua_version().has_lua54() { + return force_name_with_type_specifiers(state, name); + } - Ok((state, TypeField { key, colon, value })) + #[cfg(feature = "lua54")] + if let Some(left_angle_bracket) = state.consume_if(Symbol::LessThan) { + const ERROR_INVALID_ATTRIBUTE: &str = "expected identifier after `<` for attribute"; + + let attribute_name = match state.current() { + Ok(token) if matches!(token.token_type(), TokenType::Identifier { .. }) => { + state.consume().unwrap() } - ); - #[derive(Clone, Debug, PartialEq)] - struct ParseTypeFieldKey; - #[rustfmt::skip] - define_parser!(ParseTypeFieldKey, TypeFieldKey, |_, state| { - if let Ok((state, identifier)) = ParseIdentifier.parse(state) { - Ok((state, TypeFieldKey::Name(identifier))) - } else if let Ok((state, start_bracket)) = ParseSymbol(Symbol::LeftBracket).parse(state) - { - let (state, inner) = expect!( - state, - ParseTypeInfo(TypeInfoContext::None).parse(state), - "expected type within brackets for index signature" + Ok(token) => { + state.token_error_ranged( + token.clone(), + ERROR_INVALID_ATTRIBUTE, + &left_angle_bracket, + &token.clone(), ); - let (state, end_bracket) = expect!( - state, - ParseSymbol(Symbol::RightBracket).parse(state), - "expected `]` to match `[`" - ); + return Name { + name, + attribute: None, + #[cfg(feature = "luau")] + type_specifier: None, + }; + } - Ok(( - state, - TypeFieldKey::IndexSignature { - brackets: ContainedSpan::new(start_bracket, end_bracket), - inner, - }, - )) - } else { - Err(InternalAstError::NoMatch) + Err(()) => { + state.token_error(left_angle_bracket, ERROR_INVALID_ATTRIBUTE); + + return Name { + name, + attribute: None, + #[cfg(feature = "luau")] + type_specifier: None, + }; } - }); + }; + + let Some(right_angle_bracket) = + state.require(Symbol::GreaterThan, "expected `>` to close attribute") + else { + return Name { + name, + attribute: Some(super::lua54::Attribute { + brackets: ContainedSpan::new( + left_angle_bracket, + TokenReference::basic_symbol(">"), + ), + name: attribute_name, + }), + #[cfg(feature = "luau")] + type_specifier: None, + }; + }; + + return Name { + name, + attribute: Some(super::lua54::Attribute { + brackets: ContainedSpan::new(left_angle_bracket, right_angle_bracket), + name: attribute_name, + }), + #[cfg(feature = "luau")] + type_specifier: None, + }; } + + force_name_with_type_specifiers(state, name) } -// Lua 5.2 related syntax -#[derive(Clone, Debug, PartialEq)] -struct ParseGoto; -define_lua52_parser!(ParseGoto, Goto, TokenReference, |_, state| { - let (state, goto_token) = ParseSymbol(Symbol::Goto).parse(state)?; - let (state, label_name) = expect!( - state, - ParseIdentifier.parse(state), - "expected identifier after `goto`" - ); - - Ok(( - state, - Goto { - goto_token, - label_name, - }, - )) -}); - -#[derive(Clone, Debug, PartialEq)] -struct ParseLabel; -define_lua52_parser!(ParseLabel, Label, TokenReference, |_, state| { - let (state, left_colons) = ParseSymbol(Symbol::TwoColons).parse(state)?; - let (state, name) = expect!( - state, - ParseIdentifier.parse(state), - "expected identifier after `::`" - ); - let (state, right_colons) = expect!( - state, - ParseSymbol(Symbol::TwoColons).parse(state), - "expected `::`" - ); - - Ok(( - state, - Label { - left_colons, - name, - right_colons, - }, - )) -}); - -cfg_if::cfg_if! { - if #[cfg(feature = "lua54")] { - #[derive(Clone, Debug, PartialEq)] - struct ParseAttribute; - define_parser!(ParseAttribute, Attribute, |_, state| { - let (state, left_angle_bracket) = ParseSymbol(Symbol::LessThan).parse(state)?; - let (state, name) = expect!( - state, - ParseIdentifier.parse(state), - "expected identifier after `<`" - ); - let (state, right_angle_bracket) = expect!( - state, - ParseSymbol(Symbol::GreaterThan).parse(state), - "expected `>`" - ); +#[cfg(feature = "luau")] +fn force_name_with_type_specifiers(state: &mut ParserState, name: TokenReference) -> Name { + if !state.lua_version().has_luau() { + return force_name(state, name); + } - Ok(( - state, - Attribute { - brackets: ContainedSpan::new(left_angle_bracket, right_angle_bracket), - name, - }, - )) - }); + if let Some(punctuation) = state.consume_if(Symbol::Colon) { + let Ok(type_specifier) = expect_type_specifier(state, punctuation) else { + return Name { + name, + #[cfg(feature = "lua52")] + attribute: None, + type_specifier: None, + }; + }; + + Name { + name, + #[cfg(feature = "lua52")] + attribute: None, + type_specifier: Some(type_specifier), + } + } else { + force_name(state, name) } } -macro_rules! make_op_parser { - ($enum:ident, $parser:ident, { $($(#[$inner:meta])* $operator:ident,)+ }) => { - #[derive(Clone, Debug, PartialEq)] - struct $parser; - define_parser!($parser, $enum, |_, state| { - $( - $(#[$inner])* - if let Ok((state, operator)) = ParseSymbol(Symbol::$operator).parse(state) { - return Ok((state, $enum::$operator(operator))); - } - )+ - - // This is to ensure the operators ALWAYS match those in the actual operator - // It won't compile if they don't match up - if let Some(x) = None { - match x { - $( - $(#[$inner])* - $enum::$operator(_) => {}, - )+ - } - } - - Err(InternalAstError::NoMatch) - }); - }; +#[cfg(not(feature = "luau"))] +fn force_name_with_type_specifiers(state: &mut ParserState, name: TokenReference) -> Name { + force_name(state, name) } -#[derive(Clone, Debug, PartialEq)] -struct ParseBinOp; -define_parser!(ParseBinOp, BinOp, |_, state| { - if let Ok((state, operator)) = ParseSymbol(Symbol::And).parse(state) { - Ok((state, BinOp::And(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::Caret).parse(state) { - Ok((state, BinOp::Caret(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::GreaterThan).parse(state) { - // Lua 5.3 special case. If we find another Symbol::GreaterThan, merge them together into a DoubleGreaterThan - // We can't do this in the tokenizer since it collides with Luau generics for Array> - // We must ensure there is no whitespace in between the two symbols - #[cfg(feature = "lua53")] - if operator.trailing_trivia().next().is_none() { - if let Ok((state, operator2)) = ParseSymbol(Symbol::GreaterThan).parse(state) { - let merged_token = Token { - start_position: operator.start_position, - end_position: operator2.end_position, - token_type: TokenType::Symbol { - symbol: Symbol::DoubleGreaterThan, - }, - }; +#[cfg(not(feature = "lua54"))] +fn force_name_with_attributes(state: &mut ParserState, name: TokenReference) -> Name { + force_name_with_type_specifiers(state, name) +} - let merged_operator = TokenReference::new( - operator.leading_trivia, - merged_token, - operator2.trailing_trivia, - ); - return Ok((state, BinOp::DoubleGreaterThan(merged_operator))); - } - } - - Ok((state, BinOp::GreaterThan(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::GreaterThanEqual).parse(state) { - Ok((state, BinOp::GreaterThanEqual(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::LessThan).parse(state) { - Ok((state, BinOp::LessThan(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::LessThanEqual).parse(state) { - Ok((state, BinOp::LessThanEqual(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::Minus).parse(state) { - Ok((state, BinOp::Minus(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::Or).parse(state) { - Ok((state, BinOp::Or(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::Percent).parse(state) { - Ok((state, BinOp::Percent(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::Plus).parse(state) { - Ok((state, BinOp::Plus(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::Slash).parse(state) { - Ok((state, BinOp::Slash(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::Star).parse(state) { - Ok((state, BinOp::Star(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::TildeEqual).parse(state) { - Ok((state, BinOp::TildeEqual(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::TwoDots).parse(state) { - Ok((state, BinOp::TwoDots(operator))) - } else if let Ok((state, operator)) = ParseSymbol(Symbol::TwoEqual).parse(state) { - Ok((state, BinOp::TwoEqual(operator))) - } else { - // Luau & Lua 5.3 - #[cfg(any(feature = "roblox", feature = "lua53"))] - if let Ok((state, operator)) = ParseSymbol(Symbol::DoubleSlash).parse(state) { - return Ok((state, BinOp::DoubleSlash(operator))); - } +fn one_or_more ParserResult>( + state: &mut ParserState, + parser: F, + delimiter: Symbol, +) -> ParserResult> { + let mut values = Punctuated::new(); - // Lua 5.3 - #[cfg(feature = "lua53")] - if let Ok((state, operator)) = ParseSymbol(Symbol::Ampersand).parse(state) { - return Ok((state, BinOp::Ampersand(operator))); - } else if let Ok((state, operator)) = ParseSymbol(Symbol::DoubleLessThan).parse(state) { - return Ok((state, BinOp::DoubleLessThan(operator))); - } else if let Ok((state, operator)) = ParseSymbol(Symbol::Pipe).parse(state) { - return Ok((state, BinOp::Pipe(operator))); - } else if let Ok((state, operator)) = ParseSymbol(Symbol::Tilde).parse(state) { - return Ok((state, BinOp::Tilde(operator))); - } + loop { + let value = match parser(state) { + ParserResult::Value(value) => value, + ParserResult::NotFound | ParserResult::LexerMoved => break, + }; + + match state.consume_if(delimiter) { + Some(delimiter) => { + values.push(Pair::Punctuated(value, delimiter)); + } - Err(InternalAstError::NoMatch) + None => { + values.push(Pair::End(value)); + break; + } + } } -}); -make_op_parser!(UnOp, ParseUnOp, - { - Minus, - Not, - Hash, - #[cfg(feature = "lua53")] - Tilde, + if values.is_empty() { + return ParserResult::NotFound; } -); -#[cfg(feature = "roblox")] -make_op_parser!(CompoundOp, ParseCompoundOp, - { - PlusEqual, - MinusEqual, - StarEqual, - SlashEqual, - DoubleSlashEqual, - PercentEqual, - CaretEqual, - TwoDotsEqual, + if let Some(Pair::Punctuated(..)) = values.last() { + let last_value = values.pop().unwrap(); + + state.token_error( + last_value.punctuation().unwrap().clone(), + "trailing commas are not allowed", + ); + + values.push(Pair::End(last_value.into_value())); } -); - -// TODO - -// #[cfg(test)] -// mod tests { -// use super::*; -// use crate::{ast::extract_token_references, tokenizer::tokens}; -// use pretty_assertions::assert_eq; - -// macro_rules! assert_state_eq { -// ($state: expr, $index: expr, $tokens: ident) => { -// assert_eq!($state.index, $index); -// assert_eq!($state.len, $tokens.len()); -// }; -// } - -// macro_rules! tokens { -// ($body: expr) => { -// extract_token_references(tokens($body).expect("couldn't tokenize'")) -// }; -// } - -// #[test] -// fn test_zero_or_more_empty() { -// let tokens = tokens!("local x"); -// let state = ParserState::new(&tokens); - -// let (state, commas) = ZeroOrMore(ParseSymbol(Symbol::Comma)) -// .parse(state) -// .unwrap(); - -// assert_state_eq!(state, 0, tokens); -// assert_eq!(commas.len(), 0); -// } - -// #[test] -// fn test_zero_or_more_exists() { -// let tokens = tokens!(",,, , ,\t ,local x"); -// let state = ParserState::new(&tokens); - -// let (state, commas) = ZeroOrMore(ParseSymbol(Symbol::Comma)) -// .parse(state) -// .unwrap(); - -// assert_state_eq!(state, 9, tokens); -// assert_eq!(commas.len(), 6); -// } - -// #[test] -// fn test_one_or_more_empty() { -// let tokens = tokens!("local x"); -// let state = ParserState::new(&tokens); - -// assert!( -// OneOrMore(ParseSymbol(Symbol::End), ParseSymbol(Symbol::Comma), false) -// .parse(state) -// .is_err() -// ); -// } - -// #[test] -// fn test_one_or_more_exists_no_delimiter() { -// let tokens = tokens!("end,end, end,\t\tend local"); -// let state = ParserState::new(&tokens); - -// let (state, commas) = -// OneOrMore(ParseSymbol(Symbol::End), ParseSymbol(Symbol::Comma), false) -// .parse(state) -// .expect("OneOrMore failed"); - -// assert_state_eq!(state, 10, tokens); -// assert_eq!(commas.len(), 4); -// } - -// #[test] -// fn test_one_or_more_exists_with_delimiter() { -// let tokens = tokens!("end,end, end,\t\tend, local"); -// let state = ParserState::new(&tokens); - -// let (state, commas) = OneOrMore(ParseSymbol(Symbol::End), ParseSymbol(Symbol::Comma), true) -// .parse(state) -// .unwrap(); - -// assert_state_eq!(state, 11, tokens); -// assert_eq!(commas.len(), 4); -// } - -// #[test] -// fn test_one_or_more_exists_with_nothing() { -// let tokens = tokens!("local"); -// let state = ParserState::new(&tokens); - -// assert!( -// OneOrMore(ParseSymbol(Symbol::End), ParseSymbol(Symbol::Comma), true) -// .parse(state) -// .is_err() -// ); -// } -// } + + ParserResult::Value(values) +} + +fn parse_name_list(state: &mut ParserState) -> ParserResult> { + one_or_more(state, parse_name_with_type_specifiers, Symbol::Comma) +} + +fn parse_expression_list(state: &mut ParserState) -> ParserResult> { + one_or_more(state, parse_expression, Symbol::Comma) +} diff --git a/full-moon/src/ast/punctuated.rs b/full-moon/src/ast/punctuated.rs index 99901e67..598ffedd 100644 --- a/full-moon/src/ast/punctuated.rs +++ b/full-moon/src/ast/punctuated.rs @@ -8,7 +8,7 @@ //! Everything with punctuation uses the [`Punctuated`](Punctuated) type with the following logic. //! ```rust //! # use full_moon::parse; -//! # fn main() -> Result<(), Box> { +//! # fn main() -> Result<(), Vec> { //! let ast = parse("call(arg1, arg2, arg3)")?; //! // ^^^^^ ~~~~~ ^^^^^ //! # Ok(()) @@ -29,7 +29,7 @@ use std::{fmt::Display, iter::FromIterator}; /// A punctuated sequence of node `T` separated by /// [`TokenReference`](crate::tokenizer::TokenReference). /// Refer to the [module documentation](index.html) for more details. -#[derive(Clone, Debug, Default, Display, PartialEq, Eq)] +#[derive(Clone, Debug, Display, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] #[display(bound = "T: Display")] #[display(fmt = "{}", "util::join_vec(pairs)")] @@ -182,6 +182,29 @@ impl Punctuated { pub fn push(&mut self, pair: Pair) { self.pairs.push(pair); } + + /// Pushes a new node `T` onto the sequence, with the given punctuation. + /// Will apply the punctuation to the last item, which must exist. + pub fn push_punctuated(&mut self, value: T, punctuation: TokenReference) { + let last_pair = self.pairs.pop().expect( + "push_punctuated adds the punctuation onto the last element, but there are no elements", + ); + + if last_pair.punctuation().is_some() { + self.pairs.push(last_pair); + panic!("push_punctuated adds the punctuation onto the last element, but the last element already has punctuation"); + } + + self.pairs + .push(Pair::Punctuated(last_pair.into_value(), punctuation)); + self.pairs.push(Pair::new(value, None)); + } +} + +impl Default for Punctuated { + fn default() -> Self { + Self::new() + } } impl Sealed for Punctuated {} diff --git a/full-moon/src/ast/types.rs b/full-moon/src/ast/types.rs index 5a2b2f36..4bcde2e6 100644 --- a/full-moon/src/ast/types.rs +++ b/full-moon/src/ast/types.rs @@ -676,19 +676,22 @@ impl ExportedTypeDeclaration { } } -make_op!(CompoundOp, - #[doc = "Compound operators, such as X += Y or X -= Y"] - { - PlusEqual, - MinusEqual, - StarEqual, - SlashEqual, - DoubleSlashEqual, - PercentEqual, - CaretEqual, - TwoDotsEqual, - } -); +#[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[non_exhaustive] +#[allow(missing_docs)] +#[display(fmt = "{}")] +/// Compound operators, such as X += Y or X -= Y +pub enum CompoundOp { + PlusEqual(TokenReference), + MinusEqual(TokenReference), + StarEqual(TokenReference), + SlashEqual(TokenReference), + DoubleSlashEqual(TokenReference), + PercentEqual(TokenReference), + CaretEqual(TokenReference), + TwoDotsEqual(TokenReference), +} impl CompoundOp { /// The token associated with the operator @@ -704,6 +707,28 @@ impl CompoundOp { | Self::TwoDotsEqual(token) => token, } } + + pub(crate) fn from_token(token: TokenReference) -> Self { + if token.is_symbol(Symbol::PlusEqual) { + Self::PlusEqual(token) + } else if token.is_symbol(Symbol::MinusEqual) { + Self::MinusEqual(token) + } else if token.is_symbol(Symbol::StarEqual) { + Self::StarEqual(token) + } else if token.is_symbol(Symbol::SlashEqual) { + Self::SlashEqual(token) + } else if token.is_symbol(Symbol::DoubleSlashEqual) { + Self::DoubleSlashEqual(token) + } else if token.is_symbol(Symbol::PercentEqual) { + Self::PercentEqual(token) + } else if token.is_symbol(Symbol::CaretEqual) { + Self::CaretEqual(token) + } else if token.is_symbol(Symbol::TwoDotsEqual) { + Self::TwoDotsEqual(token) + } else { + unreachable!("converting an unknown token into a compound operator") + } + } } /// A Compound Assignment statement, such as `x += 1` or `x -= 1` diff --git a/full-moon/src/ast/versions.rs b/full-moon/src/ast/versions.rs new file mode 100644 index 00000000..1460d0ff --- /dev/null +++ b/full-moon/src/ast/versions.rs @@ -0,0 +1,133 @@ +// Lua version is handled as a bitfield to support parsing as many languages as possible at once. +// Any new language added does not necessarily need to (or should be) added to the default set. +const VERSION_LUAU: u8 = 1 << 0; +const VERSION_LUA52: u8 = 1 << 1; +const VERSION_LUA53: u8 = 1 << 2; +const VERSION_LUA54: u8 = 1 << 3; + +/// Represents the Lua version(s) to parse as. +/// Lua 5.1 is always included. +/// In order to get more Lua versions, you must include their respective features. +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub struct LuaVersion { + bitfield: u8, +} + +impl LuaVersion { + /// Creates a new LuaVersion with the default features: Luau, Lua 5.2, Lua 5.3, and Lua 5.4. + pub fn new() -> Self { + Self::default() + } + + /// Creates a new LuaVersion with only Lua 5.1. + pub fn lua51() -> Self { + Self { bitfield: 0 } + } + + /// Creates a new LuaVersion with only Luau. + #[cfg(feature = "luau")] + pub fn luau() -> Self { + Self { + bitfield: VERSION_LUAU, + } + } + + /// Adds Luau as a version to parse for. + #[cfg(feature = "luau")] + pub fn with_luau(self) -> Self { + Self { + bitfield: self.bitfield | VERSION_LUAU, + } + } + + /// Returns true if Luau is enabled. + pub fn has_luau(self) -> bool { + cfg!(feature = "luau") && (self.bitfield & VERSION_LUAU != 0) + } + + /// Creates a new LuaVersion with only Lua 5.2. + #[cfg(feature = "lua52")] + pub fn lua52() -> Self { + Self { + bitfield: VERSION_LUA52, + } + } + + /// Adds Lua 5.2 as a version to parse for. + #[cfg(feature = "lua52")] + pub fn with_lua52(self) -> Self { + self | Self::lua52() + } + + /// Returns true if Lua 5.2 is enabled. + pub fn has_lua52(self) -> bool { + cfg!(feature = "lua52") && (self.bitfield & VERSION_LUA52 != 0) + } + + /// Creates a new LuaVersion with only Lua 5.3. + #[cfg(feature = "lua53")] + pub fn lua53() -> Self { + Self { + bitfield: VERSION_LUA52 | VERSION_LUA53, + } + } + + /// Adds Lua 5.3 as a version to parse for. + #[cfg(feature = "lua53")] + pub fn with_lua53(self) -> Self { + self | Self::lua53() + } + + /// Returns true if Lua 5.3 is enabled. + pub fn has_lua53(self) -> bool { + cfg!(feature = "lua53") && (self.bitfield & VERSION_LUA53 != 0) + } + + /// Creates a new LuaVersion with only Lua 5.4. + #[cfg(feature = "lua54")] + pub fn lua54() -> Self { + Self { + bitfield: VERSION_LUA52 | VERSION_LUA53 | VERSION_LUA54, + } + } + + /// Adds Lua 5.4 as a version to parse for. + #[cfg(feature = "lua54")] + pub fn with_lua54(self) -> Self { + self | Self::lua54() + } + + /// Returns true if Lua 5.4 is enabled. + pub fn has_lua54(self) -> bool { + cfg!(feature = "lua54") && (self.bitfield & VERSION_LUA54 != 0) + } +} + +impl Default for LuaVersion { + fn default() -> Self { + Self { + bitfield: VERSION_LUAU | VERSION_LUA52 | VERSION_LUA53 | VERSION_LUA54, + } + } +} + +impl std::ops::BitOr for LuaVersion { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self { + bitfield: self.bitfield | rhs.bitfield, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn lua51_sanity() { + assert!(!LuaVersion::lua51().has_lua52()); + assert!(!LuaVersion::lua51().has_lua53()); + } +} diff --git a/full-moon/src/ast/visitors.rs b/full-moon/src/ast/visitors.rs index a42f7733..667d8b0c 100644 --- a/full-moon/src/ast/visitors.rs +++ b/full-moon/src/ast/visitors.rs @@ -111,12 +111,12 @@ impl Visit for Expression { function_call.visit(visitor); } - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] Expression::IfExpression(if_expression) => { if_expression.visit(visitor); } - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] Expression::InterpolatedString(interpolated_string) => { interpolated_string.visit(visitor); } @@ -125,7 +125,7 @@ impl Visit for Expression { table_constructor.visit(visitor); } - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] Expression::TypeAssertion { expression, type_assertion, @@ -185,12 +185,12 @@ impl VisitMut for Expression { Expression::FunctionCall(function_call.visit_mut(visitor)) } - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] Expression::IfExpression(if_expression) => { Expression::IfExpression(if_expression.visit_mut(visitor)) } - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] Expression::InterpolatedString(interpolated_string) => { Expression::InterpolatedString(interpolated_string.visit_mut(visitor)) } @@ -199,7 +199,7 @@ impl VisitMut for Expression { Expression::TableConstructor(table_constructor.visit_mut(visitor)) } - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] Expression::TypeAssertion { expression, type_assertion, @@ -329,19 +329,19 @@ impl Visit for FunctionBody { fn visit(&self, visitor: &mut V) { visitor.visit_function_body(self); - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] self.generics.visit(visitor); self.parameters_parentheses.tokens.0.visit(visitor); let mut type_specifiers; - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { type_specifiers = self.type_specifiers(); } - #[cfg(not(feature = "roblox"))] + #[cfg(not(feature = "luau"))] { // TODO: Option, and implement Visit for ! type_specifiers = std::iter::repeat::>(None); @@ -354,7 +354,7 @@ impl Visit for FunctionBody { self.parameters_parentheses.tokens.1.visit(visitor); - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] self.return_type.visit(visitor); self.block.visit(visitor); @@ -367,7 +367,7 @@ impl VisitMut for FunctionBody { fn visit_mut(mut self, visitor: &mut V) -> Self { self = visitor.visit_function_body(self); - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { self.generics = self.generics.visit_mut(visitor); } @@ -377,12 +377,12 @@ impl VisitMut for FunctionBody { let mut type_specifiers; - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { type_specifiers = self.type_specifiers.into_iter(); } - #[cfg(not(feature = "roblox"))] + #[cfg(not(feature = "luau"))] { // TODO: Option, and implement VisitMut for ! type_specifiers = std::iter::repeat::>(None); @@ -407,7 +407,7 @@ impl VisitMut for FunctionBody { self.parameters = new_parameters; - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { self.type_specifiers = new_type_specifiers; } @@ -415,7 +415,7 @@ impl VisitMut for FunctionBody { self.parameters_parentheses.tokens.1 = self.parameters_parentheses.tokens.1.visit_mut(visitor); - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { self.return_type = self.return_type.visit_mut(visitor); } @@ -446,12 +446,12 @@ impl Visit for LocalAssignment { attributes = std::iter::repeat::>(None); } - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { type_specifiers = self.type_specifiers(); } - #[cfg(not(feature = "roblox"))] + #[cfg(not(feature = "luau"))] { // TODO: Option, and implement Visit for ! type_specifiers = std::iter::repeat::>(None); @@ -488,12 +488,12 @@ impl VisitMut for LocalAssignment { attributes = std::iter::repeat::>(None); } - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { type_specifiers = self.type_specifiers.into_iter(); } - #[cfg(not(feature = "roblox"))] + #[cfg(not(feature = "luau"))] { // TODO: Option, and implement VisitMut for ! type_specifiers = std::iter::repeat::>(None); @@ -528,7 +528,7 @@ impl VisitMut for LocalAssignment { self.attributes = new_attributes; } - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { self.type_specifiers = new_type_specifiers; } @@ -547,12 +547,12 @@ impl Visit for GenericFor { let mut type_specifiers; - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { type_specifiers = self.type_specifiers(); } - #[cfg(not(feature = "roblox"))] + #[cfg(not(feature = "luau"))] { // TODO: Option, and implement Visit for ! type_specifiers = std::iter::repeat::>(None); @@ -580,12 +580,12 @@ impl VisitMut for GenericFor { let mut type_specifiers; - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { type_specifiers = self.type_specifiers.into_iter(); } - #[cfg(not(feature = "roblox"))] + #[cfg(not(feature = "luau"))] { // TODO: Option, and implement VisitMut for ! type_specifiers = std::iter::repeat::>(None); @@ -609,7 +609,7 @@ impl VisitMut for GenericFor { self.names = new_names; - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { self.type_specifiers = new_type_specifiers; } @@ -631,7 +631,7 @@ impl Visit for NumericFor { self.for_token.visit(visitor); self.index_variable.visit(visitor); - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] self.type_specifier.visit(visitor); self.equal_token.visit(visitor); @@ -654,7 +654,7 @@ impl VisitMut for NumericFor { self.for_token = self.for_token.visit_mut(visitor); self.index_variable = self.index_variable.visit_mut(visitor); - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] { self.type_specifier = self.type_specifier.visit_mut(visitor); } diff --git a/full-moon/src/atom.rs b/full-moon/src/atom.rs deleted file mode 100644 index f8f40ef7..00000000 --- a/full-moon/src/atom.rs +++ /dev/null @@ -1,462 +0,0 @@ -use logos::{Lexer, Logos}; - -use crate::ShortString; - -pub fn trim_bracket_head(slice: &str) -> (ShortString, Option) { - match test_bracket_head(slice) { - Some(count) => { - let trim = &slice[count + 2..slice.len() - count - 2]; - - (trim.into(), Some(count)) - } - - None => (slice.into(), None), - } -} - -fn test_bracket_head(slice: &str) -> Option { - if !slice.starts_with('[') { - return None; - } - - let count = slice.chars().skip(1).take_while(|&v| v == '=').count(); - - if !matches!(slice.chars().nth(count + 1), Some('[')) { - return None; - } - - Some(count) -} - -fn read_string(lex: &mut Lexer, quote: char) -> bool { - let mut escape = false; - #[cfg(any(feature = "lua52", feature = "roblox"))] - let mut z_escaped = false; - for char in lex.remainder().chars() { - match (escape, char) { - #[cfg(any(feature = "lua52", feature = "roblox"))] - (true, 'z') => { - escape = false; - z_escaped = true - } - (true, ..) => { - escape = false; - #[cfg(feature = "lua52")] - { - // support for '\' followed by a newline - if !z_escaped { - z_escaped = true; - } - } - } - (false, '\\') => escape = true, - #[cfg(any(feature = "lua52", feature = "roblox"))] - (false, '\n' | '\r') if z_escaped => z_escaped = false, - (false, '\n' | '\r') => break, - (false, ..) if char == quote => { - lex.bump(1); - return true; - } - _ => {} - } - lex.bump(char.len_utf8()); - } - false -} - -fn proceed_with_bracketed(lex: &mut Lexer, block_count: usize) -> bool { - let mut in_tail = false; - let mut current_count = 0; - - for (pos, char) in lex.remainder().char_indices() { - match (in_tail, char) { - (true, '=') => current_count += 1, - (true, ']') if block_count == current_count => { - lex.bump(pos + 1); - - return true; - } - (_, ']') => { - in_tail = true; - current_count = 0; - } - _ => in_tail = false, - } - } - - false -} - -fn read_bracketed(lex: &mut Lexer, skips: usize) -> bool { - let block_count = match lex.slice().get(skips..).and_then(test_bracket_head) { - Some(value) => value, - None => return false, - }; - - proceed_with_bracketed(lex, block_count) -} - -fn read_comment(lexer: &mut Lexer) -> bool { - let mut remainder = lexer.remainder().char_indices().peekable(); - - if matches!(remainder.peek(), Some((_, '['))) { - remainder.next(); - - let mut block_count = 0; - - loop { - let next = remainder.next(); - - match next { - Some((_, '=')) => block_count += 1, - - Some((offset, '[')) => { - // Confirmed real multi-line comment - lexer.bump(offset + 1); - return proceed_with_bracketed(lexer, block_count); - } - - // Not a multi-line comment, just --[text - Some((offset, _)) => { - lexer.bump(offset); - break; - } - - None => return false, - } - } - } - - // Normal single line comment. - // Reset remainder since it might've been bumped. - let mut current_offset = 0; - for (offset, char) in lexer.remainder().char_indices() { - if char == '\n' { - lexer.bump(offset); - return true; - } - current_offset = offset + char.len_utf8(); - } - - // The rest of the string is a comment - lexer.bump(current_offset); - true -} - -#[cfg(not(feature = "roblox"))] -fn read_right_brace(_: &mut Lexer) -> Option> { - Some(None) -} - -#[derive(Clone, Debug, Default)] -pub(crate) struct TokenizerState { - #[cfg(feature = "roblox")] - pub brace_stack: Vec, -} - -#[derive(Logos, Debug, Clone, Copy, PartialEq, Eq)] -#[logos(extras = TokenizerState)] -pub(crate) enum Atom { - #[token("and")] - And, - - #[token("break")] - Break, - - #[token("do")] - Do, - - #[token("else")] - Else, - - #[token("elseif")] - ElseIf, - - #[token("end")] - End, - - #[token("false")] - False, - - #[token("for")] - For, - - #[token("function")] - Function, - - #[token("if")] - If, - - #[token("in")] - In, - - #[token("local")] - Local, - - #[token("nil")] - Nil, - - #[token("not")] - Not, - - #[token("or")] - Or, - - #[token("repeat")] - Repeat, - - #[token("return")] - Return, - - #[token("then")] - Then, - - #[token("true")] - True, - - #[token("until")] - Until, - - #[token("while")] - While, - - #[cfg(feature = "lua52")] - #[token("goto")] - Goto, - - #[cfg(feature = "roblox")] - #[token("+=")] - PlusEqual, - - #[cfg(feature = "roblox")] - #[token("-=")] - MinusEqual, - - #[cfg(feature = "roblox")] - #[token("*=")] - StarEqual, - - #[cfg(feature = "roblox")] - #[token("/=")] - SlashEqual, - - #[cfg(feature = "roblox")] - #[token("//=")] - DoubleSlashEqual, - - #[cfg(feature = "roblox")] - #[token("%=")] - PercentEqual, - - #[cfg(feature = "roblox")] - #[token("^=")] - CaretEqual, - - #[cfg(feature = "roblox")] - #[token("..=")] - TwoDotsEqual, - - #[cfg(any(feature = "roblox", feature = "lua53"))] - #[token("&")] - Ampersand, - - #[cfg(feature = "roblox")] - #[token("->")] - ThinArrow, - - #[cfg(any(feature = "roblox", feature = "lua52"))] - #[token("::")] - TwoColons, - - #[token("^")] - Caret, - - #[token(":")] - Colon, - - #[token(",")] - Comma, - - #[token("...")] - Ellipse, - - #[token("..")] - TwoDots, - - #[token(".")] - Dot, - - #[token("==")] - TwoEqual, - - #[token("=")] - Equal, - - #[token(">=")] - GreaterThanEqual, - - #[token(">")] - GreaterThan, // Lua 5.3: we cannot include DoubleGreaterThan '>>' in the tokenizer as it collides with Luau generics - - #[token("#")] - Hash, - - #[token("[")] - LeftBracket, - - #[cfg_attr(not(feature = "roblox"), token("{"))] - #[cfg_attr( - feature = "roblox", - regex(r"\{", crate::tokenizer_luau::read_left_brace) - )] - LeftBrace, - - #[token("(")] - LeftParen, - - #[token("<=")] - LessThanEqual, - - #[token("<")] - LessThan, - - #[cfg(feature = "lua53")] - #[token("<<")] - DoubleLessThan, - - #[token("-")] - Minus, - - #[token("%")] - Percent, - - #[cfg(any(feature = "roblox", feature = "lua53"))] - #[token("|")] - Pipe, - - #[token("+")] - Plus, - - #[cfg(feature = "roblox")] - #[token("?")] - QuestionMark, - - #[cfg_attr(not(feature = "roblox"), regex(r"\}", read_right_brace))] - #[cfg_attr( - feature = "roblox", - regex(r"\}", crate::tokenizer_luau::read_interpolated_string_right_brace) - )] - RightBrace(Option), - - #[token("]")] - RightBracket, - - #[token(")")] - RightParen, - - #[token(";")] - Semicolon, - - #[token("/")] - Slash, - - #[cfg(any(feature = "roblox", feature = "lua53"))] - #[token("//")] - DoubleSlash, - - #[token("*")] - Star, - - #[cfg(feature = "lua53")] - #[token("~")] - Tilde, - - #[token("~=")] - TildeEqual, - - #[regex(r"#!.*\n")] - Shebang, - - #[token("\u{feff}")] - Bom, - - #[regex(r"[_\p{L}][_\p{L}\p{N}]*")] - Identifier, - - // An amalgamation of both options, so that we can support both feature flags enabled at the same - // time. This means some false negatives will be triggered, but its our best solution for now. - #[cfg(all(feature = "roblox", feature = "lua52"))] - #[regex(r"0[bB][01_]+([eE][01_]+)?(\.[01_]*)?")] - #[regex(r"0[xX][0-9a-fA-F_]+(\.[0-9a-fA-F_]*)?([pP][\+\-]?[0-9a-fA-F_]+)?(LL|ULL|i)?")] - #[regex(r"\.[0-9][0-9_]*([eE][\+\-]?[0-9_]+)?(LL|ULL|i)?")] - #[regex(r"[0-9][0-9_]*(\.[0-9_]*)?([eE][\+\-]?[0-9_]+)?(LL|ULL|i)?")] - Number, - - #[cfg(all(feature = "roblox", not(feature = "lua52")))] - #[regex(r"0[bB][01_]+([eE][01_]+)?(\.[01_]*)?")] - #[regex(r"0[xX][0-9a-fA-F_]+")] - #[regex(r"\.[0-9][0-9_]*([eE][\+\-]?[0-9_]+)?")] - #[regex(r"[0-9][0-9_]*(\.[0-9_]*)?([eE][\+\-]?[0-9_]+)?")] - Number, - - #[cfg(all(feature = "lua52", not(feature = "roblox")))] - // Allow fractional hexadecimal, and binary exponents - // Also support LuaJIT ULL/LL/i endings - #[regex(r"0[xX][0-9a-fA-F_]+(\.[0-9a-fA-F_]*)?([pP][\+\-]?[0-9a-fA-F_]+)?(LL|ULL|i)?")] - #[regex(r"\.[0-9][0-9_]*([eE][\+\-]?[0-9_]+)?(LL|ULL|i)?")] - #[regex(r"[0-9][0-9_]*(\.[0-9_]*)?([eE][\+\-]?[0-9_]+)?(LL|ULL|i)?")] - Number, - - #[cfg(all(not(feature = "roblox"), not(feature = "lua52")))] - #[regex(r"0[xX][0-9a-fA-F]+")] - #[regex(r"\.[0-9]+([eE][\+\-]?[0-9]+)?")] - #[regex(r"[0-9]+(\.[0-9]*)?([eE][\+\-]?[0-9]+)?")] - Number, - - #[regex(r"'", |x| read_string(x, '\''))] - ApostropheString, - - #[regex(r#"""#, |x| read_string(x, '"'))] - QuoteString, - - #[regex(r"\[=*\[", |x| read_bracketed(x, 0))] - MultiLineString, - - #[cfg(feature = "roblox")] - #[regex(r"`", crate::tokenizer_luau::read_interpolated_string_begin)] - InterpolatedStringBegin(InterpolatedStringBegin), - - // These don't work, even with priority set! Ideally, this would be what we use. - // #[regex(r"--.*")] - // SingleLineComment, - - // #[regex(r"--\[=*\[", |x| read_bracketed(x, 2))] - // MultiLineComment, - #[regex(r"--", read_comment)] - Comment, - - #[regex(r"[ \t]*(\r?\n)?")] - Whitespace, - - #[error] - Unknown, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg(feature = "roblox")] -pub enum InterpolatedStringBegin { - Formatted, // `uh {oh}` - Simple, // `no formatting` -} - -#[cfg(feature = "roblox")] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum InterpolatedStringSection { - Middle, // } ... { - End, // } -} - -// This existing, but being empty makes things much easier -#[cfg(not(feature = "roblox"))] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum InterpolatedStringSection {} diff --git a/full-moon/src/lib.rs b/full-moon/src/lib.rs index e0856657..7909f6af 100644 --- a/full-moon/src/lib.rs +++ b/full-moon/src/lib.rs @@ -19,17 +19,15 @@ pub mod tokenizer; /// Used to create visitors that recurse through [`Ast`](ast::Ast) nodes. pub mod visitors; -mod atom; mod private; mod short_string; mod util; -#[cfg(feature = "roblox")] -mod tokenizer_luau; - +pub use ast::LuaVersion; pub use short_string::ShortString; +use tokenizer::Position; -use std::fmt; +use std::{borrow::Cow, fmt}; #[cfg(all(test, not(feature = "serde")))] compile_error!("Serde feature must be enabled for tests"); @@ -45,6 +43,24 @@ pub enum Error { TokenizerError(tokenizer::TokenizerError), } +impl Error { + /// Returns a human readable error message + pub fn error_message(&self) -> Cow<'static, str> { + match self { + Error::AstError(error) => error.error_message(), + Error::TokenizerError(error) => error.to_string().into(), + } + } + + /// Returns the range of the error + pub fn range(&self) -> (Position, Position) { + match self { + Error::AstError(error) => error.range(), + Error::TokenizerError(error) => error.range(), + } + } +} + impl fmt::Display for Error { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match self { @@ -60,7 +76,8 @@ impl fmt::Display for Error { impl std::error::Error for Error {} -/// Creates an [`Ast`](ast::Ast) from Lua code +/// Creates an [`Ast`](ast::Ast) from Lua code. +/// Will use the most complete set of Lua versions enabled in your feature set. /// /// # Errors /// If the code passed cannot be tokenized, a TokenizerError will be returned. @@ -72,9 +89,24 @@ impl std::error::Error for Error {} /// assert!(full_moon::parse("local x = ").is_err()); /// ``` #[allow(clippy::result_large_err)] -pub fn parse(code: &str) -> Result { - let tokens = tokenizer::tokens(code).map_err(Error::TokenizerError)?; - ast::Ast::from_tokens(tokens).map_err(Error::AstError) +pub fn parse(code: &str) -> Result> { + parse_fallible(code, LuaVersion::new()).into_result() +} + +/// Given code and a pinned Lua version, will produce an [`ast::AstResult`]. +/// This AstResult always produces some [`Ast`](ast::Ast), regardless of errors. +/// If a partial Ast is produced (i.e. if there are any errors), a few guarantees are lost. +/// 1. Tokens may be produced that aren't in the code itself. For example, `if x == 2 code()` +/// will produce a phantom `then` token in order to produce a usable [`If`](ast::If) struct. +/// These phantom tokens will have a null position. If you need accurate positions from the +/// phantom tokens, you can call [`Ast::update_positions`](ast::Ast::update_positions). +/// 2. The code, when printed, is not guaranteed to be valid Lua. +/// This can happen in the case of something like `local x = if`, which will produce a +/// [`LocalAssignment`](ast::LocalAssignment) that would print to `local x =`. +/// 3. There are no stability guarantees for partial Ast results, but they are consistent +/// within the same exact version of full-moon. +pub fn parse_fallible(code: &str, lua_version: LuaVersion) -> ast::AstResult { + ast::AstResult::parse_fallible(code, lua_version) } /// Prints back Lua code from an [`Ast`](ast::Ast) diff --git a/full-moon/src/short_string.rs b/full-moon/src/short_string.rs index f75042de..1638b26e 100644 --- a/full-moon/src/short_string.rs +++ b/full-moon/src/short_string.rs @@ -52,3 +52,9 @@ impl + AsRef> From for ShortString { ShortString(SmolStr::from(value)) } } + +impl FromIterator for ShortString { + fn from_iter>(iter: I) -> Self { + ShortString(SmolStr::from_iter(iter)) + } +} diff --git a/full-moon/src/tokenizer/interpolated_strings.rs b/full-moon/src/tokenizer/interpolated_strings.rs new file mode 100644 index 00000000..9fdf2d6d --- /dev/null +++ b/full-moon/src/tokenizer/interpolated_strings.rs @@ -0,0 +1,101 @@ +use crate::{ + tokenizer::{TokenType, TokenizerError, TokenizerErrorType}, + ShortString, +}; + +use super::{InterpolatedStringKind, Lexer, LexerResult, Position, Token}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum BraceType { + InterpolatedString, + Normal, +} + +pub(crate) fn read_interpolated_string_section( + lexer: &mut Lexer, + start_position: Position, + format_type: InterpolatedStringKind, + end_type: InterpolatedStringKind, +) -> LexerResult { + let mut characters = Vec::new(); + let mut escape = false; + + while let Some(character) = lexer.source.current() { + if !escape && matches!(character, '\n' | '\r') { + break; + } + + assert_eq!(character, lexer.source.next().unwrap()); + + match (escape, character) { + (true, ..) => { + characters.push(character); + escape = false; + } + + // Make sure \u{1234} doesn't get treated as \u, followed by {1234} + (false, '\\') if lexer.source.consume('u') => { + characters.push('\\'); + characters.push('u'); + + if lexer.source.consume('{') { + characters.push('{'); + + while lexer.source.peek().is_some() && lexer.source.peek() != Some('}') { + characters.push(lexer.source.next().unwrap()); + } + } + } + + (false, '\\') => { + characters.push(character); + escape = true; + } + + (false, ..) if character == '{' => { + lexer.brace_stack.push(BraceType::InterpolatedString); + return LexerResult::Ok(Token { + token_type: TokenType::InterpolatedString { + literal: ShortString::from_iter(characters), + kind: format_type, + }, + + start_position, + end_position: lexer.source.position(), + }); + } + + (false, ..) if character == '`' => { + return LexerResult::Ok(Token { + token_type: TokenType::InterpolatedString { + literal: ShortString::from_iter(characters), + kind: end_type, + }, + + start_position, + end_position: lexer.source.position(), + }); + } + + _ => { + characters.push(character); + } + } + } + + LexerResult::Recovered( + Token { + token_type: TokenType::InterpolatedString { + literal: ShortString::from_iter(characters), + kind: end_type, + }, + + start_position, + end_position: lexer.source.position(), + }, + vec![TokenizerError { + error: TokenizerErrorType::UnclosedString, + range: (start_position, lexer.source.position()), + }], + ) +} diff --git a/full-moon/src/tokenizer/lexer.rs b/full-moon/src/tokenizer/lexer.rs new file mode 100644 index 00000000..5b5ce5f1 --- /dev/null +++ b/full-moon/src/tokenizer/lexer.rs @@ -0,0 +1,1381 @@ +use crate::{ast::LuaVersion, tokenizer::StringLiteralQuoteType, version_switch, ShortString}; + +use super::{ + Position, Symbol, Token, TokenReference, TokenType, TokenizerError, TokenizerErrorType, +}; + +#[cfg(feature = "luau")] +use super::{interpolated_strings, InterpolatedStringKind}; + +/// A lexer, which will produce a stream of tokens from a source string. +/// If you just want to create an [`Ast`](crate::ast::Ast) from a string, you want to use +/// [`parse`](crate::parse) instead. +pub struct Lexer { + pub(crate) source: LexerSource, + sent_eof: bool, + + next_token: Option>, + peek_token: Option>, + + #[cfg(feature = "luau")] + pub(crate) brace_stack: Vec, + + /// The Lua version(s) to parse for. + pub lua_version: LuaVersion, +} + +impl Lexer { + /// Creates a new Lexer from the given source string and Lua version(s). + pub fn new(source: &str, lua_version: LuaVersion) -> Self { + let mut lexer = Self::new_lazy(source, lua_version); + + lexer.next_token = lexer.process_first_with_trivia(); + lexer.peek_token = lexer.process_next_with_trivia(); + + lexer + } + + /// Creates a new Lexer from the given source string and Lua version(s), but does not process + /// the first token. + pub fn new_lazy(source: &str, lua_version: LuaVersion) -> Self { + Self { + source: LexerSource::new(source), + sent_eof: false, + + next_token: None, + peek_token: None, + + #[cfg(feature = "luau")] + brace_stack: Vec::new(), + + lua_version, + } + } + + /// Returns the current token. + pub fn current(&self) -> Option<&LexerResult> { + self.next_token.as_ref() + } + + /// Returns the next token. + pub fn peek(&self) -> Option<&LexerResult> { + self.peek_token.as_ref() + } + + /// Consumes the current token and returns the next token. + pub fn consume(&mut self) -> Option> { + let next = self.next_token.take()?; + self.next_token = self.peek_token.take(); + self.peek_token = self.process_next_with_trivia(); + Some(next) + } + + /// Returns a vector of all tokens left in the source string. + pub fn collect(self) -> LexerResult> { + let mut tokens = Vec::new(); + let mut lexer = self; + let mut errors = Vec::new(); + + while let Some(token_reference) = lexer.consume() { + let mut token_reference = match token_reference { + LexerResult::Ok(token_reference) => token_reference, + + LexerResult::Recovered(token_reference, mut new_errors) => { + errors.append(&mut new_errors); + token_reference + } + + LexerResult::Fatal(mut new_errors) => { + errors.append(&mut new_errors); + continue; + } + }; + + tokens.append(&mut token_reference.leading_trivia); + tokens.push(token_reference.token); + tokens.append(&mut token_reference.trailing_trivia); + } + + LexerResult::new(tokens, errors) + } + + fn create( + &self, + start_position: Position, + token_type: TokenType, + ) -> Option> { + Some(LexerResult::Ok(Token { + token_type, + start_position, + end_position: self.source.position(), + })) + } + + fn create_recovered( + &self, + start_position: Position, + token_type: TokenType, + errors: Vec, + ) -> Option> { + Some(LexerResult::new( + Token { + token_type, + start_position, + end_position: self.source.position(), + }, + errors, + )) + } + + fn process_next_with_trivia(&mut self) -> Option> { + let mut leading_trivia = Vec::new(); + let mut errors: Option> = None; + + let nontrivial_token = loop { + match self.process_next()? { + LexerResult::Ok(token) if token.token_type().is_trivia() => { + leading_trivia.push(token); + } + + LexerResult::Ok(token) => { + break token; + } + + LexerResult::Fatal(error) => { + return Some(LexerResult::Fatal(error)); + } + + LexerResult::Recovered(token, mut new_errors) => { + if let Some(errors) = errors.as_mut() { + errors.append(&mut new_errors); + } else { + errors = Some(new_errors); + } + + if token.token_type().is_trivia() { + leading_trivia.push(token); + } else { + break token; + } + } + } + }; + + let trailing_trivia = self.collect_trailing_trivia(); + let token = TokenReference { + token: nontrivial_token, + leading_trivia, + trailing_trivia, + }; + + if let Some(errors) = errors { + Some(LexerResult::Recovered(token, errors)) + } else { + Some(LexerResult::Ok(token)) + } + } + + fn process_first_with_trivia(&mut self) -> Option> { + if self.source.current() == Some('#') && self.source.peek() == Some('!') { + let start_position = self.source.position(); + let mut line = "#!".to_string(); + + self.source.next(); + self.source.next(); + + while let Some(next) = self.source.current() { + if next == '\n' { + break; + } + + self.source.next(); + line.push(next); + } + + let end_position = self.source.position(); + + let shebang = Token { + token_type: TokenType::Shebang { line: line.into() }, + start_position, + end_position, + }; + + // rewrite todo: handle LexerResult better here + if let Some(LexerResult::Ok(mut token_reference)) = self.process_next_with_trivia() { + token_reference.leading_trivia.insert(0, shebang); + return Some(LexerResult::Ok(token_reference)); + } + } + + self.process_next_with_trivia() + } + + fn collect_trailing_trivia(&mut self) -> Vec { + let mut trailing_trivia = Vec::new(); + + loop { + let sent_eof = self.sent_eof; + let start_position = self.source.lexer_position; + + match self.process_next() { + Some(LexerResult::Ok(token)) if token.token_type().is_trivia() => { + // Take all trivia up to and including the newline character. If we see a newline character + // we should break once we have taken it in. + let should_break = + if let TokenType::Whitespace { ref characters } = token.token_type() { + // Use contains in order to tolerate \r\n line endings and mixed whitespace tokens + characters.contains('\n') + } else { + false + }; + + trailing_trivia.push(token); + + if should_break { + break; + } + } + + _ => { + self.source.lexer_position = start_position; + self.sent_eof = sent_eof; + break; + } + } + } + + trailing_trivia + } + + /// Processes and returns the next token in the source string, ignoring trivia. + pub fn process_next(&mut self) -> Option> { + let start_position = self.source.position(); + + let Some(next) = self.source.next() else { + if self.sent_eof { + return None; + } else { + self.sent_eof = true; + return self.create(start_position, TokenType::Eof); + } + }; + + match next { + initial if is_identifier_start(initial) => { + let mut identifier = String::new(); + identifier.push(initial); + + while let Some(next) = self.source.current() { + if is_identifier_start(next) || next.is_ascii_digit() { + identifier.push(self.source.next().expect("peeked, but no next")); + } else { + break; + } + } + + self.create( + start_position, + if let Some(symbol) = Symbol::from_str(&identifier, self.lua_version) { + TokenType::Symbol { symbol } + } else { + TokenType::Identifier { + identifier: ShortString::from(identifier), + } + }, + ) + } + + initial @ (' ' | '\t' | '\r') => { + let mut whitespace = String::new(); + whitespace.push(initial); + + // Handle end_position appropriately: for a newline, we increment the bytes, but + // do not increment line/char + let mut end_position = Position { + bytes: start_position.bytes() + initial.len_utf8(), + line: start_position.line, + character: start_position.character + 1, + }; + + while let Some(next) = self.source.current() { + if next == ' ' || next == '\t' { + end_position.bytes += next.len_utf8(); + end_position.character += 1; + whitespace.push(self.source.next().expect("peeked, but no next")); + } else if next == '\n' { + end_position.bytes += next.len_utf8(); + whitespace.push(self.source.next().expect("peeked, but no next")); + break; + } else if next == '\r' && self.source.peek() == Some('\n') { + let carriage_return = self.source.next().expect("peeked, but no next"); + let new_line = self.source.next().expect("peeked, but no next"); + end_position.bytes += carriage_return.len_utf8() + new_line.len_utf8(); + end_position.character += 1; + whitespace.push(carriage_return); + whitespace.push(new_line); + break; + } else { + break; + } + } + + Some(LexerResult::Ok(Token { + token_type: TokenType::Whitespace { + characters: ShortString::from(whitespace.as_str()), + }, + start_position, + end_position, + })) + } + + initial @ '0' => { + if matches!(self.source.current(), Some('x' | 'X')) { + let hex_character = self.source.next().unwrap(); + self.read_hex_number(hex_character, start_position) + } else if self.lua_version.has_luau() + && matches!(self.source.current(), Some('b' | 'B')) + { + let binary_character = self.source.next().unwrap(); + self.read_binary_number(binary_character, start_position) + } else { + self.read_number(start_position, initial.to_string()) + } + } + + initial @ ('1'..='9') => self.read_number(start_position, initial.to_string()), + + quote @ ('"' | '\'') => { + let (string, recovered) = self.read_string(quote); + self.create_recovered( + start_position, + string, + if recovered { + vec![TokenizerError { + error: TokenizerErrorType::UnclosedString, + range: (start_position, self.source.position()), + }] + } else { + Vec::new() + }, + ) + } + + #[cfg(feature = "luau")] + '`' if self.lua_version.has_luau() => { + Some(interpolated_strings::read_interpolated_string_section( + self, + start_position, + InterpolatedStringKind::Begin, + InterpolatedStringKind::Simple, + )) + } + + '=' => { + if self.source.consume('=') { + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::TwoEqual, + }, + ) + } else { + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Equal, + }, + ) + } + } + + '~' => { + if self.source.consume('=') { + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::TildeEqual, + }, + ) + } else { + version_switch!(self.lua_version, { + lua53 => { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Tilde, + }, + ) + } + }); + + Some(LexerResult::Fatal(vec![TokenizerError { + error: TokenizerErrorType::InvalidSymbol("~".to_owned()), + range: (start_position, self.source.position()), + }])) + } + } + + '\n' => Some(LexerResult::Ok(Token { + token_type: TokenType::Whitespace { + characters: ShortString::from("\n"), + }, + start_position, + end_position: Position { + bytes: start_position.bytes() + 1, + ..start_position + }, + })), + + '(' => self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::LeftParen, + }, + ), + + ')' => self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::RightParen, + }, + ), + + '[' => { + let start_lexer_position = self.source.lexer_position; + + if self.source.current() == Some('[') || self.source.current() == Some('=') { + match self.read_multi_line_body() { + MultiLineBodyResult::Ok { blocks, body } => self.create( + start_position, + TokenType::StringLiteral { + literal: body.into(), + multi_line_depth: blocks, + quote_type: StringLiteralQuoteType::Brackets, + }, + ), + + MultiLineBodyResult::Unclosed { blocks, body } => self.create_recovered( + start_position, + TokenType::StringLiteral { + literal: body.into(), + multi_line_depth: blocks, + quote_type: StringLiteralQuoteType::Brackets, + }, + vec![TokenizerError { + error: TokenizerErrorType::UnclosedString, + range: (start_position, self.source.position()), + }], + ), + + MultiLineBodyResult::NotMultiLine { .. } => { + // Reset back, parse the one `[`, and let the rest be parsed again + self.source.lexer_position = start_lexer_position; + + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::LeftBracket, + }, + ) + } + } + } else { + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::LeftBracket, + }, + ) + } + } + + ']' => self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::RightBracket, + }, + ), + + ':' => { + version_switch!(self.lua_version, { + lua52 | luau => { + if self.source.consume(':') { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::TwoColons, + }, + ); + } + } + }); + + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Colon, + }, + ) + } + + ',' => self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Comma, + }, + ), + + '+' => { + version_switch!(self.lua_version, { + luau => { + if self.source.consume('=') { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::PlusEqual, + }, + ); + } + } + }); + + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Plus, + }, + ) + } + + '*' => { + version_switch!(self.lua_version, { + luau => { + if self.source.consume('=') { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::StarEqual, + }, + ); + } + } + }); + + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Star, + }, + ) + } + + '/' => { + version_switch!(self.lua_version, { + lua53 => { + if self.source.current() == Some('/') { + self.source.next(); + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::DoubleSlash, + }, + ); + } + } + luau => { + if self.source.consume('/') { + if self.source.consume('=') { + return self.create(start_position, TokenType::Symbol { symbol: Symbol::DoubleSlashEqual }) + } else { + return self.create(start_position, TokenType::Symbol { symbol: Symbol::DoubleSlash} ) + } + } else if self.source.consume('=') { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::SlashEqual, + }, + ); + } + } + }); + + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Slash, + }, + ) + } + + '%' => { + version_switch!(self.lua_version, { + luau => { + if self.source.consume('=') { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::PercentEqual, + }, + ); + } + } + }); + + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Percent, + }, + ) + } + + '^' => { + version_switch!(self.lua_version, { + luau => { + if self.source.consume('=') { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::CaretEqual, + }, + ); + } + } + }); + + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Caret, + }, + ) + } + + '#' => self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Hash, + }, + ), + + '<' => { + version_switch!(self.lua_version, { + lua53 => { + if self.source.consume('<') { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::DoubleLessThan, + }, + ); + } + } + }); + + if self.source.consume('=') { + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::LessThanEqual, + }, + ) + } else { + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::LessThan, + }, + ) + } + } + + '>' => { + version_switch!(self.lua_version, { + lua53 => { + if self.source.consume('>') { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::DoubleGreaterThan, + }, + ); + } + } + }); + + if self.source.consume('=') { + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::GreaterThanEqual, + }, + ) + } else { + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::GreaterThan, + }, + ) + } + } + + '{' => { + #[cfg(feature = "luau")] + if self.lua_version.has_luau() { + self.brace_stack + .push(interpolated_strings::BraceType::Normal); + } + + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::LeftBrace, + }, + ) + } + + '}' => { + #[cfg(feature = "luau")] + if self.lua_version.has_luau() + && self.brace_stack.pop() + == Some(interpolated_strings::BraceType::InterpolatedString) + { + return Some(interpolated_strings::read_interpolated_string_section( + self, + start_position, + InterpolatedStringKind::Middle, + InterpolatedStringKind::End, + )); + } + + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::RightBrace, + }, + ) + } + + '.' => { + if self.source.consume('.') { + if self.source.consume('.') { + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Ellipse, + }, + ) + } else { + version_switch!(self.lua_version, { + luau => { + if self.source.consume('=') { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::TwoDotsEqual, + }, + ); + } + } + }); + + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::TwoDots, + }, + ) + } + } else if matches!(self.source.current(), Some('0'..='9')) { + self.read_number(start_position, ".".to_string()) + } else { + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Dot, + }, + ) + } + } + + '-' => { + version_switch!(self.lua_version, { + luau => { + if self.source.consume('=') { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::MinusEqual, + }, + ); + } else if self.source.consume('>') { + return self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::ThinArrow + } + ); + } + } + }); + + if self.source.consume('-') { + let (token, recovered) = self.read_comment(); + + self.create_recovered( + start_position, + token, + if recovered { + vec![TokenizerError { + error: TokenizerErrorType::UnclosedComment, + range: (start_position, self.source.position()), + }] + } else { + Vec::new() + }, + ) + } else { + self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Minus, + }, + ) + } + } + + ';' => self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Semicolon, + }, + ), + + #[cfg(any(feature = "lua53", feature = "luau"))] + '&' if self.lua_version.has_lua53() || self.lua_version.has_luau() => self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Ampersand, + }, + ), + + #[cfg(any(feature = "lua53", feature = "luau"))] + '|' if self.lua_version.has_lua53() || self.lua_version.has_luau() => self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::Pipe, + }, + ), + + #[cfg(feature = "luau")] + '?' if self.lua_version.has_luau() => self.create( + start_position, + TokenType::Symbol { + symbol: Symbol::QuestionMark, + }, + ), + + unknown_char => Some(LexerResult::Fatal(vec![TokenizerError { + error: TokenizerErrorType::UnexpectedToken(unknown_char), + range: (start_position, self.source.position()), + }])), + } + } + + fn read_number( + &mut self, + start_position: Position, + mut number: String, + ) -> Option> { + let mut hit_decimal = false; + + while let Some(next) = self.source.current() { + if next.is_ascii_digit() || (self.lua_version.has_luau() && matches!(next, '_')) { + number.push(self.source.next().expect("peeked, but no next")); + } else if matches!(next, '.') { + if hit_decimal { + return Some(self.eat_invalid_number(start_position, number)); + } + + hit_decimal = true; + number.push(self.source.next().expect("peeked, but no next")); + } else if matches!(next, 'e' | 'E') { + return self.read_exponent_part(start_position, number); + } else { + break; + } + } + + self.create( + start_position, + TokenType::Number { + text: ShortString::from(number), + }, + ) + } + + fn eat_invalid_number( + &mut self, + start_position: Position, + mut number: String, + ) -> LexerResult { + loop { + if matches!(self.source.current(), Some(token) if token.is_ascii_whitespace()) + || self.source.current().is_none() + { + return LexerResult::new( + Token { + token_type: TokenType::Number { + text: number.into(), + }, + start_position, + end_position: self.source.position(), + }, + vec![TokenizerError { + error: TokenizerErrorType::InvalidNumber, + range: (start_position, self.source.position()), + }], + ); + } + + number.push(self.source.next().expect("peeked, but no next")); + } + } + + // Starts from the exponent marker (like 'e') + fn read_exponent_part( + &mut self, + start_position: Position, + mut number: String, + ) -> Option> { + number.push(self.source.next().expect("peeked, but no next")); + + let next = self.source.current(); + if matches!(next, Some('+') | Some('-')) { + number.push(self.source.next().expect("peeked, but no next")); + } + + if !matches!(self.source.current(), Some('0'..='9')) { + return Some(self.eat_invalid_number(start_position, number)); + } + + while let Some(next) = self.source.current() { + if next.is_ascii_digit() || (self.lua_version.has_luau() && matches!(next, '_')) { + number.push(self.source.next().expect("peeked, but no next")); + } else { + break; + } + } + + self.create( + start_position, + TokenType::Number { + text: ShortString::from(number), + }, + ) + } + + fn read_hex_number( + &mut self, + hex_character: char, + start_position: Position, + ) -> Option> { + let mut number = String::from_iter(['0', hex_character]); + let mut hit_decimal = false; + + while let Some(next) = self.source.current() { + match next { + '0'..='9' | 'a'..='f' | 'A'..='F' => { + number.push(self.source.next().expect("peeked, but no next")); + } + + '_' if self.lua_version.has_luau() => { + number.push(self.source.next().expect("peeked, but no next")); + } + + '.' if self.lua_version.has_lua52() => { + if hit_decimal { + return Some(self.eat_invalid_number(start_position, number)); + } + + hit_decimal = true; + number.push(self.source.next().expect("peeked, but no next")); + } + + 'p' | 'P' if self.lua_version.has_lua52() => { + if number.len() == 2 { + return Some(self.eat_invalid_number(start_position, number)); + } + + return self.read_exponent_part(start_position, number); + } + + _ => break, + } + } + + if number.len() == 2 { + return Some(self.eat_invalid_number(start_position, number)); + } + + self.create( + start_position, + TokenType::Number { + text: ShortString::from(number), + }, + ) + } + + fn read_binary_number( + &mut self, + binary_character: char, + start_position: Position, + ) -> Option> { + debug_assert!(self.lua_version.has_luau()); + + let mut number = String::from_iter(['0', binary_character]); + + while let Some(next) = self.source.current() { + match next { + '0' | '1' | '_' => { + number.push(self.source.next().expect("peeked, but no next")); + } + + _ => break, + } + } + + if number.len() == 2 { + return Some(self.eat_invalid_number(start_position, number)); + } + + self.create( + start_position, + TokenType::Number { + text: ShortString::from(number), + }, + ) + } + + // (string, had to be recovered?) + fn read_string(&mut self, quote: char) -> (TokenType, bool) { + let quote_type = match quote { + '"' => StringLiteralQuoteType::Double, + '\'' => StringLiteralQuoteType::Single, + _ => unreachable!(), + }; + + let mut literal = String::new(); + + let mut escape = false; + let mut z_escaped = false; + + loop { + let next = match self.source.next() { + Some(next) => next, + None => { + return ( + TokenType::StringLiteral { + literal: literal.into(), + multi_line_depth: 0, + quote_type, + }, + true, + ) + } + }; + + match (escape, next) { + (true, 'z') if self.lua_version.has_lua52() || self.lua_version.has_luau() => { + escape = false; + z_escaped = true; + literal.push('z'); + } + + (true, ..) => { + escape = false; + + if self.lua_version.has_lua52() || self.lua_version.has_luau() { + z_escaped = true; // support for '\' followed by a new line + } + + literal.push(next); + } + + (false, '\\') => { + escape = true; + literal.push('\\'); + } + + (false, '\n' | '\r') if z_escaped => { + z_escaped = false; + literal.push(next); + } + + (false, '\n' | '\r') => { + return ( + TokenType::StringLiteral { + literal: literal.into(), + multi_line_depth: 0, + quote_type, + }, + true, + ) + } + + (false, ..) if next == quote => { + return ( + TokenType::StringLiteral { + literal: literal.into(), + multi_line_depth: 0, + quote_type, + }, + false, + ); + } + + (false, ..) => { + literal.push(next); + } + } + } + } + + // (comment, had to be recovered?) + fn read_comment(&mut self) -> (TokenType, bool) { + let mut comment = String::new(); + + if self.source.consume('[') { + match self.read_multi_line_body() { + MultiLineBodyResult::Ok { blocks, body } => { + return ( + TokenType::MultiLineComment { + blocks, + comment: body.into(), + }, + false, + ); + } + + MultiLineBodyResult::Unclosed { blocks, body } => { + return ( + TokenType::MultiLineComment { + blocks, + comment: body.into(), + }, + true, + ); + } + + MultiLineBodyResult::NotMultiLine { blocks } => { + comment.push('['); + + for _ in 0..blocks { + comment.push('='); + } + } + } + } + + let mut position_before_new_line = self.source.lexer_position; + + while let Some(next) = self.source.next() { + if next == '\n' { + break; + } + + comment.push(next); + position_before_new_line = self.source.lexer_position; + } + + self.source.lexer_position = position_before_new_line; + + ( + TokenType::SingleLineComment { + comment: comment.into(), + }, + false, + ) + } + + fn read_multi_line_body(&mut self) -> MultiLineBodyResult { + let mut blocks = 0; + while self.source.consume('=') { + blocks += 1; + } + + if !self.source.consume('[') { + return MultiLineBodyResult::NotMultiLine { blocks }; + } + + let mut body = String::new(); + + 'read_comment_char: loop { + let next = match self.source.next() { + Some(next) => next, + None => return MultiLineBodyResult::Unclosed { blocks, body }, + }; + + if next == ']' { + let mut equal_signs = 0; + + while equal_signs < blocks { + if !self.source.consume('=') { + body.push(']'); + + for _ in 0..equal_signs { + body.push('='); + } + + continue 'read_comment_char; + } + + equal_signs += 1; + } + + if self.source.consume(']') { + break; + } + + body.push(']'); + for _ in 0..equal_signs { + body.push('='); + } + + continue; + } + + body.push(next); + } + + MultiLineBodyResult::Ok { blocks, body } + } +} + +fn is_identifier_start(character: char) -> bool { + matches!(character, 'a'..='z' | 'A'..='Z' | '_') +} + +pub(crate) struct LexerSource { + source: Vec, + lexer_position: LexerPosition, +} + +impl LexerSource { + fn new(source: &str) -> Self { + Self { + source: source.chars().collect(), + lexer_position: LexerPosition::new(), + } + } + + pub(crate) fn current(&self) -> Option { + self.source.get(self.lexer_position.index).copied() + } + + pub(crate) fn next(&mut self) -> Option { + let next = self.current()?; + + if next == '\n' { + self.lexer_position.position.line += 1; + self.lexer_position.position.character = 1; + } else { + self.lexer_position.position.character += 1; + } + + self.lexer_position.position.bytes += next.len_utf8(); + self.lexer_position.index += 1; + + Some(next) + } + + pub(crate) fn peek(&self) -> Option { + self.source.get(self.lexer_position.index + 1).copied() + } + + pub(crate) fn consume(&mut self, character: char) -> bool { + if self.current() == Some(character) { + self.next(); + true + } else { + false + } + } + + pub(crate) fn position(&self) -> Position { + self.lexer_position.position + } +} + +#[derive(Clone, Copy)] +struct LexerPosition { + position: Position, + index: usize, +} + +impl LexerPosition { + fn new() -> Self { + Self { + position: Position { + line: 1, + character: 1, + bytes: 0, + }, + index: 0, + } + } +} + +/// The result of a lexer operation. +#[derive(Debug)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub enum LexerResult { + /// The lexer operation was successful. + Ok(T), + /// The lexer operation was unsuccessful, and could not be recovered. + Fatal(Vec), + /// The lexer operation was unsuccessful, but some result can be extracted. + Recovered(T, Vec), +} + +impl LexerResult { + fn new(value: T, errors: Vec) -> Self { + if errors.is_empty() { + Self::Ok(value) + } else { + Self::Recovered(value, errors) + } + } + + /// Unwraps the result, panicking if it is not [`LexerResult::Ok`]. + pub fn unwrap(self) -> T { + match self { + Self::Ok(value) => value, + _ => panic!("expected ok, got {self:#?}"), + } + } + + /// Unwraps the errors, panicking if it is [`LexerResult::Ok`]. + pub fn unwrap_errors(self) -> Vec { + match self { + Self::Fatal(errors) | Self::Recovered(_, errors) => errors, + _ => panic!("expected fatal error, got {self:#?}"), + } + } + + /// Returns the errors, if there was any. + pub fn errors(self) -> Vec { + match self { + Self::Recovered(_, errors) => errors, + _ => Vec::new(), + } + } +} + +enum MultiLineBodyResult { + Ok { blocks: usize, body: String }, + NotMultiLine { blocks: usize }, + Unclosed { blocks: usize, body: String }, +} diff --git a/full-moon/src/tokenizer/mod.rs b/full-moon/src/tokenizer/mod.rs new file mode 100644 index 00000000..bb3fa880 --- /dev/null +++ b/full-moon/src/tokenizer/mod.rs @@ -0,0 +1,8 @@ +mod lexer; +pub use lexer::*; + +mod structs; +pub use structs::*; + +#[cfg(feature = "luau")] +mod interpolated_strings; diff --git a/full-moon/src/tokenizer.rs b/full-moon/src/tokenizer/structs.rs similarity index 52% rename from full-moon/src/tokenizer.rs rename to full-moon/src/tokenizer/structs.rs index b27fcec5..24160684 100644 --- a/full-moon/src/tokenizer.rs +++ b/full-moon/src/tokenizer/structs.rs @@ -1,372 +1,192 @@ use crate::{ - atom::{trim_bracket_head, Atom}, + ast::LuaVersion, visitors::{Visit, VisitMut, Visitor, VisitorMut}, ShortString, }; -use logos::{Lexer, Logos, Span}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use std::{ cmp::Ordering, - convert::{TryFrom, TryInto}, fmt::{self, Display}, }; -#[cfg(feature = "roblox")] -use crate::atom::{InterpolatedStringBegin, InterpolatedStringSection}; +use super::{Lexer, LexerResult}; -#[cfg(feature = "roblox")] -pub use crate::tokenizer_luau::InterpolatedStringKind; - -#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))] -#[non_exhaustive] -#[allow(missing_docs)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -/// A literal symbol, used for both words important to syntax (like while) and operators (like +) -pub enum Symbol { - And, - Break, - Do, - Else, - ElseIf, - End, - False, - For, - Function, - If, - In, - Local, - Nil, - Not, - Or, - Repeat, - Return, - Then, - True, - Until, - While, - - #[cfg(feature = "lua52")] - Goto, - - #[cfg_attr(feature = "serde", serde(rename = "+="))] - PlusEqual, - - #[cfg_attr(feature = "serde", serde(rename = "-="))] - MinusEqual, - - #[cfg_attr(feature = "serde", serde(rename = "*="))] - StarEqual, - - #[cfg_attr(feature = "serde", serde(rename = "/="))] - SlashEqual, - - #[cfg(feature = "roblox")] - #[cfg_attr(feature = "serde", serde(rename = "//="))] - DoubleSlashEqual, - - #[cfg_attr(feature = "serde", serde(rename = "%="))] - PercentEqual, - - #[cfg_attr(feature = "serde", serde(rename = "^="))] - CaretEqual, - - #[cfg_attr(feature = "serde", serde(rename = "..="))] - TwoDotsEqual, - - #[cfg(any(feature = "roblox", feature = "lua53"))] - #[cfg_attr(feature = "serde", serde(rename = "&"))] - Ampersand, - - #[cfg(feature = "roblox")] - #[cfg_attr(feature = "serde", serde(rename = "->"))] - ThinArrow, - - #[cfg(any(feature = "roblox", feature = "lua52"))] - #[cfg_attr(feature = "serde", serde(rename = "::"))] - TwoColons, - - #[cfg_attr(feature = "serde", serde(rename = "^"))] - Caret, - - #[cfg_attr(feature = "serde", serde(rename = ":"))] - Colon, - - #[cfg_attr(feature = "serde", serde(rename = ","))] - Comma, - - #[cfg_attr(feature = "serde", serde(rename = "..."))] - Ellipse, - - #[cfg_attr(feature = "serde", serde(rename = ".."))] - TwoDots, - - #[cfg_attr(feature = "serde", serde(rename = "."))] - Dot, - - #[cfg_attr(feature = "serde", serde(rename = "=="))] - TwoEqual, - - #[cfg_attr(feature = "serde", serde(rename = "="))] - Equal, - - #[cfg_attr(feature = "serde", serde(rename = ">="))] - GreaterThanEqual, - - #[cfg_attr(feature = "serde", serde(rename = ">"))] - GreaterThan, - - #[cfg(feature = "lua53")] - #[cfg_attr(feature = "serde", serde(rename = ">>"))] - DoubleGreaterThan, - - #[cfg_attr(feature = "serde", serde(rename = "#"))] - Hash, - - #[cfg_attr(feature = "serde", serde(rename = "["))] - LeftBracket, - - #[cfg_attr(feature = "serde", serde(rename = "{"))] - LeftBrace, - - #[cfg_attr(feature = "serde", serde(rename = "("))] - LeftParen, - - #[cfg_attr(feature = "serde", serde(rename = "<="))] - LessThanEqual, - - #[cfg_attr(feature = "serde", serde(rename = "<"))] - LessThan, - - #[cfg(feature = "lua53")] - #[cfg_attr(feature = "serde", serde(rename = "<<"))] - DoubleLessThan, - - #[cfg_attr(feature = "serde", serde(rename = "-"))] - Minus, - - #[cfg_attr(feature = "serde", serde(rename = "%"))] - Percent, - - #[cfg(any(feature = "roblox", feature = "lua53"))] - #[cfg_attr(feature = "serde", serde(rename = "|"))] - Pipe, - - #[cfg_attr(feature = "serde", serde(rename = "+"))] - Plus, - - #[cfg(feature = "roblox")] - #[cfg_attr(feature = "serde", serde(rename = "?"))] - QuestionMark, - - #[cfg_attr(feature = "serde", serde(rename = "}"))] - RightBrace, - - #[cfg_attr(feature = "serde", serde(rename = "]"))] - RightBracket, - - #[cfg_attr(feature = "serde", serde(rename = ")"))] - RightParen, - - #[cfg_attr(feature = "serde", serde(rename = ";"))] - Semicolon, - - #[cfg_attr(feature = "serde", serde(rename = "/"))] - Slash, - - #[cfg(any(feature = "roblox", feature = "lua53"))] - #[cfg_attr(feature = "serde", serde(rename = "//"))] - DoubleSlash, - - #[cfg_attr(feature = "serde", serde(rename = "*"))] - Star, +macro_rules! symbol { + { + $(#[$symbol_meta:meta])* + pub enum Symbol { + $( + $(#[$meta:meta])* + $([$($version:ident)|+])? $name:ident => $string:literal, + )+ + } + } => { + paste::paste! { + $(#[$symbol_meta])* + pub enum Symbol { + $( + $(#[$meta])* + $( + #[cfg(any( + $(feature = "" $version),+ + ))] + )* + #[serde(rename = $string)] + $name, + )+ + } - #[cfg(feature = "lua53")] - #[cfg_attr(feature = "serde", serde(rename = "~"))] - Tilde, + impl Symbol { + /// Given just the symbol text (no whitespace) and the Lua version, + /// returns the associated symbol, if it exists. + /// If you want a TokenReference instead, consider [`TokenReference::symbol`]. + // rewrite todo: does this link? + /// ```rust + /// # use full_moon::{LuaVersion, tokenizer::Symbol}; + /// assert_eq!(Symbol::from_str("local", LuaVersion::lua51()), Some(Symbol::Local)); + /// + /// # #[cfg(feature = "lua52")] + /// assert_eq!(Symbol::from_str("goto", LuaVersion::lua52()), Some(Symbol::Goto)); + /// assert_eq!(Symbol::from_str("goto", LuaVersion::lua51()), None); + /// ``` + #[allow(unused)] // Without any features, lua_version is unused + pub fn from_str(symbol: &str, lua_version: LuaVersion) -> Option { + match symbol { + $( + $( + #[cfg(any( + $(feature = "" $version),+ + ))] + )? + $string => { + if !crate::has_version!(lua_version, $($($version,)+)?) { + return None; + } + + Some(Self::$name) + }, + )+ + + _ => None, + } + } + } - #[cfg_attr(feature = "serde", serde(rename = "~="))] - TildeEqual, + impl Display for Symbol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + $( + $( + #[cfg(any( + $(feature = "" $version),+ + ))] + )* + Self::$name => f.write_str($string), + )+ + } + } + } + } + }; } -impl TryFrom for Symbol { - type Error = (); - - fn try_from(value: Atom) -> Result { - Ok(match value { - Atom::And => Symbol::And, - Atom::Break => Symbol::Break, - Atom::Do => Symbol::Do, - Atom::Else => Symbol::Else, - Atom::ElseIf => Symbol::ElseIf, - Atom::End => Symbol::End, - Atom::False => Symbol::False, - Atom::For => Symbol::For, - Atom::Function => Symbol::Function, - Atom::If => Symbol::If, - Atom::In => Symbol::In, - Atom::Local => Symbol::Local, - Atom::Nil => Symbol::Nil, - Atom::Not => Symbol::Not, - Atom::Or => Symbol::Or, - Atom::Repeat => Symbol::Repeat, - Atom::Return => Symbol::Return, - Atom::Then => Symbol::Then, - Atom::True => Symbol::True, - Atom::Until => Symbol::Until, - Atom::While => Symbol::While, - #[cfg(feature = "lua52")] - Atom::Goto => Symbol::Goto, - #[cfg(feature = "roblox")] - Atom::PlusEqual => Symbol::PlusEqual, - #[cfg(feature = "roblox")] - Atom::MinusEqual => Symbol::MinusEqual, - #[cfg(feature = "roblox")] - Atom::StarEqual => Symbol::StarEqual, - #[cfg(feature = "roblox")] - Atom::SlashEqual => Symbol::SlashEqual, - #[cfg(feature = "roblox")] - Atom::DoubleSlashEqual => Symbol::DoubleSlashEqual, - #[cfg(feature = "roblox")] - Atom::PercentEqual => Symbol::PercentEqual, - #[cfg(feature = "roblox")] - Atom::CaretEqual => Symbol::CaretEqual, - #[cfg(feature = "roblox")] - Atom::TwoDotsEqual => Symbol::TwoDotsEqual, - Atom::Caret => Symbol::Caret, - Atom::Colon => Symbol::Colon, - Atom::Comma => Symbol::Comma, - Atom::Ellipse => Symbol::Ellipse, - Atom::TwoDots => Symbol::TwoDots, - #[cfg(any(feature = "roblox", feature = "lua53"))] - Atom::Ampersand => Symbol::Ampersand, - #[cfg(feature = "roblox")] - Atom::ThinArrow => Symbol::ThinArrow, - #[cfg(any(feature = "roblox", feature = "lua52"))] - Atom::TwoColons => Symbol::TwoColons, - Atom::Dot => Symbol::Dot, - Atom::TwoEqual => Symbol::TwoEqual, - Atom::Equal => Symbol::Equal, - Atom::GreaterThanEqual => Symbol::GreaterThanEqual, - Atom::GreaterThan => Symbol::GreaterThan, - Atom::Hash => Symbol::Hash, - Atom::LeftBracket => Symbol::LeftBracket, - Atom::LeftBrace => Symbol::LeftBrace, - Atom::LeftParen => Symbol::LeftParen, - Atom::LessThanEqual => Symbol::LessThanEqual, - Atom::LessThan => Symbol::LessThan, - #[cfg(feature = "lua53")] - Atom::DoubleLessThan => Symbol::DoubleLessThan, - Atom::Minus => Symbol::Minus, - Atom::Percent => Symbol::Percent, - #[cfg(any(feature = "roblox", feature = "lua53"))] - Atom::Pipe => Symbol::Pipe, - #[cfg(feature = "roblox")] - Atom::QuestionMark => Symbol::QuestionMark, - Atom::Plus => Symbol::Plus, - Atom::RightBrace(None) => Symbol::RightBrace, - Atom::RightBracket => Symbol::RightBracket, - Atom::RightParen => Symbol::RightParen, - Atom::Semicolon => Symbol::Semicolon, - Atom::Slash => Symbol::Slash, - #[cfg(any(feature = "roblox", feature = "lua53"))] - Atom::DoubleSlash => Symbol::DoubleSlash, - Atom::Star => Symbol::Star, - #[cfg(feature = "lua53")] - Atom::Tilde => Symbol::Tilde, - Atom::TildeEqual => Symbol::TildeEqual, - _ => { - return Err(()); - } - }) +symbol! { + #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] + #[non_exhaustive] + #[allow(missing_docs)] + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + /// A literal symbol, used for both words important to syntax (like while) and operators (like +) + pub enum Symbol { + And => "and", + Break => "break", + Do => "do", + Else => "else", + ElseIf => "elseif", + End => "end", + False => "false", + For => "for", + Function => "function", + If => "if", + In => "in", + Local => "local", + Nil => "nil", + Not => "not", + Or => "or", + Repeat => "repeat", + Return => "return", + Then => "then", + True => "true", + Until => "until", + While => "while", + + [lua52] Goto => "goto", + + [luau] PlusEqual => "+=", + [luau] MinusEqual => "-=", + [luau] StarEqual => "*=", + [luau] SlashEqual => "/=", + [luau] DoubleSlashEqual => "//=", + [luau] PercentEqual => "%=", + [luau] CaretEqual => "^=", + [luau] TwoDotsEqual => "..=", + + [luau | lua53] Ampersand => "&", + [luau] ThinArrow => "->", + [luau | lua52] TwoColons => "::", + + Caret => "^", + Colon => ":", + Comma => ",", + Dot => ".", + TwoDots => "..", + Ellipse => "...", + Equal => "=", + TwoEqual => "==", + GreaterThan => ">", + GreaterThanEqual => ">=", + [lua53] DoubleGreaterThan => ">>", + Hash => "#", + LeftBrace => "{", + LeftBracket => "[", + LeftParen => "(", + LessThan => "<", + LessThanEqual => "<=", + [lua53] DoubleLessThan => "<<", + Minus => "-", + Percent => "%", + [luau | lua53] Pipe => "|", + Plus => "+", + [luau] QuestionMark => "?", + RightBrace => "}", + RightBracket => "]", + RightParen => ")", + Semicolon => ";", + Slash => "/", + [luau | lua53] DoubleSlash => "//", + Star => "*", + [lua53] Tilde => "~", + TildeEqual => "~=", } } -impl Display for Symbol { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - let value = match self { - Symbol::And => "and", - Symbol::Break => "break", - Symbol::Do => "do", - Symbol::Else => "else", - Symbol::ElseIf => "elseif", - Symbol::End => "end", - Symbol::False => "false", - Symbol::For => "for", - Symbol::Function => "function", - Symbol::If => "if", - Symbol::In => "in", - Symbol::Local => "local", - Symbol::Nil => "nil", - Symbol::Not => "not", - Symbol::Or => "or", - Symbol::Repeat => "repeat", - Symbol::Return => "return", - Symbol::Then => "then", - Symbol::True => "true", - Symbol::Until => "until", - Symbol::While => "while", - #[cfg(feature = "lua52")] - Symbol::Goto => "goto", - Symbol::PlusEqual => "+=", - Symbol::MinusEqual => "-=", - Symbol::StarEqual => "*=", - Symbol::SlashEqual => "/=", - #[cfg(feature = "roblox")] - Symbol::DoubleSlashEqual => "//=", - Symbol::PercentEqual => "%=", - Symbol::CaretEqual => "^=", - Symbol::TwoDotsEqual => "..=", - #[cfg(any(feature = "roblox", feature = "lua53"))] - Symbol::Ampersand => "&", - #[cfg(feature = "roblox")] - Symbol::ThinArrow => "->", - #[cfg(any(feature = "roblox", feature = "lua52"))] - Symbol::TwoColons => "::", - Symbol::Caret => "^", - Symbol::Colon => ":", - Symbol::Comma => ",", - Symbol::Ellipse => "...", - Symbol::TwoDots => "..", - Symbol::Dot => ".", - Symbol::TwoEqual => "==", - Symbol::Equal => "=", - Symbol::GreaterThanEqual => ">=", - Symbol::GreaterThan => ">", - #[cfg(feature = "lua53")] - Symbol::DoubleGreaterThan => ">>", - Symbol::Hash => "#", - Symbol::LeftBracket => "[", - Symbol::LeftBrace => "{", - Symbol::LeftParen => "(", - Symbol::LessThanEqual => "<=", - Symbol::LessThan => "<", - #[cfg(feature = "lua53")] - Symbol::DoubleLessThan => "<<", - Symbol::Minus => "-", - Symbol::Percent => "%", - #[cfg(any(feature = "roblox", feature = "lua53"))] - Symbol::Pipe => "|", - Symbol::Plus => "+", - #[cfg(feature = "roblox")] - Symbol::QuestionMark => "?", - Symbol::RightBrace => "}", - Symbol::RightBracket => "]", - Symbol::RightParen => ")", - Symbol::Semicolon => ";", - Symbol::Slash => "/", - #[cfg(any(feature = "roblox", feature = "lua53"))] - Symbol::DoubleSlash => "//", - Symbol::Star => "*", - #[cfg(feature = "lua53")] - Symbol::Tilde => "~", - Symbol::TildeEqual => "~=", - }; +#[cfg(feature = "luau")] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +/// Whether or not this section is the beginning, middle, end, or if this is a standalone string. +pub enum InterpolatedStringKind { + /// `begin{ + Begin, - value.fmt(formatter) - } + /// }middle{ + Middle, + + /// }end` + End, + + /// `simple` + Simple, } /// The possible errors that can happen while tokenizing. @@ -377,8 +197,8 @@ pub enum TokenizerErrorType { UnclosedComment, /// An unclosed string was found UnclosedString, - /// An unexpected #! was found - UnexpectedShebang, + /// An invalid number was found + InvalidNumber, /// An unexpected token was found UnexpectedToken(char), /// Symbol passed is not valid @@ -391,10 +211,10 @@ impl fmt::Display for TokenizerErrorType { match self { TokenizerErrorType::UnclosedComment => "unclosed comment".fmt(formatter), TokenizerErrorType::UnclosedString => "unclosed string".fmt(formatter), - TokenizerErrorType::UnexpectedShebang => "unexpected shebang".fmt(formatter), TokenizerErrorType::UnexpectedToken(character) => { write!(formatter, "unexpected character {character}") } + TokenizerErrorType::InvalidNumber => "invalid number".fmt(formatter), TokenizerErrorType::InvalidSymbol(symbol) => { write!(formatter, "invalid symbol {symbol}") } @@ -402,6 +222,11 @@ impl fmt::Display for TokenizerErrorType { } } +// Used by serde +fn is_usize_zero(input: &usize) -> bool { + *input == 0 +} + /// The type of tokens in parsed code #[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] @@ -448,12 +273,12 @@ pub enum TokenType { StringLiteral { /// The literal itself, ignoring quotation marks literal: ShortString, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "is_usize_zero"))] /// Number of equals signs used for a multi line string, if it is one - /// For example, `[=[string]=]` would have a `multi_line` value of Some(1) - /// `[[string]]` would have a `multi_line` value of Some(0) - /// A string such as `"string"` would have a `multi_line` value of None - multi_line: Option, + /// For example, `[=[string]=]` would have a `multi_line_depth` value of 1 + /// `[[string]]` would have a `multi_line_depth` value of 0 + /// A string such as `"string"` would have also have a `multi_line_depth` value of 0 + multi_line_depth: usize, /// The type of quotation mark used to make the string quote_type: StringLiteralQuoteType, }, @@ -471,7 +296,7 @@ pub enum TokenType { }, /// Some form of interpolated string - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] InterpolatedString { /// The literal itself, ignoring backticks literal: ShortString, @@ -483,33 +308,6 @@ pub enum TokenType { } impl TokenType { - fn new_string(literal: &str, quote_type: StringLiteralQuoteType) -> Self { - let literal = literal.into(); - - Self::StringLiteral { - literal, - quote_type, - multi_line: None, - } - } - - /// Can this token type contain new lines? - fn is_extensive(&self) -> bool { - #[cfg(feature = "roblox")] - let is_interpolated_string = matches!(self, TokenType::InterpolatedString { .. }); - - #[cfg(not(feature = "roblox"))] - let is_interpolated_string = false; - - matches!( - self, - TokenType::MultiLineComment { .. } - | TokenType::Shebang { .. } - | TokenType::StringLiteral { .. } - | TokenType::Whitespace { .. } - ) || is_interpolated_string - } - /// Returns whether a token can be practically ignored in most cases /// Comments and whitespace will return `true`, everything else will return `false` pub fn is_trivia(&self) -> bool { @@ -546,7 +344,7 @@ impl TokenType { TokenType::Symbol { .. } => TokenKind::Symbol, TokenType::Whitespace { .. } => TokenKind::Whitespace, - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] TokenType::InterpolatedString { .. } => TokenKind::InterpolatedString, } } @@ -589,13 +387,13 @@ pub enum TokenKind { /// Whitespace, such as tabs or new lines Whitespace, - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] /// Some form of interpolated string InterpolatedString, } /// A token such consisting of its [`Position`] and a [`TokenType`] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Token { pub(crate) start_position: Position, @@ -651,19 +449,24 @@ impl fmt::Display for Token { SingleLineComment { comment } => write!(formatter, "--{comment}"), StringLiteral { literal, - multi_line, + multi_line_depth, quote_type, } => { - if let Some(blocks) = multi_line { - write!(formatter, "[{0}[{1}]{0}]", "=".repeat(*blocks), literal) + if *quote_type == StringLiteralQuoteType::Brackets { + write!( + formatter, + "[{0}[{1}]{0}]", + "=".repeat(*multi_line_depth), + literal + ) } else { - write!(formatter, "{quote_type}{literal}{quote_type}") + write!(formatter, "{0}{1}{0}", quote_type.to_string(), literal) } } Symbol { symbol } => symbol.fmt(formatter), Whitespace { characters } => characters.fmt(formatter), - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] InterpolatedString { literal, kind } => match kind { InterpolatedStringKind::Begin => { write!(formatter, "`{literal}{{") @@ -685,16 +488,6 @@ impl fmt::Display for Token { } } -impl PartialEq for Token { - fn eq(&self, rhs: &Self) -> bool { - self.start_position() == rhs.start_position() - && self.end_position() == rhs.end_position() - && self.token_type == rhs.token_type - } -} - -impl Eq for Token {} - impl Ord for Token { fn cmp(&self, other: &Self) -> Ordering { self.start_position().cmp(&other.start_position()) @@ -722,7 +515,7 @@ impl Visit for Token { TokenKind::Symbol => visitor.visit_symbol(self), TokenKind::Whitespace => visitor.visit_whitespace(self), - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] TokenKind::InterpolatedString => visitor.visit_interpolated_string_segment(self), } } @@ -743,7 +536,7 @@ impl VisitMut for Token { TokenKind::Symbol => visitor.visit_symbol(token), TokenKind::Whitespace => visitor.visit_whitespace(token), - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] TokenKind::InterpolatedString => visitor.visit_interpolated_string_segment(token), } } @@ -786,39 +579,120 @@ impl TokenReference { /// # } /// ``` pub fn symbol(text: &str) -> Result { - let mut lexer = Atom::lexer(text).spanned().peekable(); + TokenReference::symbol_specific_lua_version(text, LuaVersion::new()) + } + + pub(crate) fn basic_symbol(text: &str) -> Self { + TokenReference::symbol_specific_lua_version(text, LuaVersion::lua51()).unwrap() + } + + /// Returns a symbol with the leading and trailing whitespace, + /// much like [`TokenReference::symbol`], but only if it's valid + /// for the given Lua version. + #[cfg_attr( + feature = "lua52", + doc = r##" + ```rust + # use full_moon::tokenizer::{Symbol, TokenReference, TokenType, TokenizerErrorType}; + # use full_moon::LuaVersion; + # fn main() -> Result<(), Box> { + assert!(TokenReference::symbol_specific_lua_version("goto", LuaVersion::lua51()).is_err()); + assert!(TokenReference::symbol_specific_lua_version("goto", LuaVersion::lua52()).is_ok()); + # Ok(()) + # } + "## + )] + pub fn symbol_specific_lua_version( + text: &str, + lua_version: LuaVersion, + ) -> Result { + let mut lexer = Lexer::new_lazy(text, lua_version); + + let mut leading_trivia = Vec::new(); + let symbol; + + loop { + match lexer.process_next() { + Some(LexerResult::Ok( + token @ Token { + token_type: TokenType::Whitespace { .. }, + .. + }, + )) => { + leading_trivia.push(token); + } - let leading_trivia = lexer - .next_if(|v| v.0 == Atom::Whitespace) - .map(|v| text[v.1].into()) - .unwrap_or_default(); + Some(LexerResult::Ok( + token @ Token { + token_type: TokenType::Symbol { .. }, + .. + }, + )) => { + symbol = token; + break; + } - let (atom, span) = lexer.next().unwrap(); - let symbol = atom.try_into().map_err(|_| { - let text = text[span].to_string(); + Some(LexerResult::Ok(Token { + token_type: TokenType::Eof, + .. + })) => { + return Err(TokenizerErrorType::InvalidSymbol(text.to_owned())); + } - TokenizerErrorType::InvalidSymbol(text) - })?; + Some(LexerResult::Ok(token)) => { + return Err(TokenizerErrorType::UnexpectedToken( + token.to_string().chars().next().unwrap(), + )); + } - let trailing_trivia = lexer - .next_if(|v| v.0 == Atom::Whitespace) - .map(|v| text[v.1].into()) - .unwrap_or_default(); + Some(LexerResult::Fatal(mut errors) | LexerResult::Recovered(_, mut errors)) => { + return Err(errors.remove(0).error); + } + + None => unreachable!("we shouldn't have hit eof"), + } + } + + let mut trailing_trivia = Vec::new(); + + loop { + match lexer.process_next() { + Some(LexerResult::Ok( + token @ Token { + token_type: TokenType::Whitespace { .. }, + .. + }, + )) => { + trailing_trivia.push(token); + } - if let Some(v) = lexer.next() { - let ch = text[v.1].chars().next().unwrap(); + Some(LexerResult::Ok(Token { + token_type: TokenType::Eof, + .. + })) => { + break; + } + + Some(LexerResult::Ok(token)) => { + return Err(TokenizerErrorType::UnexpectedToken( + token.to_string().chars().next().unwrap(), + )); + } - return Err(TokenizerErrorType::UnexpectedToken(ch)); + Some(LexerResult::Fatal(mut errors) | LexerResult::Recovered(_, mut errors)) => { + return Err(errors.remove(0).error); + } + + None => { + unreachable!("we shouldn't have hit eof"); + } + } } - Ok(Self { - leading_trivia: vec![Token::new(TokenType::Whitespace { - characters: leading_trivia, - })], - token: Token::new(TokenType::Symbol { symbol }), - trailing_trivia: vec![Token::new(TokenType::Whitespace { - characters: trailing_trivia, - })], + Ok(TokenReference { + leading_trivia, + token: symbol, + trailing_trivia, }) } @@ -845,6 +719,11 @@ impl TokenReference { trailing_trivia: self.trailing_trivia.clone(), } } + + /// Checks if the token is the given symbol + pub fn is_symbol(&self, symbol: Symbol) -> bool { + self.token.token_type() == &TokenType::Symbol { symbol } + } } impl std::borrow::Borrow for &TokenReference { @@ -982,170 +861,24 @@ pub enum StringLiteralQuoteType { impl fmt::Display for StringLiteralQuoteType { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { match *self { - StringLiteralQuoteType::Brackets => unreachable!(), + // Brackets cannot be properly displayed, as not only do they have + // variable depth (`=`), but also they don't open the same as + // they end, meaning this can't really be used for display purposes. + StringLiteralQuoteType::Brackets => Err(fmt::Error), StringLiteralQuoteType::Double => "\"".fmt(formatter), StringLiteralQuoteType::Single => "'".fmt(formatter), } } } -type RawToken = Result; - -impl From for RawToken { - fn from(token_type: TokenType) -> RawToken { - Ok(token_type) - } -} - -impl From for RawToken { - fn from(error: TokenizerErrorType) -> RawToken { - Err(error) - } -} - -fn tokenize(token: Atom, slice: &str) -> RawToken { - match token { - Atom::Identifier => { - let identifier = slice.into(); - - Ok(TokenType::Identifier { identifier }) - } - - Atom::Comment => { - let (comment, blocks) = trim_bracket_head(&slice[2..]); - - match blocks { - Some(blocks) => Ok(TokenType::MultiLineComment { comment, blocks }), - None => Ok(TokenType::SingleLineComment { comment }), - } - } - - Atom::Number => { - let text = slice.into(); - - Ok(TokenType::Number { text }) - } - - Atom::MultiLineString => { - let (literal, multi_line) = trim_bracket_head(slice); - - Ok(TokenType::StringLiteral { - literal, - multi_line, - quote_type: StringLiteralQuoteType::Brackets, - }) - } - - Atom::ApostropheString => Ok(TokenType::new_string( - &slice[1..slice.len() - 1], - StringLiteralQuoteType::Single, - )), - - Atom::QuoteString => Ok(TokenType::new_string( - &slice[1..slice.len() - 1], - StringLiteralQuoteType::Double, - )), - - Atom::Whitespace => { - let characters = slice.into(); - - Ok(TokenType::Whitespace { characters }) - } - - Atom::Bom => Err(TokenizerErrorType::UnexpectedToken('\u{feff}')), - - Atom::Shebang => Err(TokenizerErrorType::UnexpectedShebang), - - #[cfg(feature = "roblox")] - Atom::InterpolatedStringBegin(InterpolatedStringBegin::Simple) - | Atom::InterpolatedStringBegin(InterpolatedStringBegin::Formatted) - | Atom::RightBrace(Some(InterpolatedStringSection::Middle)) - | Atom::RightBrace(Some(InterpolatedStringSection::End)) => { - Ok(TokenType::InterpolatedString { - literal: ShortString::new(&slice[1..slice.len() - 1]), - kind: match token { - Atom::InterpolatedStringBegin(InterpolatedStringBegin::Simple) => { - InterpolatedStringKind::Simple - } - - Atom::InterpolatedStringBegin(InterpolatedStringBegin::Formatted) => { - InterpolatedStringKind::Begin - } - - Atom::RightBrace(Some(InterpolatedStringSection::Middle)) => { - InterpolatedStringKind::Middle - } - - Atom::RightBrace(Some(InterpolatedStringSection::End)) => { - InterpolatedStringKind::End - } - - _ => unreachable!(), - }, - }) - } - - Atom::Unknown => { - let first = slice.chars().next().unwrap(); - let what = match first { - '`' if cfg!(feature = "roblox") => TokenizerErrorType::UnclosedString, - '\'' | '"' | '[' => TokenizerErrorType::UnclosedString, - '-' => TokenizerErrorType::UnclosedComment, - other => TokenizerErrorType::UnexpectedToken(other), - }; - - Err(what) - } - - token => Ok(TokenType::Symbol { - symbol: token.try_into().unwrap(), - }), - } -} - -fn next_if(lexer: &mut Lexer, atom: Atom) -> Option { - if lexer.clone().next() == Some(atom) { - lexer.next(); - - Some(lexer.slice().into()) - } else { - None - } -} - -fn tokenize_code(code: &str) -> Vec<(RawToken, Span)> { - let mut lexer = Atom::lexer(code); - let mut list = Vec::new(); - - if let Some(characters) = next_if(&mut lexer, Atom::Bom) { - let raw = (Ok(TokenType::Whitespace { characters }), lexer.span()); - - list.push(raw); - } - - if let Some(line) = next_if(&mut lexer, Atom::Shebang) { - let raw = (Ok(TokenType::Shebang { line }), lexer.span()); - - list.push(raw); - } - - while let Some(atom) = lexer.next() { - let raw = (tokenize(atom, lexer.slice()), lexer.span()); - - list.push(raw); - } - - list -} - /// Information about an error that occurs while tokenizing #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct TokenizerError { /// The type of error - error: TokenizerErrorType, - /// The position of the token that caused the error - position: Position, + pub(crate) error: TokenizerErrorType, + /// The range of the token that caused the error + pub(crate) range: (Position, Position), } impl TokenizerError { @@ -1154,9 +887,14 @@ impl TokenizerError { &self.error } - /// The position of the token that caused the error + /// The position of the first token that caused the error pub fn position(&self) -> Position { - self.position + self.range.0 + } + + /// The range of the token that caused the error + pub fn range(&self) -> (Position, Position) { + self.range } } @@ -1164,130 +902,20 @@ impl fmt::Display for TokenizerError { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!( formatter, - "{} at line {}, column {}", - self.error, self.position.line, self.position.character, + "{} ({}:{} to {}:{})", + self.error, + self.range.0.line, + self.range.0.character, + self.range.1.line, + self.range.1.character ) } } impl std::error::Error for TokenizerError {} -struct TokenCollector { - result: Vec, -} - -// Collector -impl TokenCollector { - fn new() -> Self { - Self { result: Vec::new() } - } - fn push( - &mut self, - start_position: Position, - raw_token: RawToken, - end_position: Position, - ) -> Result<(), TokenizerError> { - match raw_token { - Ok(token_type) => { - self.result.push(Token { - start_position, - end_position, - token_type, - }); - Ok(()) - } - Err(error) => Err(TokenizerError { - error, - position: start_position, - }), - } - } - fn finish(mut self, eof_position: Position) -> Vec { - self.result.push(Token { - start_position: eof_position, - end_position: eof_position, - token_type: TokenType::Eof, - }); - self.result - } -} - -fn read_position(code: &str, position: &mut Position) -> bool { - let mut has_newline = false; - - for c in code.chars() { - if has_newline { - position.line += 1; - position.character = 1; - - has_newline = false; - } - - if c == '\n' { - has_newline = true; - } else { - position.character += 1; - } - } - - has_newline -} - -/// Returns a list of tokens. -/// You probably want [`parse`](crate::parse) instead. -/// -/// # Errors -/// -/// If the code passed is malformed from normal Lua expectations, -/// a [`TokenizerError`] will be returned. -/// -/// ```rust -/// # use full_moon::tokenizer::tokens; -/// assert!(tokens("local x = 1").is_ok()); -/// assert!(tokens("local 4 = end").is_ok()); // tokens does *not* check validity of code, only tokenizing -/// assert!(tokens("--[[ Unclosed comment!").is_err()); -/// ``` -pub fn tokens(code: &str) -> Result, TokenizerError> { - let mut tokens = TokenCollector::new(); - - // Logos provides token start and end information, - // but not the line or column. We iterate over the - // characters to retrieve this. - let mut position = Position { - bytes: 0, - line: 1, - character: 1, - }; - - for (token, span) in tokenize_code(code) { - let start_position = position; - - position.bytes = span.end; - - if token - .as_ref() - .map(TokenType::is_extensive) - .unwrap_or_default() - { - let has_newline = read_position(&code[span.clone()], &mut position); - - tokens.push(start_position, token, position)?; - - if has_newline { - position.line += 1; - position.character = 1; - } - } else { - position.character += span.len(); - - tokens.push(start_position, token, position)?; - } - } - - Ok(tokens.finish(position)) -} - -#[cfg(test)] +// #[cfg(test)] +#[cfg(feature = "rewrite todo: tokenizer tests")] mod tests { use crate::tokenizer::*; use pretty_assertions::assert_eq; @@ -1357,7 +985,7 @@ mod tests { } #[test] - #[cfg_attr(not(feature = "roblox"), ignore)] + #[cfg_attr(not(feature = "luau"), ignore)] fn test_rule_binary_literals() { test_rule!( "0b101", @@ -1551,7 +1179,7 @@ mod tests { ); } - #[cfg(feature = "roblox")] + #[cfg(feature = "luau")] #[test] fn test_string_interpolation_multi_line() { let tokens = tokens("`Welcome to \\\n{name}!`").unwrap(); diff --git a/full-moon/src/tokenizer_luau.rs b/full-moon/src/tokenizer_luau.rs index 5d8d4795..441d3390 100644 --- a/full-moon/src/tokenizer_luau.rs +++ b/full-moon/src/tokenizer_luau.rs @@ -87,26 +87,3 @@ pub(crate) fn read_left_brace(lexer: &mut Lexer) -> bool { lexer.extras.brace_stack.push(BraceType::Normal); true } - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -/// Whether or not this section is the beginning, middle, end, or if this is a standalone string. -pub enum InterpolatedStringKind { - /// `begin{ - Begin, - - /// }middle{ - Middle, - - /// }end` - End, - - /// `simple` - Simple, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum BraceType { - InterpolatedString, - Normal, -} diff --git a/full-moon/src/util.rs b/full-moon/src/util.rs index c6ca454f..3ec6b009 100644 --- a/full-moon/src/util.rs +++ b/full-moon/src/util.rs @@ -5,7 +5,7 @@ use crate::ast::punctuated::Punctuated; use std::fmt::Write; // Check if the vector is empty or full of None's -#[cfg(any(feature = "lua54", feature = "roblox"))] +#[cfg(any(feature = "lua54", feature = "luau"))] #[allow(clippy::ptr_arg)] pub fn empty_optional_vector(vec: &Vec>) -> bool { vec.iter().all(Option::is_none) @@ -42,7 +42,7 @@ pub fn join_vec>(vec: V) -> String { string } -#[cfg(feature = "roblox")] +#[cfg(feature = "luau")] pub fn join_type_specifiers>, T1: Display, T2: Display>( parameters: &Punctuated, type_specifiers: I, @@ -96,3 +96,26 @@ pub fn join_iterators< string } + +#[doc(hidden)] +#[macro_export] +macro_rules! has_version { + ($lua_state:expr, ) => { + true + }; + + ($lua_version:expr, $($version:ident,)+) => {{ + paste::paste! { + let mut version_passes = false; + + $( + #[cfg(feature = "" $version)] + if $lua_version.[]() { + version_passes = true; + } + )+ + + version_passes + }} + }; +} diff --git a/full-moon/src/visitors.rs b/full-moon/src/visitors.rs index 92c89903..a41c9eef 100644 --- a/full-moon/src/visitors.rs +++ b/full-moon/src/visitors.rs @@ -8,7 +8,7 @@ use crate::{ use crate::ast::lua52::*; #[cfg(feature = "lua54")] use crate::ast::lua54::*; -#[cfg(feature = "roblox")] +#[cfg(feature = "luau")] use crate::ast::types::*; macro_rules! create_visitor { @@ -31,7 +31,7 @@ macro_rules! create_visitor { /// ```rust /// # use full_moon::ast; /// # use full_moon::visitors::*; - /// # fn main() -> Result<(), Box> { + /// # fn main() -> Result<(), Vec> { /// // A visitor that logs every local assignment made /// #[derive(Default)] /// struct LocalVariableVisitor { @@ -277,7 +277,7 @@ create_visitor!(ast: { visit_while => While, // Types - #[cfg(feature = "roblox")] { + #[cfg(feature = "luau")] { visit_compound_assignment => CompoundAssignment, visit_compound_op => CompoundOp, visit_else_if_expression => ElseIfExpression, @@ -316,7 +316,7 @@ create_visitor!(ast: { visit_token, visit_whitespace, - #[cfg(feature = "roblox")] { + #[cfg(feature = "luau")] { visit_interpolated_string_segment, } }); diff --git a/full-moon/tests/cases/fail/parser/assignment-1/ast.snap b/full-moon/tests/cases/fail/parser/assignment-1/ast.snap new file mode 100644 index 00000000..2166604e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/assignment-1/ast.snap @@ -0,0 +1,71 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/assignment-1 +--- +nodes: + stmts: + - - Assignment: + var_list: + pairs: + - End: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: [] + expr_list: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/assignment-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/assignment-1/ast_to_string.snap new file mode 100644 index 00000000..d60d3ae1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/assignment-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/assignment-1 +--- +x = + diff --git a/full-moon/tests/cases/fail/parser/assignment-1/error.snap b/full-moon/tests/cases/fail/parser/assignment-1/error.snap deleted file mode 100644 index 3b8f0574..00000000 --- a/full-moon/tests/cases/fail/parser/assignment-1/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/assignment-1 - ---- -UnexpectedToken: - token: - start_position: - bytes: 3 - line: 1 - character: 4 - end_position: - bytes: 3 - line: 1 - character: 4 - token_type: - type: Eof - additional: expected values - diff --git a/full-moon/tests/cases/fail/parser/assignment-1/error_display.snap b/full-moon/tests/cases/fail/parser/assignment-1/error_display.snap new file mode 100644 index 00000000..dd052ce7 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/assignment-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/assignment-1 +--- +error[ast]: expected values to set to + ┌─ source.lua:1:3 + │ +1 │ x = + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/assignment-1/errors.snap b/full-moon/tests/cases/fail/parser/assignment-1/errors.snap new file mode 100644 index 00000000..8fdfabb4 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/assignment-1/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/assignment-1 +--- +- AstError: + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "=" + additional: expected values to set to + diff --git a/full-moon/tests/cases/fail/parser/assignment-2/ast.snap b/full-moon/tests/cases/fail/parser/assignment-2/ast.snap new file mode 100644 index 00000000..163310d0 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/assignment-2/ast.snap @@ -0,0 +1,82 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/assignment-2 +--- +nodes: + stmts: + - - Assignment: + var_list: + pairs: + - End: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/assignment-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/assignment-2/ast_to_string.snap new file mode 100644 index 00000000..beb56397 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/assignment-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/assignment-2 +--- +"x = " + diff --git a/full-moon/tests/cases/fail/parser/assignment-2/error.snap b/full-moon/tests/cases/fail/parser/assignment-2/error.snap deleted file mode 100644 index d4ca441f..00000000 --- a/full-moon/tests/cases/fail/parser/assignment-2/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/assignment-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 4 - line: 1 - character: 5 - end_position: - bytes: 7 - line: 1 - character: 8 - token_type: - type: Symbol - symbol: end - additional: expected values - diff --git a/full-moon/tests/cases/fail/parser/assignment-2/error_display.snap b/full-moon/tests/cases/fail/parser/assignment-2/error_display.snap new file mode 100644 index 00000000..94e9ebe9 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/assignment-2/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/assignment-2 +--- +error[ast]: expected values to set to + ┌─ source.lua:1:3 + │ +1 │ x = end + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:5 + │ +1 │ x = end + │ ^^^ + + diff --git a/full-moon/tests/cases/fail/parser/assignment-2/errors.snap b/full-moon/tests/cases/fail/parser/assignment-2/errors.snap new file mode 100644 index 00000000..a2865863 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/assignment-2/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/assignment-2 +--- +- AstError: + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "=" + additional: expected values to set to +- AstError: + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Symbol + symbol: end + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/if-1/error.snap b/full-moon/tests/cases/fail/parser/assignment-3/ast.snap similarity index 57% rename from full-moon/tests/cases/fail/parser/if-1/error.snap rename to full-moon/tests/cases/fail/parser/assignment-3/ast.snap index 259f266b..1a91149a 100644 --- a/full-moon/tests/cases/fail/parser/if-1/error.snap +++ b/full-moon/tests/cases/fail/parser/assignment-3/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/if-1 - +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/assignment-3 --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 9 @@ -16,5 +19,5 @@ UnexpectedToken: character: 10 token_type: type: Eof - additional: "expected 'end'" + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/assignment-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/assignment-3/ast_to_string.snap new file mode 100644 index 00000000..6ef16650 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/assignment-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/assignment-3 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/assignment-3/error.snap b/full-moon/tests/cases/fail/parser/assignment-3/error.snap deleted file mode 100644 index 350751b4..00000000 --- a/full-moon/tests/cases/fail/parser/assignment-3/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/assignment-3 - ---- -UnexpectedToken: - token: - start_position: - bytes: 0 - line: 1 - character: 1 - end_position: - bytes: 5 - line: 1 - character: 6 - token_type: - type: Symbol - symbol: until - additional: leftover token - diff --git a/full-moon/tests/cases/fail/parser/assignment-3/error_display.snap b/full-moon/tests/cases/fail/parser/assignment-3/error_display.snap new file mode 100644 index 00000000..384242f5 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/assignment-3/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/assignment-3 +--- +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:1 + │ +1 │ until = 3 + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/assignment-3/errors.snap b/full-moon/tests/cases/fail/parser/assignment-3/errors.snap new file mode 100644 index 00000000..48344c4d --- /dev/null +++ b/full-moon/tests/cases/fail/parser/assignment-3/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/assignment-3 +--- +- AstError: + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: until + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/bin-op-1/ast.snap b/full-moon/tests/cases/fail/parser/bin-op-1/ast.snap new file mode 100644 index 00000000..53a108c4 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/bin-op-1/ast.snap @@ -0,0 +1,81 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/bin-op-1 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Number + text: "1" + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/bin-op-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/bin-op-1/ast_to_string.snap new file mode 100644 index 00000000..7388d2d9 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/bin-op-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/bin-op-1 +--- +"return 1 " + diff --git a/full-moon/tests/cases/fail/parser/bin-op-1/error.snap b/full-moon/tests/cases/fail/parser/bin-op-1/error.snap deleted file mode 100644 index b0322d80..00000000 --- a/full-moon/tests/cases/fail/parser/bin-op-1/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/bin-op-1 - ---- -UnexpectedToken: - token: - start_position: - bytes: 10 - line: 1 - character: 11 - end_position: - bytes: 10 - line: 1 - character: 11 - token_type: - type: Eof - additional: expected expression - diff --git a/full-moon/tests/cases/fail/parser/bin-op-1/error_display.snap b/full-moon/tests/cases/fail/parser/bin-op-1/error_display.snap new file mode 100644 index 00000000..751e6d01 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/bin-op-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/bin-op-1 +--- +error[ast]: expected expression after binary operator + ┌─ source.lua:1:10 + │ +1 │ return 1 + + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/bin-op-1/errors.snap b/full-moon/tests/cases/fail/parser/bin-op-1/errors.snap new file mode 100644 index 00000000..89abb66f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/bin-op-1/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/bin-op-1 +--- +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: + + additional: expected expression after binary operator + diff --git a/full-moon/tests/cases/fail/parser/bin-op-2/ast.snap b/full-moon/tests/cases/fail/parser/bin-op-2/ast.snap new file mode 100644 index 00000000..244911f1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/bin-op-2/ast.snap @@ -0,0 +1,81 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/bin-op-2 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Number + text: "1" + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/bin-op-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/bin-op-2/ast_to_string.snap new file mode 100644 index 00000000..14f0337b --- /dev/null +++ b/full-moon/tests/cases/fail/parser/bin-op-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/bin-op-2 +--- +"return 1 " + diff --git a/full-moon/tests/cases/fail/parser/bin-op-2/error.snap b/full-moon/tests/cases/fail/parser/bin-op-2/error.snap deleted file mode 100644 index 48788a17..00000000 --- a/full-moon/tests/cases/fail/parser/bin-op-2/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/bin-op-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 11 - line: 1 - character: 12 - end_position: - bytes: 16 - line: 1 - character: 17 - token_type: - type: Symbol - symbol: until - additional: expected expression - diff --git a/full-moon/tests/cases/fail/parser/bin-op-2/error_display.snap b/full-moon/tests/cases/fail/parser/bin-op-2/error_display.snap new file mode 100644 index 00000000..606bcb79 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/bin-op-2/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/bin-op-2 +--- +error[ast]: expected expression after binary operator + ┌─ source.lua:1:10 + │ +1 │ return 1 + until + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:12 + │ +1 │ return 1 + until + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/bin-op-2/errors.snap b/full-moon/tests/cases/fail/parser/bin-op-2/errors.snap new file mode 100644 index 00000000..6cdc9042 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/bin-op-2/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/bin-op-2 +--- +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: + + additional: expected expression after binary operator +- AstError: + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Symbol + symbol: until + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/call-1/ast.snap b/full-moon/tests/cases/fail/parser/call-1/ast.snap new file mode 100644 index 00000000..5842f226 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-1/ast.snap @@ -0,0 +1,77 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/call-1 +--- +nodes: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/call-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/call-1/ast_to_string.snap new file mode 100644 index 00000000..d6f40b12 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/call-1 +--- +call() + diff --git a/full-moon/tests/cases/fail/parser/call-1/error.snap b/full-moon/tests/cases/fail/parser/call-1/error.snap deleted file mode 100644 index fb80435e..00000000 --- a/full-moon/tests/cases/fail/parser/call-1/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/call-1 - ---- -UnexpectedToken: - token: - start_position: - bytes: 5 - line: 1 - character: 6 - end_position: - bytes: 5 - line: 1 - character: 6 - token_type: - type: Eof - additional: "expected ')'" - diff --git a/full-moon/tests/cases/fail/parser/call-1/error_display.snap b/full-moon/tests/cases/fail/parser/call-1/error_display.snap new file mode 100644 index 00000000..fe2ed585 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/call-1 +--- +error[ast]: expected `)` to close function call + ┌─ source.lua:1:5 + │ +1 │ call( + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/call-1/errors.snap b/full-moon/tests/cases/fail/parser/call-1/errors.snap new file mode 100644 index 00000000..b1efc06a --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-1/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/call-1 +--- +- AstError: + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: ( + additional: "expected `)` to close function call" + diff --git a/full-moon/tests/cases/fail/parser/call-2/ast.snap b/full-moon/tests/cases/fail/parser/call-2/ast.snap new file mode 100644 index 00000000..ab8efbb4 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-2/ast.snap @@ -0,0 +1,94 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/call-2 +--- +nodes: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: + - End: + String: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: StringLiteral + literal: hello + quote_type: Double + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/call-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/call-2/ast_to_string.snap new file mode 100644 index 00000000..3e2bbcb7 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/call-2 +--- +"call(\"hello\")" + diff --git a/full-moon/tests/cases/fail/parser/call-2/error.snap b/full-moon/tests/cases/fail/parser/call-2/error.snap deleted file mode 100644 index 9d2f3d82..00000000 --- a/full-moon/tests/cases/fail/parser/call-2/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/call-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 12 - line: 1 - character: 13 - end_position: - bytes: 12 - line: 1 - character: 13 - token_type: - type: Eof - additional: "expected ')'" - diff --git a/full-moon/tests/cases/fail/parser/call-2/error_display.snap b/full-moon/tests/cases/fail/parser/call-2/error_display.snap new file mode 100644 index 00000000..b00135ec --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-2/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/call-2 +--- +error[ast]: expected `)` to close function call + ┌─ source.lua:1:5 + │ +1 │ call("hello" + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/call-2/errors.snap b/full-moon/tests/cases/fail/parser/call-2/errors.snap new file mode 100644 index 00000000..55506155 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-2/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/call-2 +--- +- AstError: + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: ( + additional: "expected `)` to close function call" + diff --git a/full-moon/tests/cases/fail/parser/call-3/ast.snap b/full-moon/tests/cases/fail/parser/call-3/ast.snap new file mode 100644 index 00000000..beadf471 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-3/ast.snap @@ -0,0 +1,136 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/call-3 +--- +nodes: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: + - Punctuated: + - String: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: StringLiteral + literal: hello + quote_type: Double + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Whitespace + characters: " " + - End: + String: + leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 21 + line: 1 + character: 22 + token_type: + type: StringLiteral + literal: world + quote_type: Double + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 21 + line: 1 + character: 22 + end_position: + bytes: 21 + line: 1 + character: 22 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/call-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/call-3/ast_to_string.snap new file mode 100644 index 00000000..440a9252 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/call-3 +--- +"call(\"hello\", \"world\")" + diff --git a/full-moon/tests/cases/fail/parser/call-3/error_display.snap b/full-moon/tests/cases/fail/parser/call-3/error_display.snap new file mode 100644 index 00000000..eb09a070 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-3/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/call-3 +--- +error[ast]: expected `)` to close function call + ┌─ source.lua:1:5 + │ +1 │ call("hello", "world" + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/call-3/errors.snap b/full-moon/tests/cases/fail/parser/call-3/errors.snap new file mode 100644 index 00000000..083784b6 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-3/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/call-3 +--- +- AstError: + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: ( + additional: "expected `)` to close function call" + diff --git a/full-moon/tests/cases/fail/parser/call-4/ast.snap b/full-moon/tests/cases/fail/parser/call-4/ast.snap new file mode 100644 index 00000000..215fa487 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-4/ast.snap @@ -0,0 +1,77 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/call-4 +--- +nodes: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/call-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/call-4/ast_to_string.snap new file mode 100644 index 00000000..d9f59e24 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/call-4 +--- +call() + diff --git a/full-moon/tests/cases/fail/parser/call-4/error.snap b/full-moon/tests/cases/fail/parser/call-4/error.snap deleted file mode 100644 index 67a73b92..00000000 --- a/full-moon/tests/cases/fail/parser/call-4/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/call-4 - ---- -UnexpectedToken: - token: - start_position: - bytes: 5 - line: 1 - character: 6 - end_position: - bytes: 8 - line: 1 - character: 9 - token_type: - type: Symbol - symbol: end - additional: "expected ')'" - diff --git a/full-moon/tests/cases/fail/parser/call-4/error_display.snap b/full-moon/tests/cases/fail/parser/call-4/error_display.snap new file mode 100644 index 00000000..8e453c8d --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-4/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/call-4 +--- +error[ast]: expected `)` to close function call + ┌─ source.lua:1:5 + │ +1 │ call(end) + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:6 + │ +1 │ call(end) + │ ^^^ + + diff --git a/full-moon/tests/cases/fail/parser/call-4/errors.snap b/full-moon/tests/cases/fail/parser/call-4/errors.snap new file mode 100644 index 00000000..904d3da4 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/call-4/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/call-4 +--- +- AstError: + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: ( + additional: "expected `)` to close function call" +- AstError: + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: end + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/do-1/ast.snap b/full-moon/tests/cases/fail/parser/do-1/ast.snap new file mode 100644 index 00000000..c13b270f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/do-1/ast.snap @@ -0,0 +1,133 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/do-1 +--- +nodes: + stmts: + - - Do: + do_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 3 + line: 2 + character: 1 + end_position: + bytes: 4 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 4 + line: 2 + character: 2 + end_position: + bytes: 8 + line: 2 + character: 6 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 8 + line: 2 + character: 6 + end_position: + bytes: 9 + line: 2 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 9 + line: 2 + character: 7 + end_position: + bytes: 10 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: [] + - ~ + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 2 + character: 8 + end_position: + bytes: 10 + line: 2 + character: 8 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/do-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/do-1/ast_to_string.snap new file mode 100644 index 00000000..6ad223b2 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/do-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/do-1 +--- +"do\n\tcall()end" + diff --git a/full-moon/tests/cases/fail/parser/do-1/error.snap b/full-moon/tests/cases/fail/parser/do-1/error.snap deleted file mode 100644 index 178cd106..00000000 --- a/full-moon/tests/cases/fail/parser/do-1/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/do-1 - ---- -UnexpectedToken: - token: - start_position: - bytes: 10 - line: 2 - character: 8 - end_position: - bytes: 10 - line: 2 - character: 8 - token_type: - type: Eof - additional: "expected 'end'" - diff --git a/full-moon/tests/cases/fail/parser/do-1/error_display.snap b/full-moon/tests/cases/fail/parser/do-1/error_display.snap new file mode 100644 index 00000000..25649313 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/do-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/do-1 +--- +error[ast]: expected `end` to close do block + ┌─ source.lua:2:2 + │ +2 │ call() + │ ^^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/do-1/errors.snap b/full-moon/tests/cases/fail/parser/do-1/errors.snap new file mode 100644 index 00000000..289afb58 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/do-1/errors.snap @@ -0,0 +1,26 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/do-1 +--- +- AstError: + token: + start_position: + bytes: 10 + line: 2 + character: 8 + end_position: + bytes: 10 + line: 2 + character: 8 + token_type: + type: Eof + additional: "expected `end` to close do block" + range: + - bytes: 4 + line: 2 + character: 2 + - bytes: 10 + line: 2 + character: 8 + diff --git a/full-moon/tests/cases/fail/parser/do-2/ast.snap b/full-moon/tests/cases/fail/parser/do-2/ast.snap new file mode 100644 index 00000000..73409e15 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/do-2/ast.snap @@ -0,0 +1,68 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/do-2 +--- +nodes: + stmts: + - - Do: + do_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Whitespace + characters: " " + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/do-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/do-2/ast_to_string.snap new file mode 100644 index 00000000..488764e3 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/do-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/do-2 +--- +do end + diff --git a/full-moon/tests/cases/fail/parser/do-2/error.snap b/full-moon/tests/cases/fail/parser/do-2/error.snap deleted file mode 100644 index 532b0c0f..00000000 --- a/full-moon/tests/cases/fail/parser/do-2/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/do-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 3 - line: 1 - character: 4 - end_position: - bytes: 8 - line: 1 - character: 9 - token_type: - type: Symbol - symbol: until - additional: "expected 'end'" - diff --git a/full-moon/tests/cases/fail/parser/do-2/error_display.snap b/full-moon/tests/cases/fail/parser/do-2/error_display.snap new file mode 100644 index 00000000..cc5ae9ca --- /dev/null +++ b/full-moon/tests/cases/fail/parser/do-2/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/do-2 +--- +error[ast]: expected `end` to close do block + ┌─ source.lua:1:1 + │ +1 │ do until end + │ ^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:4 + │ +1 │ do until end + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/do-2/errors.snap b/full-moon/tests/cases/fail/parser/do-2/errors.snap new file mode 100644 index 00000000..e8441877 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/do-2/errors.snap @@ -0,0 +1,41 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/do-2 +--- +- AstError: + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: until + additional: "expected `end` to close do block" + range: + - bytes: 0 + line: 1 + character: 1 + - bytes: 2 + line: 1 + character: 3 +- AstError: + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: until + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/function-1/error.snap b/full-moon/tests/cases/fail/parser/function-1/ast.snap similarity index 71% rename from full-moon/tests/cases/fail/parser/function-1/error.snap rename to full-moon/tests/cases/fail/parser/function-1/ast.snap index 85a6e601..de634353 100644 --- a/full-moon/tests/cases/fail/parser/function-1/error.snap +++ b/full-moon/tests/cases/fail/parser/function-1/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/function-1 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 8 @@ -16,5 +19,5 @@ UnexpectedToken: character: 9 token_type: type: Eof - additional: expected function name + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/function-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/function-1/ast_to_string.snap new file mode 100644 index 00000000..01ebf9c8 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/function-1 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/function-1/error_display.snap b/full-moon/tests/cases/fail/parser/function-1/error_display.snap new file mode 100644 index 00000000..3d606636 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/function-1 +--- +error[ast]: expected function name + ┌─ source.lua:1:9 + │ +1 │ function + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/function-1/errors.snap b/full-moon/tests/cases/fail/parser/function-1/errors.snap new file mode 100644 index 00000000..7f753354 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-1/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/function-1 +--- +- AstError: + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Eof + additional: expected function name + diff --git a/full-moon/tests/cases/fail/parser/function-2/error.snap b/full-moon/tests/cases/fail/parser/function-2/ast.snap similarity index 58% rename from full-moon/tests/cases/fail/parser/function-2/error.snap rename to full-moon/tests/cases/fail/parser/function-2/ast.snap index 550ebb04..cde02936 100644 --- a/full-moon/tests/cases/fail/parser/function-2/error.snap +++ b/full-moon/tests/cases/fail/parser/function-2/ast.snap @@ -1,21 +1,23 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/function-2 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: - bytes: 9 + bytes: 12 line: 1 - character: 10 + character: 13 end_position: bytes: 12 line: 1 character: 13 token_type: - type: Symbol - symbol: end - additional: expected function name + type: Eof + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/function-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/function-2/ast_to_string.snap new file mode 100644 index 00000000..55823ba0 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/function-2 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/function-2/error_display.snap b/full-moon/tests/cases/fail/parser/function-2/error_display.snap new file mode 100644 index 00000000..827de55e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-2/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/function-2 +--- +error[ast]: expected function name + ┌─ source.lua:1:10 + │ +1 │ function end + │ ^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:10 + │ +1 │ function end + │ ^^^ + + diff --git a/full-moon/tests/cases/fail/parser/function-2/errors.snap b/full-moon/tests/cases/fail/parser/function-2/errors.snap new file mode 100644 index 00000000..28aa6419 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-2/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/function-2 +--- +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: end + additional: expected function name +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: end + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/function-3/ast.snap b/full-moon/tests/cases/fail/parser/function-3/ast.snap new file mode 100644 index 00000000..7f93d136 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-3/ast.snap @@ -0,0 +1,23 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/function-3 +--- +nodes: + stmts: [] +eof: + leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/function-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/function-3/ast_to_string.snap new file mode 100644 index 00000000..4ea79048 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/function-3 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/function-3/error.snap b/full-moon/tests/cases/fail/parser/function-3/error.snap deleted file mode 100644 index d81d8073..00000000 --- a/full-moon/tests/cases/fail/parser/function-3/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/function-3 - ---- -UnexpectedToken: - token: - start_position: - bytes: 8 - line: 1 - character: 9 - end_position: - bytes: 9 - line: 1 - character: 10 - token_type: - type: Symbol - symbol: ( - additional: expected function name - diff --git a/full-moon/tests/cases/fail/parser/function-3/error_display.snap b/full-moon/tests/cases/fail/parser/function-3/error_display.snap new file mode 100644 index 00000000..226d16c4 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-3/error_display.snap @@ -0,0 +1,25 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/function-3 +--- +error[ast]: expected function name + ┌─ source.lua:1:9 + │ +1 │ function() end + │ ^ + +error[ast]: expected an expression after `(` + ┌─ source.lua:1:9 + │ +1 │ function() end + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:10 + │ +1 │ function() end + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/function-3/errors.snap b/full-moon/tests/cases/fail/parser/function-3/errors.snap new file mode 100644 index 00000000..b7209132 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-3/errors.snap @@ -0,0 +1,48 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/function-3 +--- +- AstError: + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: ( + additional: expected function name +- AstError: + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: ( + additional: "expected an expression after `(`" +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: ) + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/function-4/ast.snap b/full-moon/tests/cases/fail/parser/function-4/ast.snap new file mode 100644 index 00000000..3d453548 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-4/ast.snap @@ -0,0 +1,120 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/function-4 +--- +nodes: + stmts: + - - FunctionDeclaration: + function_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: function + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + name: + names: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Identifier + identifier: x + trailing_trivia: [] + colon_name: ~ + body: + parameters_parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + parameters: + pairs: [] + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/function-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/function-4/ast_to_string.snap new file mode 100644 index 00000000..58843c60 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/function-4 +--- +function x()end + diff --git a/full-moon/tests/cases/fail/parser/function-4/error.snap b/full-moon/tests/cases/fail/parser/function-4/error.snap deleted file mode 100644 index e0048a2a..00000000 --- a/full-moon/tests/cases/fail/parser/function-4/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/function-4 - ---- -UnexpectedToken: - token: - start_position: - bytes: 11 - line: 1 - character: 12 - end_position: - bytes: 11 - line: 1 - character: 12 - token_type: - type: Eof - additional: "expected ')'" - diff --git a/full-moon/tests/cases/fail/parser/function-4/error_display.snap b/full-moon/tests/cases/fail/parser/function-4/error_display.snap new file mode 100644 index 00000000..2eba71d8 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-4/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/function-4 +--- +error[ast]: expected a parameter name or `)` + ┌─ source.lua:1:12 + │ +1 │ function x( + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/function-4/errors.snap b/full-moon/tests/cases/fail/parser/function-4/errors.snap new file mode 100644 index 00000000..a7b350d2 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-4/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/function-4 +--- +- AstError: + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Eof + additional: "expected a parameter name or `)`" + diff --git a/full-moon/tests/cases/fail/parser/generic-for-3/error.snap b/full-moon/tests/cases/fail/parser/function-5/ast.snap similarity index 57% rename from full-moon/tests/cases/fail/parser/generic-for-3/error.snap rename to full-moon/tests/cases/fail/parser/function-5/ast.snap index d521823b..87d5c55d 100644 --- a/full-moon/tests/cases/fail/parser/generic-for-3/error.snap +++ b/full-moon/tests/cases/fail/parser/function-5/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/generic-for-3 - +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/function-5 --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 20 @@ -16,5 +19,5 @@ UnexpectedToken: character: 21 token_type: type: Eof - additional: "expected 'end'" + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/function-5/ast_to_string.snap b/full-moon/tests/cases/fail/parser/function-5/ast_to_string.snap new file mode 100644 index 00000000..7caa522c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-5/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/function-5 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/function-5/error.snap b/full-moon/tests/cases/fail/parser/function-5/error.snap deleted file mode 100644 index 2d8540d9..00000000 --- a/full-moon/tests/cases/fail/parser/function-5/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/function-5 - ---- -UnexpectedToken: - token: - start_position: - bytes: 9 - line: 1 - character: 10 - end_position: - bytes: 14 - line: 1 - character: 15 - token_type: - type: Symbol - symbol: local - additional: expected function name - diff --git a/full-moon/tests/cases/fail/parser/function-5/error_display.snap b/full-moon/tests/cases/fail/parser/function-5/error_display.snap new file mode 100644 index 00000000..cec5bb6b --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-5/error_display.snap @@ -0,0 +1,31 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/function-5 +--- +error[ast]: expected function name + ┌─ source.lua:1:10 + │ +1 │ function local() end + │ ^^^^^ + +error[ast]: expected either a variable name or `function` + ┌─ source.lua:1:15 + │ +1 │ function local() end + │ ^ + +error[ast]: expected an expression after `(` + ┌─ source.lua:1:15 + │ +1 │ function local() end + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:16 + │ +1 │ function local() end + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/function-5/errors.snap b/full-moon/tests/cases/fail/parser/function-5/errors.snap new file mode 100644 index 00000000..34442324 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-5/errors.snap @@ -0,0 +1,62 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/function-5 +--- +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: local + additional: expected function name +- AstError: + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: ( + additional: "expected either a variable name or `function`" +- AstError: + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: ( + additional: "expected an expression after `(`" +- AstError: + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Symbol + symbol: ) + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/function-6/ast.snap b/full-moon/tests/cases/fail/parser/function-6/ast.snap new file mode 100644 index 00000000..bc169761 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-6/ast.snap @@ -0,0 +1,120 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/function-6 +--- +nodes: + stmts: + - - FunctionDeclaration: + function_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: function + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + name: + names: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Identifier + identifier: x + trailing_trivia: [] + colon_name: ~ + body: + parameters_parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + parameters: + pairs: [] + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/function-6/ast_to_string.snap b/full-moon/tests/cases/fail/parser/function-6/ast_to_string.snap new file mode 100644 index 00000000..5f73dce7 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-6/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/function-6 +--- +function x()end + diff --git a/full-moon/tests/cases/fail/parser/function-6/error.snap b/full-moon/tests/cases/fail/parser/function-6/error.snap deleted file mode 100644 index 07473159..00000000 --- a/full-moon/tests/cases/fail/parser/function-6/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/function-6 - ---- -UnexpectedToken: - token: - start_position: - bytes: 12 - line: 1 - character: 13 - end_position: - bytes: 12 - line: 1 - character: 13 - token_type: - type: Eof - additional: "expected 'end'" - diff --git a/full-moon/tests/cases/fail/parser/function-6/error_display.snap b/full-moon/tests/cases/fail/parser/function-6/error_display.snap new file mode 100644 index 00000000..2153c867 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-6/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/function-6 +--- +error[ast]: expected `end` to close function body block + ┌─ source.lua:1:12 + │ +1 │ function x() + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/function-6/errors.snap b/full-moon/tests/cases/fail/parser/function-6/errors.snap new file mode 100644 index 00000000..b9ee670c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-6/errors.snap @@ -0,0 +1,26 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/function-6 +--- +- AstError: + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Eof + additional: "expected `end` to close function body block" + range: + - bytes: 11 + line: 1 + character: 12 + - bytes: 12 + line: 1 + character: 13 + diff --git a/full-moon/tests/cases/fail/parser/function-7/ast.snap b/full-moon/tests/cases/fail/parser/function-7/ast.snap new file mode 100644 index 00000000..fc5e2f60 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-7/ast.snap @@ -0,0 +1,136 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/function-7 +--- +nodes: + stmts: + - - FunctionDeclaration: + function_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: function + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + name: + names: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Identifier + identifier: x + trailing_trivia: [] + colon_name: ~ + body: + parameters_parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + parameters: + pairs: + - End: + Ellipse: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: "..." + trailing_trivia: [] + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 22 + line: 2 + character: 4 + end_position: + bytes: 22 + line: 2 + character: 4 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/function-7/ast_to_string.snap b/full-moon/tests/cases/fail/parser/function-7/ast_to_string.snap new file mode 100644 index 00000000..d739adf6 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-7/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/function-7 +--- +function x(...)end + diff --git a/full-moon/tests/cases/fail/parser/function-7/error.snap b/full-moon/tests/cases/fail/parser/function-7/error.snap deleted file mode 100644 index 48b22f2e..00000000 --- a/full-moon/tests/cases/fail/parser/function-7/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/function-7 - ---- -UnexpectedToken: - token: - start_position: - bytes: 14 - line: 1 - character: 15 - end_position: - bytes: 15 - line: 1 - character: 16 - token_type: - type: Symbol - symbol: "," - additional: "expected ')'" - diff --git a/full-moon/tests/cases/fail/parser/function-7/error_display.snap b/full-moon/tests/cases/fail/parser/function-7/error_display.snap new file mode 100644 index 00000000..67de43c3 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-7/error_display.snap @@ -0,0 +1,31 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/function-7 +--- +error[ast]: expected a `)` + ┌─ source.lua:1:15 + │ +1 │ function x(..., a) + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:15 + │ +1 │ function x(..., a) + │ ^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:1:18 + │ +1 │ function x(..., a) + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:18 + │ +1 │ function x(..., a) + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/function-7/errors.snap b/full-moon/tests/cases/fail/parser/function-7/errors.snap new file mode 100644 index 00000000..55df5d9f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-7/errors.snap @@ -0,0 +1,62 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/function-7 +--- +- AstError: + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: "," + additional: "expected a `)`" +- AstError: + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: "," + additional: "unexpected token, this needs to be a statement" +- AstError: + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: ) + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: ) + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/call-3/error.snap b/full-moon/tests/cases/fail/parser/function-8/ast.snap similarity index 57% rename from full-moon/tests/cases/fail/parser/call-3/error.snap rename to full-moon/tests/cases/fail/parser/function-8/ast.snap index 5135bec8..afa57b90 100644 --- a/full-moon/tests/cases/fail/parser/call-3/error.snap +++ b/full-moon/tests/cases/fail/parser/function-8/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/call-3 - +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/function-8 --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 21 @@ -16,5 +19,5 @@ UnexpectedToken: character: 22 token_type: type: Eof - additional: "expected ')'" + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/function-8/ast_to_string.snap b/full-moon/tests/cases/fail/parser/function-8/ast_to_string.snap new file mode 100644 index 00000000..b3f1f051 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-8/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/function-8 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/function-8/error.snap b/full-moon/tests/cases/fail/parser/function-8/error.snap deleted file mode 100644 index e31b6b62..00000000 --- a/full-moon/tests/cases/fail/parser/function-8/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/function-8 - ---- -UnexpectedToken: - token: - start_position: - bytes: 14 - line: 1 - character: 15 - end_position: - bytes: 15 - line: 1 - character: 16 - token_type: - type: Number - text: "3" - additional: expected method name - diff --git a/full-moon/tests/cases/fail/parser/function-8/error_display.snap b/full-moon/tests/cases/fail/parser/function-8/error_display.snap new file mode 100644 index 00000000..bc83b3fe --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-8/error_display.snap @@ -0,0 +1,31 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/function-8 +--- +error[ast]: expected name after `:` + ┌─ source.lua:1:15 + │ +1 │ function name:3() end + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:15 + │ +1 │ function name:3() end + │ ^ + +error[ast]: expected an expression after `(` + ┌─ source.lua:1:16 + │ +1 │ function name:3() end + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:17 + │ +1 │ function name:3() end + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/function-8/errors.snap b/full-moon/tests/cases/fail/parser/function-8/errors.snap new file mode 100644 index 00000000..11c643fe --- /dev/null +++ b/full-moon/tests/cases/fail/parser/function-8/errors.snap @@ -0,0 +1,62 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/function-8 +--- +- AstError: + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Number + text: "3" + additional: "expected name after `:`" +- AstError: + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Number + text: "3" + additional: "unexpected token, this needs to be a statement" +- AstError: + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Symbol + symbol: ( + additional: "expected an expression after `(`" +- AstError: + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: ) + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/generic-for-1/error.snap b/full-moon/tests/cases/fail/parser/generic-for-1/ast.snap similarity index 72% rename from full-moon/tests/cases/fail/parser/generic-for-1/error.snap rename to full-moon/tests/cases/fail/parser/generic-for-1/ast.snap index 13038403..a53668a6 100644 --- a/full-moon/tests/cases/fail/parser/generic-for-1/error.snap +++ b/full-moon/tests/cases/fail/parser/generic-for-1/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/generic-for-1 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 8 @@ -16,5 +19,5 @@ UnexpectedToken: character: 9 token_type: type: Eof - additional: expected expression + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/generic-for-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/generic-for-1/ast_to_string.snap new file mode 100644 index 00000000..bcac1403 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/generic-for-1 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/generic-for-1/error_display.snap b/full-moon/tests/cases/fail/parser/generic-for-1/error_display.snap new file mode 100644 index 00000000..27048f70 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/generic-for-1 +--- +error[ast]: expected expressions after `in` + ┌─ source.lua:1:7 + │ +1 │ for x in + │ ^^ + + diff --git a/full-moon/tests/cases/fail/parser/generic-for-1/errors.snap b/full-moon/tests/cases/fail/parser/generic-for-1/errors.snap new file mode 100644 index 00000000..99949dca --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-1/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/generic-for-1 +--- +- AstError: + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: in + additional: "expected expressions after `in`" + diff --git a/full-moon/tests/cases/fail/parser/generic-for-2/ast.snap b/full-moon/tests/cases/fail/parser/generic-for-2/ast.snap new file mode 100644 index 00000000..578e0015 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-2/ast.snap @@ -0,0 +1,210 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/generic-for-2 +--- +nodes: + stmts: + - - GenericFor: + for_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: for + trailing_trivia: + - start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Whitespace + characters: " " + names: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + in_token: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: in + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + FunctionCall: + prefix: + Name: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Identifier + identifier: pairs + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: + - End: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Identifier + identifier: y + trailing_trivia: [] + do_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: do + trailing_trivia: [] + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/generic-for-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/generic-for-2/ast_to_string.snap new file mode 100644 index 00000000..35a74e7a --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/generic-for-2 +--- +for x in pairs(y)doend + diff --git a/full-moon/tests/cases/fail/parser/generic-for-2/error_display.snap b/full-moon/tests/cases/fail/parser/generic-for-2/error_display.snap new file mode 100644 index 00000000..67fae56e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-2/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/generic-for-2 +--- +error[ast]: expected `do` after expression list + ┌─ source.lua:1:18 + │ +1 │ for x in pairs(y) + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/generic-for-2/errors.snap b/full-moon/tests/cases/fail/parser/generic-for-2/errors.snap new file mode 100644 index 00000000..8f834d21 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-2/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/generic-for-2 +--- +- AstError: + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Eof + additional: "expected `do` after expression list" + diff --git a/full-moon/tests/cases/fail/parser/generic-for-3/ast.snap b/full-moon/tests/cases/fail/parser/generic-for-3/ast.snap new file mode 100644 index 00000000..7972c504 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-3/ast.snap @@ -0,0 +1,221 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/generic-for-3 +--- +nodes: + stmts: + - - GenericFor: + for_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: for + trailing_trivia: + - start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Whitespace + characters: " " + names: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + in_token: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: in + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + FunctionCall: + prefix: + Name: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Identifier + identifier: pairs + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Whitespace + characters: " " + arguments: + pairs: + - End: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Identifier + identifier: y + trailing_trivia: [] + do_token: + leading_trivia: [] + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 20 + line: 1 + character: 21 + token_type: + type: Symbol + symbol: do + trailing_trivia: [] + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 20 + line: 1 + character: 21 + end_position: + bytes: 20 + line: 1 + character: 21 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/generic-for-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/generic-for-3/ast_to_string.snap new file mode 100644 index 00000000..9fefea03 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/generic-for-3 +--- +for x in pairs(y) doend + diff --git a/full-moon/tests/cases/fail/parser/generic-for-3/error_display.snap b/full-moon/tests/cases/fail/parser/generic-for-3/error_display.snap new file mode 100644 index 00000000..2e9cf822 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-3/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/generic-for-3 +--- +error[ast]: expected `end` to close for loop block + ┌─ source.lua:1:19 + │ +1 │ for x in pairs(y) do + │ ^^ + + diff --git a/full-moon/tests/cases/fail/parser/generic-for-3/errors.snap b/full-moon/tests/cases/fail/parser/generic-for-3/errors.snap new file mode 100644 index 00000000..a7760826 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-3/errors.snap @@ -0,0 +1,26 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/generic-for-3 +--- +- AstError: + token: + start_position: + bytes: 20 + line: 1 + character: 21 + end_position: + bytes: 20 + line: 1 + character: 21 + token_type: + type: Eof + additional: "expected `end` to close for loop block" + range: + - bytes: 18 + line: 1 + character: 19 + - bytes: 20 + line: 1 + character: 21 + diff --git a/full-moon/tests/cases/fail/parser/generic-for-4/ast.snap b/full-moon/tests/cases/fail/parser/generic-for-4/ast.snap new file mode 100644 index 00000000..9ebd07a6 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-4/ast.snap @@ -0,0 +1,150 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/generic-for-4 +--- +nodes: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: [] + token: + start_position: + bytes: 20 + line: 1 + character: 21 + end_position: + bytes: 25 + line: 1 + character: 26 + token_type: + type: Identifier + identifier: pairs + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 30 + line: 1 + character: 31 + end_position: + bytes: 31 + line: 1 + character: 32 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 31 + line: 1 + character: 32 + end_position: + bytes: 32 + line: 1 + character: 33 + token_type: + type: Whitespace + characters: " " + arguments: + pairs: + - End: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 26 + line: 1 + character: 27 + end_position: + bytes: 30 + line: 1 + character: 31 + token_type: + type: Identifier + identifier: list + trailing_trivia: [] + - ~ + - - Do: + do_token: + leading_trivia: [] + token: + start_position: + bytes: 32 + line: 1 + character: 33 + end_position: + bytes: 34 + line: 1 + character: 35 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 34 + line: 1 + character: 35 + end_position: + bytes: 35 + line: 1 + character: 36 + token_type: + type: Whitespace + characters: " " + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 35 + line: 1 + character: 36 + end_position: + bytes: 38 + line: 1 + character: 39 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 38 + line: 1 + character: 39 + end_position: + bytes: 38 + line: 1 + character: 39 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/generic-for-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/generic-for-4/ast_to_string.snap new file mode 100644 index 00000000..9a16fc0f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/generic-for-4 +--- +pairs(list) do end + diff --git a/full-moon/tests/cases/fail/parser/generic-for-4/error.snap b/full-moon/tests/cases/fail/parser/generic-for-4/error.snap deleted file mode 100644 index 510325a3..00000000 --- a/full-moon/tests/cases/fail/parser/generic-for-4/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/generic-for-4 - ---- -UnexpectedToken: - token: - start_position: - bytes: 9 - line: 1 - character: 10 - end_position: - bytes: 10 - line: 1 - character: 11 - token_type: - type: Symbol - symbol: "," - additional: "expected 'in'" - diff --git a/full-moon/tests/cases/fail/parser/generic-for-4/error_display.snap b/full-moon/tests/cases/fail/parser/generic-for-4/error_display.snap new file mode 100644 index 00000000..22df6589 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-4/error_display.snap @@ -0,0 +1,31 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/generic-for-4 +--- +error[ast]: trailing commas are not allowed + ┌─ source.lua:1:10 + │ +1 │ for index, local in pairs(list) do end + │ ^ + +error[ast]: expected `in` after name list + ┌─ source.lua:1:12 + │ +1 │ for index, local in pairs(list) do end + │ ^^^^^ + +error[ast]: expected either a variable name or `function` + ┌─ source.lua:1:18 + │ +1 │ for index, local in pairs(list) do end + │ ^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:18 + │ +1 │ for index, local in pairs(list) do end + │ ^^ + + diff --git a/full-moon/tests/cases/fail/parser/generic-for-4/errors.snap b/full-moon/tests/cases/fail/parser/generic-for-4/errors.snap new file mode 100644 index 00000000..c2e5d95d --- /dev/null +++ b/full-moon/tests/cases/fail/parser/generic-for-4/errors.snap @@ -0,0 +1,62 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/generic-for-4 +--- +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "," + additional: trailing commas are not allowed +- AstError: + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Symbol + symbol: local + additional: "expected `in` after name list" +- AstError: + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Symbol + symbol: in + additional: "expected either a variable name or `function`" +- AstError: + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Symbol + symbol: in + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/if-1/ast.snap b/full-moon/tests/cases/fail/parser/if-1/ast.snap new file mode 100644 index 00000000..175f404d --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-1/ast.snap @@ -0,0 +1,114 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/if-1 +--- +nodes: + stmts: + - - If: + if_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: if + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Whitespace + characters: " " + condition: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + then_token: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: then + trailing_trivia: [] + block: + stmts: [] + else_if: ~ + else_token: ~ + else: ~ + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/if-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/if-1/ast_to_string.snap new file mode 100644 index 00000000..2f837453 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/if-1 +--- +if x thenend + diff --git a/full-moon/tests/cases/fail/parser/if-1/error_display.snap b/full-moon/tests/cases/fail/parser/if-1/error_display.snap new file mode 100644 index 00000000..fcb0be21 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/if-1 +--- +error[ast]: expected `end` to conclude `if` + ┌─ source.lua:1:10 + │ +1 │ if x then + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/if-1/errors.snap b/full-moon/tests/cases/fail/parser/if-1/errors.snap new file mode 100644 index 00000000..19e156e5 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-1/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/if-1 +--- +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Eof + additional: "expected `end` to conclude `if`" + diff --git a/full-moon/tests/cases/fail/parser/if-2/ast.snap b/full-moon/tests/cases/fail/parser/if-2/ast.snap new file mode 100644 index 00000000..c9be7781 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-2/ast.snap @@ -0,0 +1,216 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/if-2 +--- +nodes: + stmts: + - - If: + if_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: if + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Whitespace + characters: " " + condition: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + then_token: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: then + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: [] + else_if: ~ + else_token: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 2 + character: 1 + end_position: + bytes: 14 + line: 2 + character: 5 + token_type: + type: Symbol + symbol: else + trailing_trivia: + - start_position: + bytes: 14 + line: 2 + character: 5 + end_position: + bytes: 15 + line: 2 + character: 5 + token_type: + type: Whitespace + characters: "\n" + else: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 15 + line: 3 + character: 1 + end_position: + bytes: 16 + line: 3 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 16 + line: 3 + character: 2 + end_position: + bytes: 20 + line: 3 + character: 6 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 20 + line: 3 + character: 6 + end_position: + bytes: 21 + line: 3 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 21 + line: 3 + character: 7 + end_position: + bytes: 22 + line: 3 + character: 8 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: [] + - ~ + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 22 + line: 3 + character: 8 + end_position: + bytes: 22 + line: 3 + character: 8 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/if-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/if-2/ast_to_string.snap new file mode 100644 index 00000000..28c67583 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/if-2 +--- +"if x then\nelse\n\tcall()end" + diff --git a/full-moon/tests/cases/fail/parser/if-2/error.snap b/full-moon/tests/cases/fail/parser/if-2/error.snap deleted file mode 100644 index ecb24af6..00000000 --- a/full-moon/tests/cases/fail/parser/if-2/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/if-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 22 - line: 3 - character: 8 - end_position: - bytes: 22 - line: 3 - character: 8 - token_type: - type: Eof - additional: "expected 'end'" - diff --git a/full-moon/tests/cases/fail/parser/if-2/error_display.snap b/full-moon/tests/cases/fail/parser/if-2/error_display.snap new file mode 100644 index 00000000..c69c5395 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-2/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/if-2 +--- +error[ast]: expected `end` to conclude `if` + ┌─ source.lua:3:8 + │ +3 │ call() + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/if-2/errors.snap b/full-moon/tests/cases/fail/parser/if-2/errors.snap new file mode 100644 index 00000000..e06a8961 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-2/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/if-2 +--- +- AstError: + token: + start_position: + bytes: 22 + line: 3 + character: 8 + end_position: + bytes: 22 + line: 3 + character: 8 + token_type: + type: Eof + additional: "expected `end` to conclude `if`" + diff --git a/full-moon/tests/cases/fail/parser/generic-for-2/error.snap b/full-moon/tests/cases/fail/parser/if-3/ast.snap similarity index 58% rename from full-moon/tests/cases/fail/parser/generic-for-2/error.snap rename to full-moon/tests/cases/fail/parser/if-3/ast.snap index 45836d6d..1ec7da5e 100644 --- a/full-moon/tests/cases/fail/parser/generic-for-2/error.snap +++ b/full-moon/tests/cases/fail/parser/if-3/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/generic-for-2 - +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/if-3 --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 17 @@ -16,5 +19,5 @@ UnexpectedToken: character: 18 token_type: type: Eof - additional: "expected 'do'" + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/if-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/if-3/ast_to_string.snap new file mode 100644 index 00000000..7cee6be9 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/if-3 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/if-3/error.snap b/full-moon/tests/cases/fail/parser/if-3/error.snap deleted file mode 100644 index 1fdc21ae..00000000 --- a/full-moon/tests/cases/fail/parser/if-3/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/if-3 - ---- -UnexpectedToken: - token: - start_position: - bytes: 3 - line: 1 - character: 4 - end_position: - bytes: 8 - line: 1 - character: 9 - token_type: - type: Symbol - symbol: local - additional: expected condition - diff --git a/full-moon/tests/cases/fail/parser/if-3/error_display.snap b/full-moon/tests/cases/fail/parser/if-3/error_display.snap new file mode 100644 index 00000000..b1b5b87c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-3/error_display.snap @@ -0,0 +1,25 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/if-3 +--- +error[ast]: expected condition after `if` + ┌─ source.lua:1:1 + │ +1 │ if local then end + │ ^^ + +error[ast]: expected either a variable name or `function` + ┌─ source.lua:1:10 + │ +1 │ if local then end + │ ^^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:10 + │ +1 │ if local then end + │ ^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/if-3/errors.snap b/full-moon/tests/cases/fail/parser/if-3/errors.snap new file mode 100644 index 00000000..ea1d4d90 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-3/errors.snap @@ -0,0 +1,48 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/if-3 +--- +- AstError: + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: if + additional: "expected condition after `if`" +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: then + additional: "expected either a variable name or `function`" +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: then + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/if-4/ast.snap b/full-moon/tests/cases/fail/parser/if-4/ast.snap new file mode 100644 index 00000000..482fc269 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-4/ast.snap @@ -0,0 +1,196 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/if-4 +--- +nodes: + stmts: + - - If: + if_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: if + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Whitespace + characters: " " + condition: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + then_token: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: then + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: [] + else_if: + - else_if_token: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 2 + character: 1 + end_position: + bytes: 16 + line: 2 + character: 7 + token_type: + type: Symbol + symbol: elseif + trailing_trivia: + - start_position: + bytes: 16 + line: 2 + character: 7 + end_position: + bytes: 17 + line: 2 + character: 8 + token_type: + type: Whitespace + characters: " " + condition: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 17 + line: 2 + character: 8 + end_position: + bytes: 18 + line: 2 + character: 9 + token_type: + type: Identifier + identifier: y + trailing_trivia: + - start_position: + bytes: 18 + line: 2 + character: 9 + end_position: + bytes: 19 + line: 2 + character: 10 + token_type: + type: Whitespace + characters: " " + then_token: + leading_trivia: [] + token: + start_position: + bytes: 19 + line: 2 + character: 10 + end_position: + bytes: 23 + line: 2 + character: 14 + token_type: + type: Symbol + symbol: then + trailing_trivia: [] + block: + stmts: [] + else_token: ~ + else: ~ + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 23 + line: 2 + character: 14 + end_position: + bytes: 23 + line: 2 + character: 14 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/if-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/if-4/ast_to_string.snap new file mode 100644 index 00000000..0206f0b3 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/if-4 +--- +"if x then\nelseif y thenend" + diff --git a/full-moon/tests/cases/fail/parser/if-4/error.snap b/full-moon/tests/cases/fail/parser/if-4/error.snap deleted file mode 100644 index 4cc99058..00000000 --- a/full-moon/tests/cases/fail/parser/if-4/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/if-4 - ---- -UnexpectedToken: - token: - start_position: - bytes: 23 - line: 2 - character: 14 - end_position: - bytes: 23 - line: 2 - character: 14 - token_type: - type: Eof - additional: "expected 'end'" - diff --git a/full-moon/tests/cases/fail/parser/if-4/error_display.snap b/full-moon/tests/cases/fail/parser/if-4/error_display.snap new file mode 100644 index 00000000..a4493dd0 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-4/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/if-4 +--- +error[ast]: expected `end` to conclude `if` + ┌─ source.lua:2:14 + │ +2 │ elseif y then + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/if-4/errors.snap b/full-moon/tests/cases/fail/parser/if-4/errors.snap new file mode 100644 index 00000000..4e4d9763 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-4/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/if-4 +--- +- AstError: + token: + start_position: + bytes: 23 + line: 2 + character: 14 + end_position: + bytes: 23 + line: 2 + character: 14 + token_type: + type: Eof + additional: "expected `end` to conclude `if`" + diff --git a/full-moon/tests/cases/fail/parser/if-5/ast.snap b/full-moon/tests/cases/fail/parser/if-5/ast.snap new file mode 100644 index 00000000..2a9e9111 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-5/ast.snap @@ -0,0 +1,379 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/if-5 +--- +nodes: + stmts: + - - If: + if_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: if + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Whitespace + characters: " " + condition: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + then_token: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: then + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 10 + line: 2 + character: 1 + end_position: + bytes: 11 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 11 + line: 2 + character: 2 + end_position: + bytes: 16 + line: 2 + character: 7 + token_type: + type: Identifier + identifier: call1 + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 16 + line: 2 + character: 7 + end_position: + bytes: 17 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 17 + line: 2 + character: 8 + end_position: + bytes: 18 + line: 2 + character: 9 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 18 + line: 2 + character: 9 + end_position: + bytes: 19 + line: 2 + character: 9 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: [] + - ~ + else_if: ~ + else_token: + leading_trivia: [] + token: + start_position: + bytes: 19 + line: 3 + character: 1 + end_position: + bytes: 23 + line: 3 + character: 5 + token_type: + type: Symbol + symbol: else + trailing_trivia: + - start_position: + bytes: 23 + line: 3 + character: 5 + end_position: + bytes: 24 + line: 3 + character: 5 + token_type: + type: Whitespace + characters: "\n" + else: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 24 + line: 4 + character: 1 + end_position: + bytes: 25 + line: 4 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 25 + line: 4 + character: 2 + end_position: + bytes: 30 + line: 4 + character: 7 + token_type: + type: Identifier + identifier: call2 + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 30 + line: 4 + character: 7 + end_position: + bytes: 31 + line: 4 + character: 8 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 31 + line: 4 + character: 8 + end_position: + bytes: 32 + line: 4 + character: 9 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 32 + line: 4 + character: 9 + end_position: + bytes: 33 + line: 4 + character: 9 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: [] + - ~ + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 47 + line: 6 + character: 1 + end_position: + bytes: 48 + line: 6 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 48 + line: 6 + character: 2 + end_position: + bytes: 53 + line: 6 + character: 7 + token_type: + type: Identifier + identifier: call3 + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 53 + line: 6 + character: 7 + end_position: + bytes: 54 + line: 6 + character: 8 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 54 + line: 6 + character: 8 + end_position: + bytes: 55 + line: 6 + character: 9 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 55 + line: 6 + character: 9 + end_position: + bytes: 56 + line: 6 + character: 9 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 59 + line: 7 + character: 4 + end_position: + bytes: 59 + line: 7 + character: 4 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/if-5/ast_to_string.snap b/full-moon/tests/cases/fail/parser/if-5/ast_to_string.snap new file mode 100644 index 00000000..4be1ad91 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-5/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/if-5 +--- +"if x then\n\tcall1()\nelse\n\tcall2()\nend\tcall3()\n" + diff --git a/full-moon/tests/cases/fail/parser/if-5/error.snap b/full-moon/tests/cases/fail/parser/if-5/error.snap deleted file mode 100644 index 6f7932e4..00000000 --- a/full-moon/tests/cases/fail/parser/if-5/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/if-5 - ---- -UnexpectedToken: - token: - start_position: - bytes: 33 - line: 5 - character: 1 - end_position: - bytes: 39 - line: 5 - character: 7 - token_type: - type: Symbol - symbol: elseif - additional: "expected 'end'" - diff --git a/full-moon/tests/cases/fail/parser/if-5/error_display.snap b/full-moon/tests/cases/fail/parser/if-5/error_display.snap new file mode 100644 index 00000000..c47c9ef3 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-5/error_display.snap @@ -0,0 +1,31 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/if-5 +--- +error[ast]: expected `end` to conclude `if` + ┌─ source.lua:5:1 + │ +5 │ elseif y then + │ ^^^^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:5:1 + │ +5 │ elseif y then + │ ^^^^^^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:5:10 + │ +5 │ elseif y then + │ ^^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:5:10 + │ +5 │ elseif y then + │ ^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/if-5/errors.snap b/full-moon/tests/cases/fail/parser/if-5/errors.snap new file mode 100644 index 00000000..9af48a5a --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-5/errors.snap @@ -0,0 +1,62 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/if-5 +--- +- AstError: + token: + start_position: + bytes: 33 + line: 5 + character: 1 + end_position: + bytes: 39 + line: 5 + character: 7 + token_type: + type: Symbol + symbol: elseif + additional: "expected `end` to conclude `if`" +- AstError: + token: + start_position: + bytes: 33 + line: 5 + character: 1 + end_position: + bytes: 39 + line: 5 + character: 7 + token_type: + type: Symbol + symbol: elseif + additional: "unexpected token, this needs to be a statement" +- AstError: + token: + start_position: + bytes: 42 + line: 5 + character: 10 + end_position: + bytes: 46 + line: 5 + character: 14 + token_type: + type: Symbol + symbol: then + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 42 + line: 5 + character: 10 + end_position: + bytes: 46 + line: 5 + character: 14 + token_type: + type: Symbol + symbol: then + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/if-6/ast.snap b/full-moon/tests/cases/fail/parser/if-6/ast.snap new file mode 100644 index 00000000..f632be91 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-6/ast.snap @@ -0,0 +1,227 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/if-6 +--- +nodes: + stmts: + - - If: + if_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: if + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Whitespace + characters: " " + condition: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + then_token: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: then + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: [] + else_if: ~ + else_token: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 2 + character: 1 + end_position: + bytes: 14 + line: 2 + character: 5 + token_type: + type: Symbol + symbol: else + trailing_trivia: + - start_position: + bytes: 14 + line: 2 + character: 5 + end_position: + bytes: 15 + line: 2 + character: 6 + token_type: + type: Whitespace + characters: " " + else: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 20 + line: 3 + character: 1 + end_position: + bytes: 21 + line: 3 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 21 + line: 3 + character: 2 + end_position: + bytes: 25 + line: 3 + character: 6 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 25 + line: 3 + character: 6 + end_position: + bytes: 26 + line: 3 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 26 + line: 3 + character: 7 + end_position: + bytes: 27 + line: 3 + character: 8 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 27 + line: 3 + character: 8 + end_position: + bytes: 28 + line: 3 + character: 8 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 31 + line: 4 + character: 4 + end_position: + bytes: 31 + line: 4 + character: 4 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/if-6/ast_to_string.snap b/full-moon/tests/cases/fail/parser/if-6/ast_to_string.snap new file mode 100644 index 00000000..92b0b3ac --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-6/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/if-6 +--- +"if x then\nelse end\tcall()\n" + diff --git a/full-moon/tests/cases/fail/parser/if-6/error.snap b/full-moon/tests/cases/fail/parser/if-6/error.snap deleted file mode 100644 index 216ba7ca..00000000 --- a/full-moon/tests/cases/fail/parser/if-6/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/if-6 - ---- -UnexpectedToken: - token: - start_position: - bytes: 15 - line: 2 - character: 6 - end_position: - bytes: 19 - line: 2 - character: 10 - token_type: - type: Symbol - symbol: then - additional: "expected 'end'" - diff --git a/full-moon/tests/cases/fail/parser/if-6/error_display.snap b/full-moon/tests/cases/fail/parser/if-6/error_display.snap new file mode 100644 index 00000000..c8f4e254 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-6/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/if-6 +--- +error[ast]: expected `end` to conclude `if` + ┌─ source.lua:2:6 + │ +2 │ else then + │ ^^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:6 + │ +2 │ else then + │ ^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/if-6/errors.snap b/full-moon/tests/cases/fail/parser/if-6/errors.snap new file mode 100644 index 00000000..25bf982a --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-6/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/if-6 +--- +- AstError: + token: + start_position: + bytes: 15 + line: 2 + character: 6 + end_position: + bytes: 19 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: then + additional: "expected `end` to conclude `if`" +- AstError: + token: + start_position: + bytes: 15 + line: 2 + character: 6 + end_position: + bytes: 19 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: then + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/if-7/ast.snap b/full-moon/tests/cases/fail/parser/if-7/ast.snap new file mode 100644 index 00000000..a8bee9d9 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-7/ast.snap @@ -0,0 +1,170 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/if-7 +--- +nodes: + stmts: + - - If: + if_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: if + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Whitespace + characters: " " + condition: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + then_token: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: then + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + block: + stmts: + - - Do: + do_token: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 13 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 13 + line: 2 + character: 1 + end_position: + bytes: 16 + line: 2 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ + else_if: ~ + else_token: ~ + else: ~ + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 2 + character: 4 + end_position: + bytes: 16 + line: 2 + character: 4 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/if-7/ast_to_string.snap b/full-moon/tests/cases/fail/parser/if-7/ast_to_string.snap new file mode 100644 index 00000000..3ab6efce --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-7/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/if-7 +--- +"if x then do\nendend" + diff --git a/full-moon/tests/cases/fail/parser/if-7/error.snap b/full-moon/tests/cases/fail/parser/if-7/error.snap deleted file mode 100644 index 7910b9c9..00000000 --- a/full-moon/tests/cases/fail/parser/if-7/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/if-7 - ---- -UnexpectedToken: - token: - start_position: - bytes: 16 - line: 2 - character: 4 - end_position: - bytes: 16 - line: 2 - character: 4 - token_type: - type: Eof - additional: "expected 'end'" - diff --git a/full-moon/tests/cases/fail/parser/if-7/error_display.snap b/full-moon/tests/cases/fail/parser/if-7/error_display.snap new file mode 100644 index 00000000..ee217fae --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-7/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/if-7 +--- +error[ast]: expected `end` to conclude `if` + ┌─ source.lua:2:4 + │ +2 │ end + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/if-7/errors.snap b/full-moon/tests/cases/fail/parser/if-7/errors.snap new file mode 100644 index 00000000..e3e0debd --- /dev/null +++ b/full-moon/tests/cases/fail/parser/if-7/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/if-7 +--- +- AstError: + token: + start_position: + bytes: 16 + line: 2 + character: 4 + end_position: + bytes: 16 + line: 2 + character: 4 + token_type: + type: Eof + additional: "expected `end` to conclude `if`" + diff --git a/full-moon/tests/cases/fail/parser/index-1/error.snap b/full-moon/tests/cases/fail/parser/index-1/ast.snap similarity index 71% rename from full-moon/tests/cases/fail/parser/index-1/error.snap rename to full-moon/tests/cases/fail/parser/index-1/ast.snap index 368f5852..222e0dec 100644 --- a/full-moon/tests/cases/fail/parser/index-1/error.snap +++ b/full-moon/tests/cases/fail/parser/index-1/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/index-1 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 3 @@ -16,5 +19,5 @@ UnexpectedToken: character: 4 token_type: type: Eof - additional: "expected ']'" + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/index-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/index-1/ast_to_string.snap new file mode 100644 index 00000000..e63b2061 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/index-1 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/index-1/error_display.snap b/full-moon/tests/cases/fail/parser/index-1/error_display.snap new file mode 100644 index 00000000..9c69eac1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-1/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/index-1 +--- +error[ast]: expected `]` to close index expression + ┌─ source.lua:1:2 + │ +1 │ x[2 + │ ^^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:1:4 + │ +1 │ x[2 + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/index-1/errors.snap b/full-moon/tests/cases/fail/parser/index-1/errors.snap new file mode 100644 index 00000000..dfb0f219 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-1/errors.snap @@ -0,0 +1,39 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/index-1 +--- +- AstError: + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Eof + additional: "expected `]` to close index expression" + range: + - bytes: 1 + line: 1 + character: 2 + - bytes: 3 + line: 1 + character: 4 +- AstError: + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Eof + additional: unexpected expression when looking for a statement + diff --git a/full-moon/tests/cases/fail/parser/index-2/error.snap b/full-moon/tests/cases/fail/parser/index-2/ast.snap similarity index 71% rename from full-moon/tests/cases/fail/parser/index-2/error.snap rename to full-moon/tests/cases/fail/parser/index-2/ast.snap index 78b40b59..9b6dfa6a 100644 --- a/full-moon/tests/cases/fail/parser/index-2/error.snap +++ b/full-moon/tests/cases/fail/parser/index-2/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/index-2 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 2 @@ -16,5 +19,5 @@ UnexpectedToken: character: 3 token_type: type: Eof - additional: expected expression + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/index-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/index-2/ast_to_string.snap new file mode 100644 index 00000000..acdae59d --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/index-2 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/index-2/error_display.snap b/full-moon/tests/cases/fail/parser/index-2/error_display.snap new file mode 100644 index 00000000..8c235bac --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-2/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/index-2 +--- +error[ast]: expected expression after `[` + ┌─ source.lua:1:2 + │ +1 │ x[ + │ ^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:1:3 + │ +1 │ x[ + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/index-2/errors.snap b/full-moon/tests/cases/fail/parser/index-2/errors.snap new file mode 100644 index 00000000..feb31115 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-2/errors.snap @@ -0,0 +1,33 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/index-2 +--- +- AstError: + token: + start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: "[" + additional: "expected expression after `[`" +- AstError: + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Eof + additional: unexpected expression when looking for a statement + diff --git a/full-moon/tests/lua52_cases/fail/parser/label-1/error.snap b/full-moon/tests/cases/fail/parser/index-3/ast.snap similarity index 57% rename from full-moon/tests/lua52_cases/fail/parser/label-1/error.snap rename to full-moon/tests/cases/fail/parser/index-3/ast.snap index 11007fd8..71001217 100644 --- a/full-moon/tests/lua52_cases/fail/parser/label-1/error.snap +++ b/full-moon/tests/cases/fail/parser/index-3/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/lua52_cases/fail/parser/label-1 - +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/index-3 --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 7 @@ -16,5 +19,5 @@ UnexpectedToken: character: 8 token_type: type: Eof - additional: "expected `::`" + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/index-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/index-3/ast_to_string.snap new file mode 100644 index 00000000..9296a0d2 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/index-3 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/index-3/error.snap b/full-moon/tests/cases/fail/parser/index-3/error.snap deleted file mode 100644 index ad38f497..00000000 --- a/full-moon/tests/cases/fail/parser/index-3/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/index-3 - ---- -UnexpectedToken: - token: - start_position: - bytes: 2 - line: 1 - character: 3 - end_position: - bytes: 3 - line: 1 - character: 4 - token_type: - type: Symbol - symbol: "]" - additional: expected expression - diff --git a/full-moon/tests/cases/fail/parser/index-3/error_display.snap b/full-moon/tests/cases/fail/parser/index-3/error_display.snap new file mode 100644 index 00000000..5a4c49c3 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-3/error_display.snap @@ -0,0 +1,25 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/index-3 +--- +error[ast]: expected expression after `[` + ┌─ source.lua:1:2 + │ +1 │ x[] = 1 + │ ^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:1:3 + │ +1 │ x[] = 1 + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:3 + │ +1 │ x[] = 1 + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/index-3/errors.snap b/full-moon/tests/cases/fail/parser/index-3/errors.snap new file mode 100644 index 00000000..76ffc51c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-3/errors.snap @@ -0,0 +1,48 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/index-3 +--- +- AstError: + token: + start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: "[" + additional: "expected expression after `[`" +- AstError: + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "]" + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "]" + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/index-4/ast.snap b/full-moon/tests/cases/fail/parser/index-4/ast.snap new file mode 100644 index 00000000..5b390d31 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-4/ast.snap @@ -0,0 +1,124 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/index-4 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: y + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Identifier + identifier: x + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/index-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/index-4/ast_to_string.snap new file mode 100644 index 00000000..486685aa --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/index-4 +--- +local y = x + diff --git a/full-moon/tests/cases/fail/parser/index-4/error.snap b/full-moon/tests/cases/fail/parser/index-4/error.snap deleted file mode 100644 index bd8b7b91..00000000 --- a/full-moon/tests/cases/fail/parser/index-4/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/index-4 - ---- -UnexpectedToken: - token: - start_position: - bytes: 10 - line: 1 - character: 11 - end_position: - bytes: 11 - line: 1 - character: 12 - token_type: - type: Identifier - identifier: x - additional: expected expression - diff --git a/full-moon/tests/cases/fail/parser/index-4/error_display.snap b/full-moon/tests/cases/fail/parser/index-4/error_display.snap new file mode 100644 index 00000000..69b67390 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-4/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/index-4 +--- +error[ast]: expected expression after `[` + ┌─ source.lua:1:12 + │ +1 │ local y = x[end] + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:13 + │ +1 │ local y = x[end] + │ ^^^ + + diff --git a/full-moon/tests/cases/fail/parser/index-4/errors.snap b/full-moon/tests/cases/fail/parser/index-4/errors.snap new file mode 100644 index 00000000..c640f83f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-4/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/index-4 +--- +- AstError: + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: "[" + additional: "expected expression after `[`" +- AstError: + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: end + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/index-5/ast.snap b/full-moon/tests/cases/fail/parser/index-5/ast.snap new file mode 100644 index 00000000..7440fbe5 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-5/ast.snap @@ -0,0 +1,71 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/index-5 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Identifier + identifier: name + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/index-5/ast_to_string.snap b/full-moon/tests/cases/fail/parser/index-5/ast_to_string.snap new file mode 100644 index 00000000..6d9d885d --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-5/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/index-5 +--- +return name + diff --git a/full-moon/tests/cases/fail/parser/index-5/error.snap b/full-moon/tests/cases/fail/parser/index-5/error.snap deleted file mode 100644 index 38cf978c..00000000 --- a/full-moon/tests/cases/fail/parser/index-5/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/index-5 - ---- -UnexpectedToken: - token: - start_position: - bytes: 12 - line: 1 - character: 13 - end_position: - bytes: 17 - line: 1 - character: 18 - token_type: - type: Symbol - symbol: until - additional: expected name - diff --git a/full-moon/tests/cases/fail/parser/index-5/error_display.snap b/full-moon/tests/cases/fail/parser/index-5/error_display.snap new file mode 100644 index 00000000..7fd11fc6 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-5/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/index-5 +--- +error[ast]: expected identifier after `.` + ┌─ source.lua:1:12 + │ +1 │ return name.until + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:13 + │ +1 │ return name.until + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/index-5/errors.snap b/full-moon/tests/cases/fail/parser/index-5/errors.snap new file mode 100644 index 00000000..c086086b --- /dev/null +++ b/full-moon/tests/cases/fail/parser/index-5/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/index-5 +--- +- AstError: + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: "." + additional: "expected identifier after `.`" +- AstError: + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: until + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/last-stmt-1/ast.snap b/full-moon/tests/cases/fail/parser/last-stmt-1/ast.snap new file mode 100644 index 00000000..6d686d75 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/last-stmt-1/ast.snap @@ -0,0 +1,291 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 23 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/last-stmt-1 +--- +nodes: + stmts: + - - LocalFunction: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + function_token: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: function + trailing_trivia: + - start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " + name: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Identifier + identifier: x + trailing_trivia: [] + body: + parameters_parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 19 + token_type: + type: Whitespace + characters: "\n" + parameters: + pairs: [] + block: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: + - start_position: + bytes: 19 + line: 2 + character: 1 + end_position: + bytes: 20 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 20 + line: 2 + character: 2 + end_position: + bytes: 26 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 26 + line: 2 + character: 8 + end_position: + bytes: 27 + line: 2 + character: 9 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 27 + line: 2 + character: 9 + end_position: + bytes: 28 + line: 2 + character: 10 + token_type: + type: Number + text: "1" + trailing_trivia: + - start_position: + bytes: 28 + line: 2 + character: 10 + end_position: + bytes: 29 + line: 2 + character: 10 + token_type: + type: Whitespace + characters: "\n" + - ~ + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ + last_stmt: + - Return: + token: + leading_trivia: + - start_position: + bytes: 29 + line: 3 + character: 1 + end_position: + bytes: 30 + line: 3 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 30 + line: 3 + character: 2 + end_position: + bytes: 36 + line: 3 + character: 8 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 36 + line: 3 + character: 8 + end_position: + bytes: 37 + line: 3 + character: 9 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 37 + line: 3 + character: 9 + end_position: + bytes: 38 + line: 3 + character: 10 + token_type: + type: Number + text: "2" + trailing_trivia: + - start_position: + bytes: 38 + line: 3 + character: 10 + end_position: + bytes: 39 + line: 3 + character: 10 + token_type: + type: Whitespace + characters: "\n" + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 43 + line: 5 + character: 1 + end_position: + bytes: 43 + line: 5 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/last-stmt-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/last-stmt-1/ast_to_string.snap new file mode 100644 index 00000000..de5fb646 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/last-stmt-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/last-stmt-1 +--- +"local function x()\n\treturn 1\nend\treturn 2\n" + diff --git a/full-moon/tests/cases/fail/parser/last-stmt-1/error_display.snap b/full-moon/tests/cases/fail/parser/last-stmt-1/error_display.snap new file mode 100644 index 00000000..aa58c713 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/last-stmt-1/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/last-stmt-1 +--- +error[ast]: expected `end` to close function body block + ┌─ source.lua:2:2 + │ +2 │ return 1 + │ ^^^^^^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:4:1 + │ +4 │ end + │ ^^^ + + diff --git a/full-moon/tests/cases/fail/parser/last-stmt-1/errors.snap b/full-moon/tests/cases/fail/parser/last-stmt-1/errors.snap new file mode 100644 index 00000000..d08c245e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/last-stmt-1/errors.snap @@ -0,0 +1,41 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/last-stmt-1 +--- +- AstError: + token: + start_position: + bytes: 30 + line: 3 + character: 2 + end_position: + bytes: 36 + line: 3 + character: 8 + token_type: + type: Symbol + symbol: return + additional: "expected `end` to close function body block" + range: + - bytes: 20 + line: 2 + character: 2 + - bytes: 28 + line: 2 + character: 10 +- AstError: + token: + start_position: + bytes: 39 + line: 4 + character: 1 + end_position: + bytes: 42 + line: 4 + character: 4 + token_type: + type: Symbol + symbol: end + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/last-stmt-1/source.lua b/full-moon/tests/cases/fail/parser/last-stmt-1/source.lua new file mode 100644 index 00000000..82fa7719 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/last-stmt-1/source.lua @@ -0,0 +1,4 @@ +local function x() + return 1 + return 2 +end diff --git a/full-moon/tests/cases/fail/parser/last-stmt-1/tokens.snap b/full-moon/tests/cases/fail/parser/last-stmt-1/tokens.snap new file mode 100644 index 00000000..63be35e3 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/last-stmt-1/tokens.snap @@ -0,0 +1,237 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 68 +expression: tokens +input_file: full-moon/tests/cases/fail/parser/last-stmt-1 +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local +- start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: function +- start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Identifier + identifier: x +- start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: ( +- start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: ) +- start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 19 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 19 + line: 2 + character: 1 + end_position: + bytes: 20 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" +- start_position: + bytes: 20 + line: 2 + character: 2 + end_position: + bytes: 26 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: return +- start_position: + bytes: 26 + line: 2 + character: 8 + end_position: + bytes: 27 + line: 2 + character: 9 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 27 + line: 2 + character: 9 + end_position: + bytes: 28 + line: 2 + character: 10 + token_type: + type: Number + text: "1" +- start_position: + bytes: 28 + line: 2 + character: 10 + end_position: + bytes: 29 + line: 2 + character: 10 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 29 + line: 3 + character: 1 + end_position: + bytes: 30 + line: 3 + character: 2 + token_type: + type: Whitespace + characters: "\t" +- start_position: + bytes: 30 + line: 3 + character: 2 + end_position: + bytes: 36 + line: 3 + character: 8 + token_type: + type: Symbol + symbol: return +- start_position: + bytes: 36 + line: 3 + character: 8 + end_position: + bytes: 37 + line: 3 + character: 9 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 37 + line: 3 + character: 9 + end_position: + bytes: 38 + line: 3 + character: 10 + token_type: + type: Number + text: "2" +- start_position: + bytes: 38 + line: 3 + character: 10 + end_position: + bytes: 39 + line: 3 + character: 10 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 39 + line: 4 + character: 1 + end_position: + bytes: 42 + line: 4 + character: 4 + token_type: + type: Symbol + symbol: end +- start_position: + bytes: 42 + line: 4 + character: 4 + end_position: + bytes: 43 + line: 4 + character: 4 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 43 + line: 5 + character: 1 + end_position: + bytes: 43 + line: 5 + character: 1 + token_type: + type: Eof + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-1/ast.snap b/full-moon/tests/cases/fail/parser/local-assignment-1/ast.snap new file mode 100644 index 00000000..ae6bfc2a --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-1/ast.snap @@ -0,0 +1,82 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/local-assignment-1 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: ~ + expr_list: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-assignment-1/ast_to_string.snap new file mode 100644 index 00000000..978a49d1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-assignment-1 +--- +"local x " + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-1/error.snap b/full-moon/tests/cases/fail/parser/local-assignment-1/error.snap deleted file mode 100644 index abb3e3c8..00000000 --- a/full-moon/tests/cases/fail/parser/local-assignment-1/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/local-assignment-1 - ---- -UnexpectedToken: - token: - start_position: - bytes: 8 - line: 1 - character: 9 - end_position: - bytes: 9 - line: 1 - character: 10 - token_type: - type: Identifier - identifier: y - additional: leftover token - diff --git a/full-moon/tests/cases/fail/parser/local-assignment-1/error_display.snap b/full-moon/tests/cases/fail/parser/local-assignment-1/error_display.snap new file mode 100644 index 00000000..ef5a06f1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-assignment-1 +--- +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:1:10 + │ +1 │ local x y + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-1/errors.snap b/full-moon/tests/cases/fail/parser/local-assignment-1/errors.snap new file mode 100644 index 00000000..c96d5321 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-1/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-assignment-1 +--- +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Eof + additional: unexpected expression when looking for a statement + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-2/ast.snap b/full-moon/tests/cases/fail/parser/local-assignment-2/ast.snap new file mode 100644 index 00000000..59339fec --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-2/ast.snap @@ -0,0 +1,96 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/local-assignment-2 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: [] + expr_list: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-assignment-2/ast_to_string.snap new file mode 100644 index 00000000..0e89b5c1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-assignment-2 +--- +local x = + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-2/error.snap b/full-moon/tests/cases/fail/parser/local-assignment-2/error.snap deleted file mode 100644 index b1b79c21..00000000 --- a/full-moon/tests/cases/fail/parser/local-assignment-2/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/local-assignment-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 9 - line: 1 - character: 10 - end_position: - bytes: 9 - line: 1 - character: 10 - token_type: - type: Eof - additional: expected expression - diff --git a/full-moon/tests/cases/fail/parser/local-assignment-2/error_display.snap b/full-moon/tests/cases/fail/parser/local-assignment-2/error_display.snap new file mode 100644 index 00000000..2d3cc9bc --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-2/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-assignment-2 +--- +error[ast]: expected an expression + ┌─ source.lua:1:9 + │ +1 │ local x = + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-2/errors.snap b/full-moon/tests/cases/fail/parser/local-assignment-2/errors.snap new file mode 100644 index 00000000..96c0cc2a --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-2/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-assignment-2 +--- +- AstError: + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + additional: expected an expression + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-3/ast.snap b/full-moon/tests/cases/fail/parser/local-assignment-3/ast.snap new file mode 100644 index 00000000..ae264791 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-3/ast.snap @@ -0,0 +1,123 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/local-assignment-3 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Number + text: "1" + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-assignment-3/ast_to_string.snap new file mode 100644 index 00000000..f4da167a --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-assignment-3 +--- +local x = 1 + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-3/error.snap b/full-moon/tests/cases/fail/parser/local-assignment-3/error.snap deleted file mode 100644 index 8b950ad9..00000000 --- a/full-moon/tests/cases/fail/parser/local-assignment-3/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/local-assignment-3 - ---- -UnexpectedToken: - token: - start_position: - bytes: 11 - line: 1 - character: 12 - end_position: - bytes: 12 - line: 1 - character: 13 - token_type: - type: Symbol - symbol: "," - additional: leftover token - diff --git a/full-moon/tests/cases/fail/parser/local-assignment-3/error_display.snap b/full-moon/tests/cases/fail/parser/local-assignment-3/error_display.snap new file mode 100644 index 00000000..df0ad916 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-3/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-assignment-3 +--- +error[ast]: trailing commas are not allowed + ┌─ source.lua:1:12 + │ +1 │ local x = 1, + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-3/errors.snap b/full-moon/tests/cases/fail/parser/local-assignment-3/errors.snap new file mode 100644 index 00000000..803e6f86 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-3/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-assignment-3 +--- +- AstError: + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: "," + additional: trailing commas are not allowed + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-4/error.snap b/full-moon/tests/cases/fail/parser/local-assignment-4/ast.snap similarity index 59% rename from full-moon/tests/cases/fail/parser/local-assignment-4/error.snap rename to full-moon/tests/cases/fail/parser/local-assignment-4/ast.snap index 944f2ec5..c2680a6d 100644 --- a/full-moon/tests/cases/fail/parser/local-assignment-4/error.snap +++ b/full-moon/tests/cases/fail/parser/local-assignment-4/ast.snap @@ -1,21 +1,23 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/local-assignment-4 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: - bytes: 6 + bytes: 9 line: 1 - character: 7 + character: 10 end_position: bytes: 9 line: 1 character: 10 token_type: - type: Symbol - symbol: end - additional: expected name + type: Eof + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/local-assignment-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-assignment-4/ast_to_string.snap new file mode 100644 index 00000000..ff3a59f7 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-assignment-4 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-4/error_display.snap b/full-moon/tests/cases/fail/parser/local-assignment-4/error_display.snap new file mode 100644 index 00000000..1e8474d9 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-4/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-assignment-4 +--- +error[ast]: expected either a variable name or `function` + ┌─ source.lua:1:7 + │ +1 │ local end + │ ^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:7 + │ +1 │ local end + │ ^^^ + + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-4/errors.snap b/full-moon/tests/cases/fail/parser/local-assignment-4/errors.snap new file mode 100644 index 00000000..0986aef8 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-4/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-assignment-4 +--- +- AstError: + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: end + additional: "expected either a variable name or `function`" +- AstError: + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: end + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-5/ast.snap b/full-moon/tests/cases/fail/parser/local-assignment-5/ast.snap new file mode 100644 index 00000000..b0996b9e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-5/ast.snap @@ -0,0 +1,107 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/local-assignment-5 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-5/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-assignment-5/ast_to_string.snap new file mode 100644 index 00000000..4b3582eb --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-5/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-assignment-5 +--- +"local x = " + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-5/error.snap b/full-moon/tests/cases/fail/parser/local-assignment-5/error.snap deleted file mode 100644 index 6dfabad1..00000000 --- a/full-moon/tests/cases/fail/parser/local-assignment-5/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/local-assignment-5 - ---- -UnexpectedToken: - token: - start_position: - bytes: 10 - line: 1 - character: 11 - end_position: - bytes: 13 - line: 1 - character: 14 - token_type: - type: Symbol - symbol: end - additional: expected expression - diff --git a/full-moon/tests/cases/fail/parser/local-assignment-5/error_display.snap b/full-moon/tests/cases/fail/parser/local-assignment-5/error_display.snap new file mode 100644 index 00000000..a0e10c78 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-5/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-assignment-5 +--- +error[ast]: expected an expression + ┌─ source.lua:1:9 + │ +1 │ local x = end + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:11 + │ +1 │ local x = end + │ ^^^ + + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-5/errors.snap b/full-moon/tests/cases/fail/parser/local-assignment-5/errors.snap new file mode 100644 index 00000000..24481c2e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-5/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-assignment-5 +--- +- AstError: + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + additional: expected an expression +- AstError: + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: end + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-6/ast.snap b/full-moon/tests/cases/fail/parser/local-assignment-6/ast.snap new file mode 100644 index 00000000..c028da36 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-6/ast.snap @@ -0,0 +1,218 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 16 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/local-assignment-6 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: "\n" + expr_list: + pairs: [] + - ~ + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 2 + character: 1 + end_position: + bytes: 15 + line: 2 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 15 + line: 2 + character: 6 + end_position: + bytes: 16 + line: 2 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 2 + character: 7 + end_position: + bytes: 17 + line: 2 + character: 8 + token_type: + type: Identifier + identifier: y + trailing_trivia: + - start_position: + bytes: 17 + line: 2 + character: 8 + end_position: + bytes: 18 + line: 2 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 18 + line: 2 + character: 9 + end_position: + bytes: 19 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 19 + line: 2 + character: 10 + end_position: + bytes: 20 + line: 2 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 20 + line: 2 + character: 11 + end_position: + bytes: 21 + line: 2 + character: 12 + token_type: + type: Number + text: "2" + trailing_trivia: + - start_position: + bytes: 21 + line: 2 + character: 12 + end_position: + bytes: 22 + line: 2 + character: 12 + token_type: + type: Whitespace + characters: "\n" + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 22 + line: 3 + character: 1 + end_position: + bytes: 22 + line: 3 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-6/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-assignment-6/ast_to_string.snap new file mode 100644 index 00000000..3d5e444d --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-6/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 19 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-assignment-6 +--- +"local x =\nlocal y = 2\n" + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-6/error_display.snap b/full-moon/tests/cases/fail/parser/local-assignment-6/error_display.snap new file mode 100644 index 00000000..5a0551bf --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-6/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-assignment-6 +--- +error[ast]: expected an expression + ┌─ source.lua:1:9 + │ +1 │ local x = + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-6/errors.snap b/full-moon/tests/cases/fail/parser/local-assignment-6/errors.snap new file mode 100644 index 00000000..4cd3d0c4 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-6/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-assignment-6 +--- +- AstError: + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + additional: expected an expression + diff --git a/full-moon/tests/cases/fail/parser/local-assignment-6/source.lua b/full-moon/tests/cases/fail/parser/local-assignment-6/source.lua new file mode 100644 index 00000000..19f15f41 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-6/source.lua @@ -0,0 +1,2 @@ +local x = +local y = 2 diff --git a/full-moon/tests/cases/fail/parser/local-assignment-6/tokens.snap b/full-moon/tests/cases/fail/parser/local-assignment-6/tokens.snap new file mode 100644 index 00000000..f139ed2f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-assignment-6/tokens.snap @@ -0,0 +1,171 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: tokens +input_file: full-moon/tests/cases/fail/parser/local-assignment-6 +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local +- start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x +- start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 10 + line: 2 + character: 1 + end_position: + bytes: 15 + line: 2 + character: 6 + token_type: + type: Symbol + symbol: local +- start_position: + bytes: 15 + line: 2 + character: 6 + end_position: + bytes: 16 + line: 2 + character: 7 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 16 + line: 2 + character: 7 + end_position: + bytes: 17 + line: 2 + character: 8 + token_type: + type: Identifier + identifier: y +- start_position: + bytes: 17 + line: 2 + character: 8 + end_position: + bytes: 18 + line: 2 + character: 9 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 18 + line: 2 + character: 9 + end_position: + bytes: 19 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 19 + line: 2 + character: 10 + end_position: + bytes: 20 + line: 2 + character: 11 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 20 + line: 2 + character: 11 + end_position: + bytes: 21 + line: 2 + character: 12 + token_type: + type: Number + text: "2" +- start_position: + bytes: 21 + line: 2 + character: 12 + end_position: + bytes: 22 + line: 2 + character: 12 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 22 + line: 3 + character: 1 + end_position: + bytes: 22 + line: 3 + character: 1 + token_type: + type: Eof + diff --git a/full-moon/tests/cases/fail/parser/local-function-1/error.snap b/full-moon/tests/cases/fail/parser/local-function-1/ast.snap similarity index 72% rename from full-moon/tests/cases/fail/parser/local-function-1/error.snap rename to full-moon/tests/cases/fail/parser/local-function-1/ast.snap index c77ecf39..8f35e17d 100644 --- a/full-moon/tests/cases/fail/parser/local-function-1/error.snap +++ b/full-moon/tests/cases/fail/parser/local-function-1/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/local-function-1 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 14 @@ -16,5 +19,5 @@ UnexpectedToken: character: 15 token_type: type: Eof - additional: expected name + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/local-function-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-function-1/ast_to_string.snap new file mode 100644 index 00000000..2b89cc71 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-function-1 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/local-function-1/error_display.snap b/full-moon/tests/cases/fail/parser/local-function-1/error_display.snap new file mode 100644 index 00000000..b0f0828b --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-function-1 +--- +error[ast]: expected a function name + ┌─ source.lua:1:15 + │ +1 │ local function + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/local-function-1/errors.snap b/full-moon/tests/cases/fail/parser/local-function-1/errors.snap new file mode 100644 index 00000000..df14f81b --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-1/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-function-1 +--- +- AstError: + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Eof + additional: expected a function name + diff --git a/full-moon/tests/cases/fail/parser/local-function-2/error.snap b/full-moon/tests/cases/fail/parser/local-function-2/ast.snap similarity index 72% rename from full-moon/tests/cases/fail/parser/local-function-2/error.snap rename to full-moon/tests/cases/fail/parser/local-function-2/ast.snap index dba04dfd..b8d987d6 100644 --- a/full-moon/tests/cases/fail/parser/local-function-2/error.snap +++ b/full-moon/tests/cases/fail/parser/local-function-2/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/local-function-2 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 16 @@ -16,5 +19,5 @@ UnexpectedToken: character: 17 token_type: type: Eof - additional: "expected '('" + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/local-function-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-function-2/ast_to_string.snap new file mode 100644 index 00000000..57ee1b62 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-function-2 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/local-function-2/error_display.snap b/full-moon/tests/cases/fail/parser/local-function-2/error_display.snap new file mode 100644 index 00000000..bcac5b4c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-2/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-function-2 +--- +error[ast]: expected a function body + ┌─ source.lua:1:7 + │ +1 │ local function x + │ ^^^^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/local-function-2/errors.snap b/full-moon/tests/cases/fail/parser/local-function-2/errors.snap new file mode 100644 index 00000000..deacbda1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-2/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-function-2 +--- +- AstError: + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: function + additional: expected a function body + diff --git a/full-moon/tests/cases/fail/parser/local-function-3/ast.snap b/full-moon/tests/cases/fail/parser/local-function-3/ast.snap new file mode 100644 index 00000000..a773c2b7 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-3/ast.snap @@ -0,0 +1,142 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/local-function-3 +--- +nodes: + stmts: + - - LocalFunction: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + function_token: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: function + trailing_trivia: + - start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " + name: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Identifier + identifier: x + trailing_trivia: [] + body: + parameters_parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + parameters: + pairs: [] + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/local-function-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-function-3/ast_to_string.snap new file mode 100644 index 00000000..e5b59eb7 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-function-3 +--- +local function x()end + diff --git a/full-moon/tests/cases/fail/parser/local-function-3/error.snap b/full-moon/tests/cases/fail/parser/local-function-3/error.snap deleted file mode 100644 index d205c15f..00000000 --- a/full-moon/tests/cases/fail/parser/local-function-3/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/local-function-3 - ---- -UnexpectedToken: - token: - start_position: - bytes: 17 - line: 1 - character: 18 - end_position: - bytes: 17 - line: 1 - character: 18 - token_type: - type: Eof - additional: "expected ')'" - diff --git a/full-moon/tests/cases/fail/parser/local-function-3/error_display.snap b/full-moon/tests/cases/fail/parser/local-function-3/error_display.snap new file mode 100644 index 00000000..5869ede9 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-3/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-function-3 +--- +error[ast]: expected a parameter name or `)` + ┌─ source.lua:1:18 + │ +1 │ local function x( + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/local-function-3/errors.snap b/full-moon/tests/cases/fail/parser/local-function-3/errors.snap new file mode 100644 index 00000000..9eb9335c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-3/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-function-3 +--- +- AstError: + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Eof + additional: "expected a parameter name or `)`" + diff --git a/full-moon/tests/cases/fail/parser/local-function-4/ast.snap b/full-moon/tests/cases/fail/parser/local-function-4/ast.snap new file mode 100644 index 00000000..4a10477c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-4/ast.snap @@ -0,0 +1,218 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/local-function-4 +--- +nodes: + stmts: + - - LocalFunction: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + function_token: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: function + trailing_trivia: + - start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " + name: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Identifier + identifier: x + trailing_trivia: [] + body: + parameters_parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 19 + token_type: + type: Whitespace + characters: "\n" + parameters: + pairs: [] + block: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 19 + line: 2 + character: 1 + end_position: + bytes: 20 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 20 + line: 2 + character: 2 + end_position: + bytes: 24 + line: 2 + character: 6 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 24 + line: 2 + character: 6 + end_position: + bytes: 25 + line: 2 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 25 + line: 2 + character: 7 + end_position: + bytes: 26 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: [] + - ~ + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 26 + line: 2 + character: 8 + end_position: + bytes: 26 + line: 2 + character: 8 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/local-function-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-function-4/ast_to_string.snap new file mode 100644 index 00000000..dddbc315 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-function-4 +--- +"local function x()\n\tcall()end" + diff --git a/full-moon/tests/cases/fail/parser/local-function-4/error.snap b/full-moon/tests/cases/fail/parser/local-function-4/error.snap deleted file mode 100644 index 3756a758..00000000 --- a/full-moon/tests/cases/fail/parser/local-function-4/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/local-function-4 - ---- -UnexpectedToken: - token: - start_position: - bytes: 26 - line: 2 - character: 8 - end_position: - bytes: 26 - line: 2 - character: 8 - token_type: - type: Eof - additional: "expected 'end'" - diff --git a/full-moon/tests/cases/fail/parser/local-function-4/error_display.snap b/full-moon/tests/cases/fail/parser/local-function-4/error_display.snap new file mode 100644 index 00000000..6f3e49e1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-4/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-function-4 +--- +error[ast]: expected `end` to close function body block + ┌─ source.lua:2:2 + │ +2 │ call() + │ ^^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/local-function-4/errors.snap b/full-moon/tests/cases/fail/parser/local-function-4/errors.snap new file mode 100644 index 00000000..5af4c8dc --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-4/errors.snap @@ -0,0 +1,26 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-function-4 +--- +- AstError: + token: + start_position: + bytes: 26 + line: 2 + character: 8 + end_position: + bytes: 26 + line: 2 + character: 8 + token_type: + type: Eof + additional: "expected `end` to close function body block" + range: + - bytes: 20 + line: 2 + character: 2 + - bytes: 26 + line: 2 + character: 8 + diff --git a/full-moon/tests/cases/fail/parser/local-function-5/ast.snap b/full-moon/tests/cases/fail/parser/local-function-5/ast.snap new file mode 100644 index 00000000..0b5cf608 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-5/ast.snap @@ -0,0 +1,99 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/local-function-5 +--- +nodes: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 20 + line: 2 + character: 1 + end_position: + bytes: 21 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 21 + line: 2 + character: 2 + end_position: + bytes: 25 + line: 2 + character: 6 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 25 + line: 2 + character: 6 + end_position: + bytes: 26 + line: 2 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 26 + line: 2 + character: 7 + end_position: + bytes: 27 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 27 + line: 2 + character: 8 + end_position: + bytes: 28 + line: 2 + character: 8 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 31 + line: 3 + character: 4 + end_position: + bytes: 31 + line: 3 + character: 4 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/local-function-5/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-function-5/ast_to_string.snap new file mode 100644 index 00000000..16a223dc --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-5/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-function-5 +--- +"\tcall()\n" + diff --git a/full-moon/tests/cases/fail/parser/local-function-5/error.snap b/full-moon/tests/cases/fail/parser/local-function-5/error.snap deleted file mode 100644 index 0398de07..00000000 --- a/full-moon/tests/cases/fail/parser/local-function-5/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/local-function-5 - ---- -UnexpectedToken: - token: - start_position: - bytes: 15 - line: 1 - character: 16 - end_position: - bytes: 17 - line: 1 - character: 18 - token_type: - type: Symbol - symbol: do - additional: expected name - diff --git a/full-moon/tests/cases/fail/parser/local-function-5/error_display.snap b/full-moon/tests/cases/fail/parser/local-function-5/error_display.snap new file mode 100644 index 00000000..1dfd6ef6 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-5/error_display.snap @@ -0,0 +1,25 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-function-5 +--- +error[ast]: expected a function name + ┌─ source.lua:1:16 + │ +1 │ local function do() + │ ^^ + +error[ast]: expected an expression after `(` + ┌─ source.lua:1:18 + │ +1 │ local function do() + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:19 + │ +1 │ local function do() + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/local-function-5/errors.snap b/full-moon/tests/cases/fail/parser/local-function-5/errors.snap new file mode 100644 index 00000000..62ba729e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-5/errors.snap @@ -0,0 +1,48 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-function-5 +--- +- AstError: + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: do + additional: expected a function name +- AstError: + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: ( + additional: "expected an expression after `(`" +- AstError: + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Symbol + symbol: ) + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/local-function-6/ast.snap b/full-moon/tests/cases/fail/parser/local-function-6/ast.snap new file mode 100644 index 00000000..e78329aa --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-6/ast.snap @@ -0,0 +1,142 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/local-function-6 +--- +nodes: + stmts: + - - LocalFunction: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + function_token: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: function + trailing_trivia: + - start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " + name: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Identifier + identifier: x + trailing_trivia: [] + body: + parameters_parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + parameters: + pairs: [] + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 25 + line: 2 + character: 4 + end_position: + bytes: 25 + line: 2 + character: 4 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/local-function-6/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-function-6/ast_to_string.snap new file mode 100644 index 00000000..8028e693 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-6/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-function-6 +--- +local function x()end + diff --git a/full-moon/tests/cases/fail/parser/local-function-6/error.snap b/full-moon/tests/cases/fail/parser/local-function-6/error.snap deleted file mode 100644 index b96a9f6c..00000000 --- a/full-moon/tests/cases/fail/parser/local-function-6/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/local-function-6 - ---- -UnexpectedToken: - token: - start_position: - bytes: 17 - line: 1 - character: 18 - end_position: - bytes: 18 - line: 1 - character: 19 - token_type: - type: Symbol - symbol: "," - additional: "expected ')'" - diff --git a/full-moon/tests/cases/fail/parser/local-function-6/error_display.snap b/full-moon/tests/cases/fail/parser/local-function-6/error_display.snap new file mode 100644 index 00000000..f975547b --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-6/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-function-6 +--- +error[ast]: expected a parameter name or `)` + ┌─ source.lua:1:18 + │ +1 │ local function x(,,,) + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:18 + │ +1 │ local function x(,,,) + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/local-function-6/errors.snap b/full-moon/tests/cases/fail/parser/local-function-6/errors.snap new file mode 100644 index 00000000..e362a18e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-6/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-function-6 +--- +- AstError: + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: "," + additional: "expected a parameter name or `)`" +- AstError: + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: "," + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/local-function-7/ast.snap b/full-moon/tests/cases/fail/parser/local-function-7/ast.snap new file mode 100644 index 00000000..e7e3d4c8 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-7/ast.snap @@ -0,0 +1,356 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 16 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/local-function-7 +--- +nodes: + stmts: + - - LocalFunction: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + function_token: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: function + trailing_trivia: + - start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " + name: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Identifier + identifier: foo + trailing_trivia: [] + body: + parameters_parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 24 + line: 1 + character: 25 + end_position: + bytes: 25 + line: 1 + character: 26 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 26 + token_type: + type: Whitespace + characters: "\n" + parameters: + pairs: + - Punctuated: + - Name: + leading_trivia: [] + token: + start_position: + bytes: 19 + line: 1 + character: 20 + end_position: + bytes: 20 + line: 1 + character: 21 + token_type: + type: Identifier + identifier: x + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 20 + line: 1 + character: 21 + end_position: + bytes: 21 + line: 1 + character: 22 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 21 + line: 1 + character: 22 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Whitespace + characters: " " + - End: + Name: + leading_trivia: [] + token: + start_position: + bytes: 22 + line: 1 + character: 23 + end_position: + bytes: 23 + line: 1 + character: 24 + token_type: + type: Identifier + identifier: y + trailing_trivia: [] + block: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 26 + line: 2 + character: 1 + end_position: + bytes: 27 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 27 + line: 2 + character: 2 + end_position: + bytes: 32 + line: 2 + character: 7 + token_type: + type: Identifier + identifier: print + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 32 + line: 2 + character: 7 + end_position: + bytes: 33 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 37 + line: 2 + character: 12 + end_position: + bytes: 38 + line: 2 + character: 13 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 38 + line: 2 + character: 13 + end_position: + bytes: 39 + line: 2 + character: 13 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: + - Punctuated: + - Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 33 + line: 2 + character: 8 + end_position: + bytes: 34 + line: 2 + character: 9 + token_type: + type: Identifier + identifier: x + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 34 + line: 2 + character: 9 + end_position: + bytes: 35 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 35 + line: 2 + character: 10 + end_position: + bytes: 36 + line: 2 + character: 11 + token_type: + type: Whitespace + characters: " " + - End: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 36 + line: 2 + character: 11 + end_position: + bytes: 37 + line: 2 + character: 12 + token_type: + type: Identifier + identifier: y + trailing_trivia: [] + - ~ + end_token: + leading_trivia: [] + token: + start_position: + bytes: 39 + line: 3 + character: 1 + end_position: + bytes: 42 + line: 3 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: + - start_position: + bytes: 42 + line: 3 + character: 4 + end_position: + bytes: 43 + line: 3 + character: 4 + token_type: + type: Whitespace + characters: "\n" + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 43 + line: 4 + character: 1 + end_position: + bytes: 43 + line: 4 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/local-function-7/ast_to_string.snap b/full-moon/tests/cases/fail/parser/local-function-7/ast_to_string.snap new file mode 100644 index 00000000..624bd6a7 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-7/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 19 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/local-function-7 +--- +"local function foo(x, y)\n\tprint(x, y)\nend\n" + diff --git a/full-moon/tests/cases/fail/parser/local-function-7/error_display.snap b/full-moon/tests/cases/fail/parser/local-function-7/error_display.snap new file mode 100644 index 00000000..5eeef31c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-7/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/local-function-7 +--- +error[ast]: trailing commas in arguments are not allowed + ┌─ source.lua:1:24 + │ +1 │ local function foo(x, y,) + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/local-function-7/errors.snap b/full-moon/tests/cases/fail/parser/local-function-7/errors.snap new file mode 100644 index 00000000..9d5612cc --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-7/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/local-function-7 +--- +- AstError: + token: + start_position: + bytes: 23 + line: 1 + character: 24 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Symbol + symbol: "," + additional: trailing commas in arguments are not allowed + diff --git a/full-moon/tests/cases/fail/parser/local-function-7/source.lua b/full-moon/tests/cases/fail/parser/local-function-7/source.lua new file mode 100644 index 00000000..504b7678 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-7/source.lua @@ -0,0 +1,3 @@ +local function foo(x, y,) + print(x, y) +end diff --git a/full-moon/tests/cases/fail/parser/local-function-7/tokens.snap b/full-moon/tests/cases/fail/parser/local-function-7/tokens.snap new file mode 100644 index 00000000..f7d41dc3 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/local-function-7/tokens.snap @@ -0,0 +1,281 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: tokens +input_file: full-moon/tests/cases/fail/parser/local-function-7 +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local +- start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: function +- start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Identifier + identifier: foo +- start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Symbol + symbol: ( +- start_position: + bytes: 19 + line: 1 + character: 20 + end_position: + bytes: 20 + line: 1 + character: 21 + token_type: + type: Identifier + identifier: x +- start_position: + bytes: 20 + line: 1 + character: 21 + end_position: + bytes: 21 + line: 1 + character: 22 + token_type: + type: Symbol + symbol: "," +- start_position: + bytes: 21 + line: 1 + character: 22 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 22 + line: 1 + character: 23 + end_position: + bytes: 23 + line: 1 + character: 24 + token_type: + type: Identifier + identifier: y +- start_position: + bytes: 23 + line: 1 + character: 24 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Symbol + symbol: "," +- start_position: + bytes: 24 + line: 1 + character: 25 + end_position: + bytes: 25 + line: 1 + character: 26 + token_type: + type: Symbol + symbol: ) +- start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 26 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 26 + line: 2 + character: 1 + end_position: + bytes: 27 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" +- start_position: + bytes: 27 + line: 2 + character: 2 + end_position: + bytes: 32 + line: 2 + character: 7 + token_type: + type: Identifier + identifier: print +- start_position: + bytes: 32 + line: 2 + character: 7 + end_position: + bytes: 33 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: ( +- start_position: + bytes: 33 + line: 2 + character: 8 + end_position: + bytes: 34 + line: 2 + character: 9 + token_type: + type: Identifier + identifier: x +- start_position: + bytes: 34 + line: 2 + character: 9 + end_position: + bytes: 35 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: "," +- start_position: + bytes: 35 + line: 2 + character: 10 + end_position: + bytes: 36 + line: 2 + character: 11 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 36 + line: 2 + character: 11 + end_position: + bytes: 37 + line: 2 + character: 12 + token_type: + type: Identifier + identifier: y +- start_position: + bytes: 37 + line: 2 + character: 12 + end_position: + bytes: 38 + line: 2 + character: 13 + token_type: + type: Symbol + symbol: ) +- start_position: + bytes: 38 + line: 2 + character: 13 + end_position: + bytes: 39 + line: 2 + character: 13 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 39 + line: 3 + character: 1 + end_position: + bytes: 42 + line: 3 + character: 4 + token_type: + type: Symbol + symbol: end +- start_position: + bytes: 42 + line: 3 + character: 4 + end_position: + bytes: 43 + line: 3 + character: 4 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 43 + line: 4 + character: 1 + end_position: + bytes: 43 + line: 4 + character: 1 + token_type: + type: Eof + diff --git a/full-moon/tests/cases/fail/parser/method-call-1/ast.snap b/full-moon/tests/cases/fail/parser/method-call-1/ast.snap new file mode 100644 index 00000000..10cea19b --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-1/ast.snap @@ -0,0 +1,71 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/method-call-1 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Identifier + identifier: name + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/method-call-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/method-call-1/ast_to_string.snap new file mode 100644 index 00000000..b60b6703 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/method-call-1 +--- +return name + diff --git a/full-moon/tests/cases/fail/parser/method-call-1/error.snap b/full-moon/tests/cases/fail/parser/method-call-1/error.snap deleted file mode 100644 index 073d1cc1..00000000 --- a/full-moon/tests/cases/fail/parser/method-call-1/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/method-call-1 - ---- -UnexpectedToken: - token: - start_position: - bytes: 12 - line: 1 - character: 13 - end_position: - bytes: 12 - line: 1 - character: 13 - token_type: - type: Eof - additional: expected method - diff --git a/full-moon/tests/cases/fail/parser/method-call-1/error_display.snap b/full-moon/tests/cases/fail/parser/method-call-1/error_display.snap new file mode 100644 index 00000000..30fe852b --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/method-call-1 +--- +error[ast]: expected identifier after `:` + ┌─ source.lua:1:12 + │ +1 │ return name: + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/method-call-1/errors.snap b/full-moon/tests/cases/fail/parser/method-call-1/errors.snap new file mode 100644 index 00000000..7ec3fb30 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-1/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/method-call-1 +--- +- AstError: + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: ":" + additional: "expected identifier after `:`" + diff --git a/full-moon/tests/cases/fail/parser/method-call-2/ast.snap b/full-moon/tests/cases/fail/parser/method-call-2/ast.snap new file mode 100644 index 00000000..249ed2de --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-2/ast.snap @@ -0,0 +1,139 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/method-call-2 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + FunctionCall: + prefix: + Name: + leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Identifier + identifier: name + trailing_trivia: [] + suffixes: + - Call: + MethodCall: + colon_token: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: ":" + trailing_trivia: [] + name: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Identifier + identifier: method + trailing_trivia: [] + args: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/method-call-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/method-call-2/ast_to_string.snap new file mode 100644 index 00000000..c938d823 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/method-call-2 +--- +"return name:method()" + diff --git a/full-moon/tests/cases/fail/parser/method-call-2/error.snap b/full-moon/tests/cases/fail/parser/method-call-2/error.snap deleted file mode 100644 index 4785d712..00000000 --- a/full-moon/tests/cases/fail/parser/method-call-2/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/method-call-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 18 - line: 1 - character: 19 - end_position: - bytes: 18 - line: 1 - character: 19 - token_type: - type: Eof - additional: expected args - diff --git a/full-moon/tests/cases/fail/parser/method-call-2/error_display.snap b/full-moon/tests/cases/fail/parser/method-call-2/error_display.snap new file mode 100644 index 00000000..2fbc475f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-2/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/method-call-2 +--- +error[ast]: expected arguments after `:` + ┌─ source.lua:1:13 + │ +1 │ return name:method + │ ^^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/method-call-2/errors.snap b/full-moon/tests/cases/fail/parser/method-call-2/errors.snap new file mode 100644 index 00000000..87bf91f9 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-2/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/method-call-2 +--- +- AstError: + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Identifier + identifier: method + additional: "expected arguments after `:`" + diff --git a/full-moon/tests/cases/fail/parser/method-call-3/ast.snap b/full-moon/tests/cases/fail/parser/method-call-3/ast.snap new file mode 100644 index 00000000..9135a802 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-3/ast.snap @@ -0,0 +1,139 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/method-call-3 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + FunctionCall: + prefix: + Name: + leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Identifier + identifier: name + trailing_trivia: [] + suffixes: + - Call: + MethodCall: + colon_token: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: ":" + trailing_trivia: [] + name: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Identifier + identifier: method + trailing_trivia: [] + args: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 25 + line: 1 + character: 26 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/method-call-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/method-call-3/ast_to_string.snap new file mode 100644 index 00000000..b1a2a4bb --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/method-call-3 +--- +"return name:method()" + diff --git a/full-moon/tests/cases/fail/parser/method-call-3/error.snap b/full-moon/tests/cases/fail/parser/method-call-3/error.snap deleted file mode 100644 index d4bb7961..00000000 --- a/full-moon/tests/cases/fail/parser/method-call-3/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/method-call-3 - ---- -UnexpectedToken: - token: - start_position: - bytes: 19 - line: 1 - character: 20 - end_position: - bytes: 24 - line: 1 - character: 25 - token_type: - type: Symbol - symbol: until - additional: "expected ')'" - diff --git a/full-moon/tests/cases/fail/parser/method-call-3/error_display.snap b/full-moon/tests/cases/fail/parser/method-call-3/error_display.snap new file mode 100644 index 00000000..3d5571a1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-3/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/method-call-3 +--- +error[ast]: expected `)` to close function call + ┌─ source.lua:1:19 + │ +1 │ return name:method(until) + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:20 + │ +1 │ return name:method(until) + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/method-call-3/errors.snap b/full-moon/tests/cases/fail/parser/method-call-3/errors.snap new file mode 100644 index 00000000..7d92bd96 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/method-call-3/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/method-call-3 +--- +- AstError: + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Symbol + symbol: ( + additional: "expected `)` to close function call" +- AstError: + token: + start_position: + bytes: 19 + line: 1 + character: 20 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Symbol + symbol: until + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-1/error.snap b/full-moon/tests/cases/fail/parser/numeric-for-1/ast.snap similarity index 72% rename from full-moon/tests/cases/fail/parser/numeric-for-1/error.snap rename to full-moon/tests/cases/fail/parser/numeric-for-1/ast.snap index 30f9fce2..50bd5002 100644 --- a/full-moon/tests/cases/fail/parser/numeric-for-1/error.snap +++ b/full-moon/tests/cases/fail/parser/numeric-for-1/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/numeric-for-1 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 5 @@ -16,5 +19,5 @@ UnexpectedToken: character: 6 token_type: type: Eof - additional: "expected 'in'" + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/numeric-for-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/numeric-for-1/ast_to_string.snap new file mode 100644 index 00000000..ae345e39 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/numeric-for-1 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-1/error_display.snap b/full-moon/tests/cases/fail/parser/numeric-for-1/error_display.snap new file mode 100644 index 00000000..cdc726b1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/numeric-for-1 +--- +error[ast]: expected `in` after name list + ┌─ source.lua:1:6 + │ +1 │ for x + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-1/errors.snap b/full-moon/tests/cases/fail/parser/numeric-for-1/errors.snap new file mode 100644 index 00000000..c2a73d30 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-1/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/numeric-for-1 +--- +- AstError: + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Eof + additional: "expected `in` after name list" + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-2/error.snap b/full-moon/tests/cases/fail/parser/numeric-for-2/ast.snap similarity index 72% rename from full-moon/tests/cases/fail/parser/numeric-for-2/error.snap rename to full-moon/tests/cases/fail/parser/numeric-for-2/ast.snap index fa0f09c6..547db2e2 100644 --- a/full-moon/tests/cases/fail/parser/numeric-for-2/error.snap +++ b/full-moon/tests/cases/fail/parser/numeric-for-2/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/numeric-for-2 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 7 @@ -16,5 +19,5 @@ UnexpectedToken: character: 8 token_type: type: Eof - additional: expected start expression + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/numeric-for-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/numeric-for-2/ast_to_string.snap new file mode 100644 index 00000000..26c01905 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/numeric-for-2 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-2/error_display.snap b/full-moon/tests/cases/fail/parser/numeric-for-2/error_display.snap new file mode 100644 index 00000000..f73b49c0 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-2/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/numeric-for-2 +--- +error[ast]: expected start expression after `=` + ┌─ source.lua:1:7 + │ +1 │ for x = + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-2/errors.snap b/full-moon/tests/cases/fail/parser/numeric-for-2/errors.snap new file mode 100644 index 00000000..7204f023 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-2/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/numeric-for-2 +--- +- AstError: + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Symbol + symbol: "=" + additional: "expected start expression after `=`" + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-3/error.snap b/full-moon/tests/cases/fail/parser/numeric-for-3/ast.snap similarity index 72% rename from full-moon/tests/cases/fail/parser/numeric-for-3/error.snap rename to full-moon/tests/cases/fail/parser/numeric-for-3/ast.snap index 7eccec07..8fed389e 100644 --- a/full-moon/tests/cases/fail/parser/numeric-for-3/error.snap +++ b/full-moon/tests/cases/fail/parser/numeric-for-3/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/numeric-for-3 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 9 @@ -16,5 +19,5 @@ UnexpectedToken: character: 10 token_type: type: Eof - additional: expected comma + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/numeric-for-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/numeric-for-3/ast_to_string.snap new file mode 100644 index 00000000..4fc0a802 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/numeric-for-3 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-3/error_display.snap b/full-moon/tests/cases/fail/parser/numeric-for-3/error_display.snap new file mode 100644 index 00000000..92002008 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-3/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/numeric-for-3 +--- +error[ast]: expected `,` after start expression + ┌─ source.lua:1:10 + │ +1 │ for x = 1 + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-3/errors.snap b/full-moon/tests/cases/fail/parser/numeric-for-3/errors.snap new file mode 100644 index 00000000..e82f9db0 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-3/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/numeric-for-3 +--- +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Eof + additional: "expected `,` after start expression" + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-4/ast.snap b/full-moon/tests/cases/fail/parser/numeric-for-4/ast.snap new file mode 100644 index 00000000..92be5c7f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-4/ast.snap @@ -0,0 +1,206 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/numeric-for-4 +--- +nodes: + stmts: + - - NumericFor: + for_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: for + trailing_trivia: + - start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Whitespace + characters: " " + index_variable: + leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + start: + Number: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Number + text: "1" + trailing_trivia: [] + start_end_comma: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " + end: + Number: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Number + text: "10" + trailing_trivia: + - start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Whitespace + characters: " " + end_step_comma: ~ + step: ~ + do_token: + leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Symbol + symbol: do + trailing_trivia: [] + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/numeric-for-4/ast_to_string.snap new file mode 100644 index 00000000..aa0a9598 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/numeric-for-4 +--- +"for x = 1, 10 doend" + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-4/error.snap b/full-moon/tests/cases/fail/parser/numeric-for-4/error.snap deleted file mode 100644 index cf31996c..00000000 --- a/full-moon/tests/cases/fail/parser/numeric-for-4/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/numeric-for-4 - ---- -UnexpectedToken: - token: - start_position: - bytes: 16 - line: 1 - character: 17 - end_position: - bytes: 16 - line: 1 - character: 17 - token_type: - type: Eof - additional: "expected 'end'" - diff --git a/full-moon/tests/cases/fail/parser/numeric-for-4/error_display.snap b/full-moon/tests/cases/fail/parser/numeric-for-4/error_display.snap new file mode 100644 index 00000000..d6a94981 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-4/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/numeric-for-4 +--- +error[ast]: expected `end` to close numeric for loop block + ┌─ source.lua:1:15 + │ +1 │ for x = 1, 10 do + │ ^^ + + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-4/errors.snap b/full-moon/tests/cases/fail/parser/numeric-for-4/errors.snap new file mode 100644 index 00000000..5a548ac9 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-4/errors.snap @@ -0,0 +1,26 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/numeric-for-4 +--- +- AstError: + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Eof + additional: "expected `end` to close numeric for loop block" + range: + - bytes: 14 + line: 1 + character: 15 + - bytes: 16 + line: 1 + character: 17 + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-5/ast.snap b/full-moon/tests/cases/fail/parser/numeric-for-5/ast.snap new file mode 100644 index 00000000..2ef9e723 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-5/ast.snap @@ -0,0 +1,68 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/numeric-for-5 +--- +nodes: + stmts: + - - Do: + do_token: + leading_trivia: [] + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 20 + line: 1 + character: 21 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 20 + line: 1 + character: 21 + end_position: + bytes: 21 + line: 1 + character: 22 + token_type: + type: Whitespace + characters: " " + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 21 + line: 1 + character: 22 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 24 + line: 1 + character: 25 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-5/ast_to_string.snap b/full-moon/tests/cases/fail/parser/numeric-for-5/ast_to_string.snap new file mode 100644 index 00000000..1048e85b --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-5/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/numeric-for-5 +--- +do end + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-5/error.snap b/full-moon/tests/cases/fail/parser/numeric-for-5/error.snap deleted file mode 100644 index 1a2bfcc2..00000000 --- a/full-moon/tests/cases/fail/parser/numeric-for-5/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/numeric-for-5 - ---- -UnexpectedToken: - token: - start_position: - bytes: 4 - line: 1 - character: 5 - end_position: - bytes: 9 - line: 1 - character: 10 - token_type: - type: Symbol - symbol: local - additional: expected names - diff --git a/full-moon/tests/cases/fail/parser/numeric-for-5/error_display.snap b/full-moon/tests/cases/fail/parser/numeric-for-5/error_display.snap new file mode 100644 index 00000000..6dd956ac --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-5/error_display.snap @@ -0,0 +1,25 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/numeric-for-5 +--- +error[ast]: expected name after `for` + ┌─ source.lua:1:1 + │ +1 │ for local = 1, 10 do end + │ ^^^ + +error[ast]: expected either a variable name or `function` + ┌─ source.lua:1:11 + │ +1 │ for local = 1, 10 do end + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:11 + │ +1 │ for local = 1, 10 do end + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/numeric-for-5/errors.snap b/full-moon/tests/cases/fail/parser/numeric-for-5/errors.snap new file mode 100644 index 00000000..b9069091 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/numeric-for-5/errors.snap @@ -0,0 +1,48 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/numeric-for-5 +--- +- AstError: + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: for + additional: "expected name after `for`" +- AstError: + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Symbol + symbol: "=" + additional: "expected either a variable name or `function`" +- AstError: + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Symbol + symbol: "=" + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-1/ast.snap b/full-moon/tests/cases/fail/parser/paren-expression-1/ast.snap new file mode 100644 index 00000000..9a618d3f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-1/ast.snap @@ -0,0 +1,54 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/paren-expression-1 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/paren-expression-1/ast_to_string.snap new file mode 100644 index 00000000..4e2df4a0 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/paren-expression-1 +--- +"return " + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-1/error.snap b/full-moon/tests/cases/fail/parser/paren-expression-1/error.snap deleted file mode 100644 index c3b364a8..00000000 --- a/full-moon/tests/cases/fail/parser/paren-expression-1/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/paren-expression-1 - ---- -UnexpectedToken: - token: - start_position: - bytes: 8 - line: 1 - character: 9 - end_position: - bytes: 8 - line: 1 - character: 9 - token_type: - type: Eof - additional: expected expression - diff --git a/full-moon/tests/cases/fail/parser/paren-expression-1/error_display.snap b/full-moon/tests/cases/fail/parser/paren-expression-1/error_display.snap new file mode 100644 index 00000000..3fbcc487 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/paren-expression-1 +--- +error[ast]: expected an expression after `(` + ┌─ source.lua:1:8 + │ +1 │ return ( + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-1/errors.snap b/full-moon/tests/cases/fail/parser/paren-expression-1/errors.snap new file mode 100644 index 00000000..94c958e9 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-1/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/paren-expression-1 +--- +- AstError: + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: ( + additional: "expected an expression after `(`" + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-2/ast.snap b/full-moon/tests/cases/fail/parser/paren-expression-2/ast.snap new file mode 100644 index 00000000..a1bed510 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-2/ast.snap @@ -0,0 +1,143 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/paren-expression-2 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - Punctuated: + - Parentheses: + contained: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + expression: + Number: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Number + text: "3" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Number + text: "4" + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/paren-expression-2/ast_to_string.snap new file mode 100644 index 00000000..7c7b7b3e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/paren-expression-2 +--- +"return (3), 4" + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-2/error.snap b/full-moon/tests/cases/fail/parser/paren-expression-2/error.snap deleted file mode 100644 index 0a3acb43..00000000 --- a/full-moon/tests/cases/fail/parser/paren-expression-2/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/paren-expression-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 9 - line: 1 - character: 10 - end_position: - bytes: 10 - line: 1 - character: 11 - token_type: - type: Symbol - symbol: "," - additional: "expected ')'" - diff --git a/full-moon/tests/cases/fail/parser/paren-expression-2/error_display.snap b/full-moon/tests/cases/fail/parser/paren-expression-2/error_display.snap new file mode 100644 index 00000000..f9bdf548 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-2/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/paren-expression-2 +--- +error[ast]: expected `)` after expression + ┌─ source.lua:1:10 + │ +1 │ return (3, 4 + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-2/errors.snap b/full-moon/tests/cases/fail/parser/paren-expression-2/errors.snap new file mode 100644 index 00000000..87e5d06e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-2/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/paren-expression-2 +--- +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "," + additional: "expected `)` after expression" + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-3/ast.snap b/full-moon/tests/cases/fail/parser/paren-expression-3/ast.snap new file mode 100644 index 00000000..2729875c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-3/ast.snap @@ -0,0 +1,143 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/paren-expression-3 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - Punctuated: + - Parentheses: + contained: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + expression: + Number: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Number + text: "3" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Number + text: "4" + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/paren-expression-3/ast_to_string.snap new file mode 100644 index 00000000..88575f6d --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/paren-expression-3 +--- +"return (3), 4" + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-3/error.snap b/full-moon/tests/cases/fail/parser/paren-expression-3/error.snap deleted file mode 100644 index 87de070f..00000000 --- a/full-moon/tests/cases/fail/parser/paren-expression-3/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/paren-expression-3 - ---- -UnexpectedToken: - token: - start_position: - bytes: 9 - line: 1 - character: 10 - end_position: - bytes: 10 - line: 1 - character: 11 - token_type: - type: Symbol - symbol: "," - additional: "expected ')'" - diff --git a/full-moon/tests/cases/fail/parser/paren-expression-3/error_display.snap b/full-moon/tests/cases/fail/parser/paren-expression-3/error_display.snap new file mode 100644 index 00000000..f71cc90f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-3/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/paren-expression-3 +--- +error[ast]: expected `)` after expression + ┌─ source.lua:1:10 + │ +1 │ return (3, 4, + │ ^ + +error[ast]: trailing commas are not allowed + ┌─ source.lua:1:13 + │ +1 │ return (3, 4, + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-3/errors.snap b/full-moon/tests/cases/fail/parser/paren-expression-3/errors.snap new file mode 100644 index 00000000..39c04a7b --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-3/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/paren-expression-3 +--- +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "," + additional: "expected `)` after expression" +- AstError: + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: "," + additional: trailing commas are not allowed + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-4/ast.snap b/full-moon/tests/cases/fail/parser/paren-expression-4/ast.snap new file mode 100644 index 00000000..81bfc7d2 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-4/ast.snap @@ -0,0 +1,54 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/paren-expression-4 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/paren-expression-4/ast_to_string.snap new file mode 100644 index 00000000..c4512901 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/paren-expression-4 +--- +"return " + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-4/error.snap b/full-moon/tests/cases/fail/parser/paren-expression-4/error.snap deleted file mode 100644 index d3b92dd8..00000000 --- a/full-moon/tests/cases/fail/parser/paren-expression-4/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/paren-expression-4 - ---- -UnexpectedToken: - token: - start_position: - bytes: 8 - line: 1 - character: 9 - end_position: - bytes: 9 - line: 1 - character: 10 - token_type: - type: Symbol - symbol: ) - additional: expected expression - diff --git a/full-moon/tests/cases/fail/parser/paren-expression-4/error_display.snap b/full-moon/tests/cases/fail/parser/paren-expression-4/error_display.snap new file mode 100644 index 00000000..0651705c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-4/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/paren-expression-4 +--- +error[ast]: expected an expression after `(` + ┌─ source.lua:1:8 + │ +1 │ return () + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:9 + │ +1 │ return () + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-4/errors.snap b/full-moon/tests/cases/fail/parser/paren-expression-4/errors.snap new file mode 100644 index 00000000..a8953076 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-4/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/paren-expression-4 +--- +- AstError: + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: ( + additional: "expected an expression after `(`" +- AstError: + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: ) + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-5/ast.snap b/full-moon/tests/cases/fail/parser/paren-expression-5/ast.snap new file mode 100644 index 00000000..19f591f1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-5/ast.snap @@ -0,0 +1,54 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/paren-expression-5 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-5/ast_to_string.snap b/full-moon/tests/cases/fail/parser/paren-expression-5/ast_to_string.snap new file mode 100644 index 00000000..a049d748 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-5/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/paren-expression-5 +--- +"return " + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-5/error.snap b/full-moon/tests/cases/fail/parser/paren-expression-5/error.snap deleted file mode 100644 index 3bc2dbe3..00000000 --- a/full-moon/tests/cases/fail/parser/paren-expression-5/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/paren-expression-5 - ---- -UnexpectedToken: - token: - start_position: - bytes: 8 - line: 1 - character: 9 - end_position: - bytes: 13 - line: 1 - character: 14 - token_type: - type: Symbol - symbol: until - additional: expected expression - diff --git a/full-moon/tests/cases/fail/parser/paren-expression-5/error_display.snap b/full-moon/tests/cases/fail/parser/paren-expression-5/error_display.snap new file mode 100644 index 00000000..f0a08736 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-5/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/paren-expression-5 +--- +error[ast]: expected an expression after `(` + ┌─ source.lua:1:8 + │ +1 │ return (until) + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:9 + │ +1 │ return (until) + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/paren-expression-5/errors.snap b/full-moon/tests/cases/fail/parser/paren-expression-5/errors.snap new file mode 100644 index 00000000..7d3f5179 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/paren-expression-5/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/paren-expression-5 +--- +- AstError: + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: ( + additional: "expected an expression after `(`" +- AstError: + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: until + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-1/ast.snap b/full-moon/tests/cases/fail/parser/repeat-until-1/ast.snap new file mode 100644 index 00000000..f387c3cd --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-1/ast.snap @@ -0,0 +1,79 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/repeat-until-1 +--- +nodes: + stmts: + - - Do: + do_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: [] + end_token: + leading_trivia: + - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 1 + token_type: + type: Whitespace + characters: "\n" + token: + start_position: + bytes: 1 + line: 2 + character: 1 + end_position: + bytes: 4 + line: 2 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/repeat-until-1/ast_to_string.snap new file mode 100644 index 00000000..d400c86a --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/repeat-until-1 +--- +"do\n\nend" + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-1/error.snap b/full-moon/tests/cases/fail/parser/repeat-until-1/error.snap deleted file mode 100644 index b44e5013..00000000 --- a/full-moon/tests/cases/fail/parser/repeat-until-1/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/repeat-until-1 - ---- -UnexpectedToken: - token: - start_position: - bytes: 6 - line: 1 - character: 7 - end_position: - bytes: 6 - line: 1 - character: 7 - token_type: - type: Eof - additional: "expected 'until'" - diff --git a/full-moon/tests/cases/fail/parser/repeat-until-1/error_display.snap b/full-moon/tests/cases/fail/parser/repeat-until-1/error_display.snap new file mode 100644 index 00000000..bbc3c0f3 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/repeat-until-1 +--- +error[ast]: expected `until` after block + ┌─ source.lua:1:7 + │ +1 │ repeat + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-1/errors.snap b/full-moon/tests/cases/fail/parser/repeat-until-1/errors.snap new file mode 100644 index 00000000..f9d9c706 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-1/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/repeat-until-1 +--- +- AstError: + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Eof + additional: "expected `until` after block" + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-2/ast.snap b/full-moon/tests/cases/fail/parser/repeat-until-2/ast.snap new file mode 100644 index 00000000..49243233 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-2/ast.snap @@ -0,0 +1,144 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/repeat-until-2 +--- +nodes: + stmts: + - - Do: + do_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 7 + line: 2 + character: 1 + end_position: + bytes: 8 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 8 + line: 2 + character: 2 + end_position: + bytes: 12 + line: 2 + character: 6 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 12 + line: 2 + character: 6 + end_position: + bytes: 13 + line: 2 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 13 + line: 2 + character: 7 + end_position: + bytes: 14 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: [] + - ~ + end_token: + leading_trivia: + - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 1 + token_type: + type: Whitespace + characters: "\n" + token: + start_position: + bytes: 1 + line: 2 + character: 1 + end_position: + bytes: 4 + line: 2 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 14 + line: 2 + character: 8 + end_position: + bytes: 14 + line: 2 + character: 8 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/repeat-until-2/ast_to_string.snap new file mode 100644 index 00000000..18da7d66 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/repeat-until-2 +--- +"do\n\tcall()\nend" + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-2/error.snap b/full-moon/tests/cases/fail/parser/repeat-until-2/error.snap deleted file mode 100644 index 45692cbc..00000000 --- a/full-moon/tests/cases/fail/parser/repeat-until-2/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/repeat-until-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 14 - line: 2 - character: 8 - end_position: - bytes: 14 - line: 2 - character: 8 - token_type: - type: Eof - additional: "expected 'until'" - diff --git a/full-moon/tests/cases/fail/parser/repeat-until-2/error_display.snap b/full-moon/tests/cases/fail/parser/repeat-until-2/error_display.snap new file mode 100644 index 00000000..df4d7506 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-2/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/repeat-until-2 +--- +error[ast]: expected `until` after block + ┌─ source.lua:2:8 + │ +2 │ call() + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-2/errors.snap b/full-moon/tests/cases/fail/parser/repeat-until-2/errors.snap new file mode 100644 index 00000000..d3726ae8 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-2/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/repeat-until-2 +--- +- AstError: + token: + start_position: + bytes: 14 + line: 2 + character: 8 + end_position: + bytes: 14 + line: 2 + character: 8 + token_type: + type: Eof + additional: "expected `until` after block" + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-3/ast.snap b/full-moon/tests/cases/fail/parser/repeat-until-3/ast.snap new file mode 100644 index 00000000..1ba3b873 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-3/ast.snap @@ -0,0 +1,155 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/repeat-until-3 +--- +nodes: + stmts: + - - Do: + do_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 7 + line: 2 + character: 1 + end_position: + bytes: 8 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 8 + line: 2 + character: 2 + end_position: + bytes: 12 + line: 2 + character: 6 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 12 + line: 2 + character: 6 + end_position: + bytes: 13 + line: 2 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 13 + line: 2 + character: 7 + end_position: + bytes: 14 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 14 + line: 2 + character: 8 + end_position: + bytes: 15 + line: 2 + character: 8 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: [] + - ~ + end_token: + leading_trivia: + - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 1 + token_type: + type: Whitespace + characters: "\n" + token: + start_position: + bytes: 1 + line: 2 + character: 1 + end_position: + bytes: 4 + line: 2 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 20 + line: 3 + character: 6 + end_position: + bytes: 20 + line: 3 + character: 6 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/repeat-until-3/ast_to_string.snap new file mode 100644 index 00000000..4859ec1e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/repeat-until-3 +--- +"do\n\tcall()\n\nend" + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-3/error.snap b/full-moon/tests/cases/fail/parser/repeat-until-3/error.snap deleted file mode 100644 index 47af4ec5..00000000 --- a/full-moon/tests/cases/fail/parser/repeat-until-3/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/repeat-until-3 - ---- -UnexpectedToken: - token: - start_position: - bytes: 20 - line: 3 - character: 6 - end_position: - bytes: 20 - line: 3 - character: 6 - token_type: - type: Eof - additional: expected condition - diff --git a/full-moon/tests/cases/fail/parser/repeat-until-3/error_display.snap b/full-moon/tests/cases/fail/parser/repeat-until-3/error_display.snap new file mode 100644 index 00000000..d0769759 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-3/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/repeat-until-3 +--- +error[ast]: expected a condition after `until` + ┌─ source.lua:3:1 + │ +3 │ until + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-3/errors.snap b/full-moon/tests/cases/fail/parser/repeat-until-3/errors.snap new file mode 100644 index 00000000..babdc5f4 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-3/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/repeat-until-3 +--- +- AstError: + token: + start_position: + bytes: 15 + line: 3 + character: 1 + end_position: + bytes: 20 + line: 3 + character: 6 + token_type: + type: Symbol + symbol: until + additional: "expected a condition after `until`" + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-4/ast.snap b/full-moon/tests/cases/fail/parser/repeat-until-4/ast.snap new file mode 100644 index 00000000..6e35709d --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-4/ast.snap @@ -0,0 +1,155 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/repeat-until-4 +--- +nodes: + stmts: + - - Do: + do_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 7 + line: 2 + character: 1 + end_position: + bytes: 8 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 8 + line: 2 + character: 2 + end_position: + bytes: 12 + line: 2 + character: 6 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 12 + line: 2 + character: 6 + end_position: + bytes: 13 + line: 2 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 13 + line: 2 + character: 7 + end_position: + bytes: 14 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 14 + line: 2 + character: 8 + end_position: + bytes: 15 + line: 2 + character: 8 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: [] + - ~ + end_token: + leading_trivia: + - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 1 + token_type: + type: Whitespace + characters: "\n" + token: + start_position: + bytes: 1 + line: 2 + character: 1 + end_position: + bytes: 4 + line: 2 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 24 + line: 3 + character: 10 + end_position: + bytes: 24 + line: 3 + character: 10 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/repeat-until-4/ast_to_string.snap new file mode 100644 index 00000000..975a9000 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/repeat-until-4 +--- +"do\n\tcall()\n\nend" + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-4/error.snap b/full-moon/tests/cases/fail/parser/repeat-until-4/error.snap deleted file mode 100644 index 7c4f9096..00000000 --- a/full-moon/tests/cases/fail/parser/repeat-until-4/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/repeat-until-4 - ---- -UnexpectedToken: - token: - start_position: - bytes: 21 - line: 3 - character: 7 - end_position: - bytes: 24 - line: 3 - character: 10 - token_type: - type: Symbol - symbol: end - additional: expected condition - diff --git a/full-moon/tests/cases/fail/parser/repeat-until-4/error_display.snap b/full-moon/tests/cases/fail/parser/repeat-until-4/error_display.snap new file mode 100644 index 00000000..39b0e166 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-4/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/repeat-until-4 +--- +error[ast]: expected a condition after `until` + ┌─ source.lua:3:1 + │ +3 │ until end + │ ^^^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:3:7 + │ +3 │ until end + │ ^^^ + + diff --git a/full-moon/tests/cases/fail/parser/repeat-until-4/errors.snap b/full-moon/tests/cases/fail/parser/repeat-until-4/errors.snap new file mode 100644 index 00000000..03319562 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/repeat-until-4/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/repeat-until-4 +--- +- AstError: + token: + start_position: + bytes: 15 + line: 3 + character: 1 + end_position: + bytes: 20 + line: 3 + character: 6 + token_type: + type: Symbol + symbol: until + additional: "expected a condition after `until`" +- AstError: + token: + start_position: + bytes: 21 + line: 3 + character: 7 + end_position: + bytes: 24 + line: 3 + character: 10 + token_type: + type: Symbol + symbol: end + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/table-1/ast.snap b/full-moon/tests/cases/fail/parser/table-1/ast.snap new file mode 100644 index 00000000..58b9d344 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-1/ast.snap @@ -0,0 +1,88 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/table-1 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + TableConstructor: + braces: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "{" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: "}" + trailing_trivia: [] + fields: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/table-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/table-1/ast_to_string.snap new file mode 100644 index 00000000..dbf93c51 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/table-1 +--- +"return {}" + diff --git a/full-moon/tests/cases/fail/parser/table-1/error.snap b/full-moon/tests/cases/fail/parser/table-1/error.snap deleted file mode 100644 index 9215a0bd..00000000 --- a/full-moon/tests/cases/fail/parser/table-1/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/table-1 - ---- -UnexpectedToken: - token: - start_position: - bytes: 8 - line: 1 - character: 9 - end_position: - bytes: 8 - line: 1 - character: 9 - token_type: - type: Eof - additional: "expected '}'" - diff --git a/full-moon/tests/cases/fail/parser/table-1/error_display.snap b/full-moon/tests/cases/fail/parser/table-1/error_display.snap new file mode 100644 index 00000000..7ad52e5f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/table-1 +--- +error[ast]: expected a field + ┌─ source.lua:1:8 + │ +1 │ return { + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/table-1/errors.snap b/full-moon/tests/cases/fail/parser/table-1/errors.snap new file mode 100644 index 00000000..77ace4f1 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-1/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/table-1 +--- +- AstError: + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "{" + additional: expected a field + diff --git a/full-moon/tests/cases/fail/parser/table-2/ast.snap b/full-moon/tests/cases/fail/parser/table-2/ast.snap new file mode 100644 index 00000000..3a606172 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-2/ast.snap @@ -0,0 +1,194 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/table-2 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + TableConstructor: + braces: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "{" + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: "\n" + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: "}" + trailing_trivia: [] + fields: + pairs: + - Punctuated: + - NameKey: + key: + leading_trivia: + - start_position: + bytes: 9 + line: 2 + character: 1 + end_position: + bytes: 10 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 10 + line: 2 + character: 2 + end_position: + bytes: 11 + line: 2 + character: 3 + token_type: + type: Identifier + identifier: a + trailing_trivia: + - start_position: + bytes: 11 + line: 2 + character: 3 + end_position: + bytes: 12 + line: 2 + character: 4 + token_type: + type: Whitespace + characters: " " + equal: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 2 + character: 4 + end_position: + bytes: 13 + line: 2 + character: 5 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 13 + line: 2 + character: 5 + end_position: + bytes: 14 + line: 2 + character: 6 + token_type: + type: Whitespace + characters: " " + value: + Number: + leading_trivia: [] + token: + start_position: + bytes: 14 + line: 2 + character: 6 + end_position: + bytes: 15 + line: 2 + character: 7 + token_type: + type: Number + text: "1" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 15 + line: 2 + character: 7 + end_position: + bytes: 16 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: "," + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 2 + character: 8 + end_position: + bytes: 16 + line: 2 + character: 8 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/table-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/table-2/ast_to_string.snap new file mode 100644 index 00000000..12b33603 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/table-2 +--- +"return {\n\ta = 1,}" + diff --git a/full-moon/tests/cases/fail/parser/table-2/error.snap b/full-moon/tests/cases/fail/parser/table-2/error.snap deleted file mode 100644 index 71d3d36a..00000000 --- a/full-moon/tests/cases/fail/parser/table-2/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/table-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 16 - line: 2 - character: 8 - end_position: - bytes: 16 - line: 2 - character: 8 - token_type: - type: Eof - additional: "expected '}'" - diff --git a/full-moon/tests/cases/fail/parser/table-2/error_display.snap b/full-moon/tests/cases/fail/parser/table-2/error_display.snap new file mode 100644 index 00000000..0951cb02 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-2/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/table-2 +--- +error[ast]: expected a field + ┌─ source.lua:2:6 + │ +2 │ a = 1, + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/table-2/errors.snap b/full-moon/tests/cases/fail/parser/table-2/errors.snap new file mode 100644 index 00000000..2f301a96 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-2/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/table-2 +--- +- AstError: + token: + start_position: + bytes: 14 + line: 2 + character: 6 + end_position: + bytes: 15 + line: 2 + character: 7 + token_type: + type: Number + text: "1" + additional: expected a field + diff --git a/full-moon/tests/cases/fail/parser/table-3/ast.snap b/full-moon/tests/cases/fail/parser/table-3/ast.snap new file mode 100644 index 00000000..89fa7152 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-3/ast.snap @@ -0,0 +1,99 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/table-3 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + TableConstructor: + braces: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "{" + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: "\n" + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: "}" + trailing_trivia: [] + fields: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 13 + line: 2 + character: 5 + end_position: + bytes: 13 + line: 2 + character: 5 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/table-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/table-3/ast_to_string.snap new file mode 100644 index 00000000..5581e3f5 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/table-3 +--- +"return {\n}" + diff --git a/full-moon/tests/cases/fail/parser/table-3/error.snap b/full-moon/tests/cases/fail/parser/table-3/error.snap deleted file mode 100644 index 5e211053..00000000 --- a/full-moon/tests/cases/fail/parser/table-3/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/table-3 - ---- -UnexpectedToken: - token: - start_position: - bytes: 13 - line: 2 - character: 5 - end_position: - bytes: 13 - line: 2 - character: 5 - token_type: - type: Eof - additional: expected value - diff --git a/full-moon/tests/cases/fail/parser/table-3/error_display.snap b/full-moon/tests/cases/fail/parser/table-3/error_display.snap new file mode 100644 index 00000000..7608225a --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-3/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/table-3 +--- +error[ast]: expected an expression after `=` + ┌─ source.lua:2:4 + │ +2 │ a = + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/table-3/errors.snap b/full-moon/tests/cases/fail/parser/table-3/errors.snap new file mode 100644 index 00000000..8374a65d --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-3/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/table-3 +--- +- AstError: + token: + start_position: + bytes: 12 + line: 2 + character: 4 + end_position: + bytes: 13 + line: 2 + character: 5 + token_type: + type: Symbol + symbol: "=" + additional: "expected an expression after `=`" + diff --git a/full-moon/tests/cases/fail/parser/table-4/ast.snap b/full-moon/tests/cases/fail/parser/table-4/ast.snap new file mode 100644 index 00000000..d96f796a --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-4/ast.snap @@ -0,0 +1,99 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/table-4 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + TableConstructor: + braces: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "{" + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: "}" + trailing_trivia: [] + fields: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/table-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/table-4/ast_to_string.snap new file mode 100644 index 00000000..05eb8039 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/table-4 +--- +"return { }" + diff --git a/full-moon/tests/cases/fail/parser/table-4/error.snap b/full-moon/tests/cases/fail/parser/table-4/error.snap deleted file mode 100644 index d6352c0d..00000000 --- a/full-moon/tests/cases/fail/parser/table-4/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/table-4 - ---- -UnexpectedToken: - token: - start_position: - bytes: 9 - line: 1 - character: 10 - end_position: - bytes: 14 - line: 1 - character: 15 - token_type: - type: Symbol - symbol: until - additional: "expected '}'" - diff --git a/full-moon/tests/cases/fail/parser/table-4/error_display.snap b/full-moon/tests/cases/fail/parser/table-4/error_display.snap new file mode 100644 index 00000000..7b159525 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-4/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/table-4 +--- +error[ast]: expected a field + ┌─ source.lua:1:8 + │ +1 │ return { until } + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:10 + │ +1 │ return { until } + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/table-4/errors.snap b/full-moon/tests/cases/fail/parser/table-4/errors.snap new file mode 100644 index 00000000..f33beb1a --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-4/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/table-4 +--- +- AstError: + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "{" + additional: expected a field +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: until + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/table-5/ast.snap b/full-moon/tests/cases/fail/parser/table-5/ast.snap new file mode 100644 index 00000000..9cf4e570 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-5/ast.snap @@ -0,0 +1,99 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/table-5 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + TableConstructor: + braces: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "{" + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: "\n" + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: "}" + trailing_trivia: [] + fields: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 22 + line: 3 + character: 2 + end_position: + bytes: 22 + line: 3 + character: 2 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/table-5/ast_to_string.snap b/full-moon/tests/cases/fail/parser/table-5/ast_to_string.snap new file mode 100644 index 00000000..455fea7e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-5/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/table-5 +--- +"return {\n}" + diff --git a/full-moon/tests/cases/fail/parser/table-5/error.snap b/full-moon/tests/cases/fail/parser/table-5/error.snap deleted file mode 100644 index 8151d304..00000000 --- a/full-moon/tests/cases/fail/parser/table-5/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/table-5 - ---- -UnexpectedToken: - token: - start_position: - bytes: 10 - line: 2 - character: 2 - end_position: - bytes: 15 - line: 2 - character: 7 - token_type: - type: Symbol - symbol: until - additional: "expected '}'" - diff --git a/full-moon/tests/cases/fail/parser/table-5/error_display.snap b/full-moon/tests/cases/fail/parser/table-5/error_display.snap new file mode 100644 index 00000000..121aee3c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-5/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/table-5 +--- +error[ast]: expected a field + ┌─ source.lua:1:8 + │ +1 │ return { + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:2 + │ +2 │ until = 1, + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/table-5/errors.snap b/full-moon/tests/cases/fail/parser/table-5/errors.snap new file mode 100644 index 00000000..5d2d3d61 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-5/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/table-5 +--- +- AstError: + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "{" + additional: expected a field +- AstError: + token: + start_position: + bytes: 10 + line: 2 + character: 2 + end_position: + bytes: 15 + line: 2 + character: 7 + token_type: + type: Symbol + symbol: until + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/table-6/ast.snap b/full-moon/tests/cases/fail/parser/table-6/ast.snap new file mode 100644 index 00000000..4505fdaf --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-6/ast.snap @@ -0,0 +1,99 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/table-6 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + TableConstructor: + braces: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "{" + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: "\n" + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: "}" + trailing_trivia: [] + fields: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 22 + line: 3 + character: 2 + end_position: + bytes: 22 + line: 3 + character: 2 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/table-6/ast_to_string.snap b/full-moon/tests/cases/fail/parser/table-6/ast_to_string.snap new file mode 100644 index 00000000..3b436b06 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-6/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/table-6 +--- +"return {\n}" + diff --git a/full-moon/tests/cases/fail/parser/table-6/error.snap b/full-moon/tests/cases/fail/parser/table-6/error.snap deleted file mode 100644 index 594df63d..00000000 --- a/full-moon/tests/cases/fail/parser/table-6/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/table-6 - ---- -UnexpectedToken: - token: - start_position: - bytes: 14 - line: 2 - character: 6 - end_position: - bytes: 19 - line: 2 - character: 11 - token_type: - type: Symbol - symbol: until - additional: expected value - diff --git a/full-moon/tests/cases/fail/parser/table-6/error_display.snap b/full-moon/tests/cases/fail/parser/table-6/error_display.snap new file mode 100644 index 00000000..286e8f6f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-6/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/table-6 +--- +error[ast]: expected an expression after `=` + ┌─ source.lua:2:4 + │ +2 │ x = until, + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:6 + │ +2 │ x = until, + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/table-6/errors.snap b/full-moon/tests/cases/fail/parser/table-6/errors.snap new file mode 100644 index 00000000..e553ca92 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-6/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/table-6 +--- +- AstError: + token: + start_position: + bytes: 12 + line: 2 + character: 4 + end_position: + bytes: 13 + line: 2 + character: 5 + token_type: + type: Symbol + symbol: "=" + additional: "expected an expression after `=`" +- AstError: + token: + start_position: + bytes: 14 + line: 2 + character: 6 + end_position: + bytes: 19 + line: 2 + character: 11 + token_type: + type: Symbol + symbol: until + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/table-7/ast.snap b/full-moon/tests/cases/fail/parser/table-7/ast.snap new file mode 100644 index 00000000..b243fc3c --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-7/ast.snap @@ -0,0 +1,99 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/table-7 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + TableConstructor: + braces: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "{" + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: "\n" + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: "}" + trailing_trivia: [] + fields: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 27 + line: 3 + character: 2 + end_position: + bytes: 27 + line: 3 + character: 2 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/table-7/ast_to_string.snap b/full-moon/tests/cases/fail/parser/table-7/ast_to_string.snap new file mode 100644 index 00000000..3086fd52 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-7/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/table-7 +--- +"return {\n}" + diff --git a/full-moon/tests/cases/fail/parser/table-7/error.snap b/full-moon/tests/cases/fail/parser/table-7/error.snap deleted file mode 100644 index 53a63532..00000000 --- a/full-moon/tests/cases/fail/parser/table-7/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/table-7 - ---- -UnexpectedToken: - token: - start_position: - bytes: 11 - line: 2 - character: 3 - end_position: - bytes: 16 - line: 2 - character: 8 - token_type: - type: Symbol - symbol: until - additional: expected key - diff --git a/full-moon/tests/cases/fail/parser/table-7/error_display.snap b/full-moon/tests/cases/fail/parser/table-7/error_display.snap new file mode 100644 index 00000000..cc620248 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-7/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/table-7 +--- +error[ast]: expected an expression after `[` + ┌─ source.lua:2:2 + │ +2 │ [until] = true, + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:3 + │ +2 │ [until] = true, + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/table-7/errors.snap b/full-moon/tests/cases/fail/parser/table-7/errors.snap new file mode 100644 index 00000000..b83763dc --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-7/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/table-7 +--- +- AstError: + token: + start_position: + bytes: 10 + line: 2 + character: 2 + end_position: + bytes: 11 + line: 2 + character: 3 + token_type: + type: Symbol + symbol: "[" + additional: "expected an expression after `[`" +- AstError: + token: + start_position: + bytes: 11 + line: 2 + character: 3 + end_position: + bytes: 16 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: until + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/table-8/ast.snap b/full-moon/tests/cases/fail/parser/table-8/ast.snap new file mode 100644 index 00000000..0f781755 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-8/ast.snap @@ -0,0 +1,99 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/table-8 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + TableConstructor: + braces: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "{" + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: "\n" + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: "}" + trailing_trivia: [] + fields: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 19 + line: 3 + character: 2 + end_position: + bytes: 19 + line: 3 + character: 2 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/table-8/ast_to_string.snap b/full-moon/tests/cases/fail/parser/table-8/ast_to_string.snap new file mode 100644 index 00000000..d3ffb123 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-8/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/table-8 +--- +"return {\n}" + diff --git a/full-moon/tests/cases/fail/parser/table-8/error.snap b/full-moon/tests/cases/fail/parser/table-8/error.snap deleted file mode 100644 index 56b2ccec..00000000 --- a/full-moon/tests/cases/fail/parser/table-8/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/table-8 - ---- -UnexpectedToken: - token: - start_position: - bytes: 11 - line: 2 - character: 3 - end_position: - bytes: 12 - line: 2 - character: 4 - token_type: - type: Symbol - symbol: "]" - additional: expected key - diff --git a/full-moon/tests/cases/fail/parser/table-8/error_display.snap b/full-moon/tests/cases/fail/parser/table-8/error_display.snap new file mode 100644 index 00000000..bc85e288 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-8/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/table-8 +--- +error[ast]: expected an expression after `[` + ┌─ source.lua:2:2 + │ +2 │ [] = 1, + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:3 + │ +2 │ [] = 1, + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/table-8/errors.snap b/full-moon/tests/cases/fail/parser/table-8/errors.snap new file mode 100644 index 00000000..c7358df8 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-8/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/table-8 +--- +- AstError: + token: + start_position: + bytes: 10 + line: 2 + character: 2 + end_position: + bytes: 11 + line: 2 + character: 3 + token_type: + type: Symbol + symbol: "[" + additional: "expected an expression after `[`" +- AstError: + token: + start_position: + bytes: 11 + line: 2 + character: 3 + end_position: + bytes: 12 + line: 2 + character: 4 + token_type: + type: Symbol + symbol: "]" + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/table-9/ast.snap b/full-moon/tests/cases/fail/parser/table-9/ast.snap new file mode 100644 index 00000000..9aa867fc --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-9/ast.snap @@ -0,0 +1,152 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 23 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/table-9 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + TableConstructor: + braces: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Symbol + symbol: "{" + trailing_trivia: + - start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: "\n" + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: "}" + trailing_trivia: [] + fields: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 28 + line: 4 + character: 1 + end_position: + bytes: 28 + line: 4 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/table-9/ast_to_string.snap b/full-moon/tests/cases/fail/parser/table-9/ast_to_string.snap new file mode 100644 index 00000000..2de4e247 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-9/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/table-9 +--- +"local x = {\n}" + diff --git a/full-moon/tests/cases/fail/parser/table-9/error_display.snap b/full-moon/tests/cases/fail/parser/table-9/error_display.snap new file mode 100644 index 00000000..72573f05 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-9/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/table-9 +--- +error[ast]: expected `]` after expression + ┌─ source.lua:2:2 + │ +2 │ [a.b.c = 10, + │ ^^^^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:9 + │ +2 │ [a.b.c = 10, + │ ^ + + diff --git a/full-moon/tests/cases/fail/parser/table-9/errors.snap b/full-moon/tests/cases/fail/parser/table-9/errors.snap new file mode 100644 index 00000000..ccf239f3 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-9/errors.snap @@ -0,0 +1,41 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/table-9 +--- +- AstError: + token: + start_position: + bytes: 20 + line: 2 + character: 9 + end_position: + bytes: 21 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: "=" + additional: "expected `]` after expression" + range: + - bytes: 13 + line: 2 + character: 2 + - bytes: 19 + line: 2 + character: 8 +- AstError: + token: + start_position: + bytes: 20 + line: 2 + character: 9 + end_position: + bytes: 21 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: "=" + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/table-9/source.lua b/full-moon/tests/cases/fail/parser/table-9/source.lua new file mode 100644 index 00000000..6542bbab --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-9/source.lua @@ -0,0 +1,3 @@ +local x = { + [a.b.c = 10, +} diff --git a/full-moon/tests/cases/fail/parser/table-9/tokens.snap b/full-moon/tests/cases/fail/parser/table-9/tokens.snap new file mode 100644 index 00000000..73062431 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/table-9/tokens.snap @@ -0,0 +1,270 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 68 +expression: tokens +input_file: full-moon/tests/cases/fail/parser/table-9 +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local +- start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x +- start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Symbol + symbol: "{" +- start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 12 + line: 2 + character: 1 + end_position: + bytes: 13 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" +- start_position: + bytes: 13 + line: 2 + character: 2 + end_position: + bytes: 14 + line: 2 + character: 3 + token_type: + type: Symbol + symbol: "[" +- start_position: + bytes: 14 + line: 2 + character: 3 + end_position: + bytes: 15 + line: 2 + character: 4 + token_type: + type: Identifier + identifier: a +- start_position: + bytes: 15 + line: 2 + character: 4 + end_position: + bytes: 16 + line: 2 + character: 5 + token_type: + type: Symbol + symbol: "." +- start_position: + bytes: 16 + line: 2 + character: 5 + end_position: + bytes: 17 + line: 2 + character: 6 + token_type: + type: Identifier + identifier: b +- start_position: + bytes: 17 + line: 2 + character: 6 + end_position: + bytes: 18 + line: 2 + character: 7 + token_type: + type: Symbol + symbol: "." +- start_position: + bytes: 18 + line: 2 + character: 7 + end_position: + bytes: 19 + line: 2 + character: 8 + token_type: + type: Identifier + identifier: c +- start_position: + bytes: 19 + line: 2 + character: 8 + end_position: + bytes: 20 + line: 2 + character: 9 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 20 + line: 2 + character: 9 + end_position: + bytes: 21 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 21 + line: 2 + character: 10 + end_position: + bytes: 22 + line: 2 + character: 11 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 22 + line: 2 + character: 11 + end_position: + bytes: 24 + line: 2 + character: 13 + token_type: + type: Number + text: "10" +- start_position: + bytes: 24 + line: 2 + character: 13 + end_position: + bytes: 25 + line: 2 + character: 14 + token_type: + type: Symbol + symbol: "," +- start_position: + bytes: 25 + line: 2 + character: 14 + end_position: + bytes: 26 + line: 2 + character: 14 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 26 + line: 3 + character: 1 + end_position: + bytes: 27 + line: 3 + character: 2 + token_type: + type: Symbol + symbol: "}" +- start_position: + bytes: 27 + line: 3 + character: 2 + end_position: + bytes: 28 + line: 3 + character: 2 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 28 + line: 4 + character: 1 + end_position: + bytes: 28 + line: 4 + character: 1 + token_type: + type: Eof + diff --git a/full-moon/tests/cases/fail/parser/un-op-1/ast.snap b/full-moon/tests/cases/fail/parser/un-op-1/ast.snap new file mode 100644 index 00000000..5d28823b --- /dev/null +++ b/full-moon/tests/cases/fail/parser/un-op-1/ast.snap @@ -0,0 +1,54 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/un-op-1 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/un-op-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/un-op-1/ast_to_string.snap new file mode 100644 index 00000000..881c33f3 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/un-op-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/un-op-1 +--- +"return " + diff --git a/full-moon/tests/cases/fail/parser/un-op-1/error.snap b/full-moon/tests/cases/fail/parser/un-op-1/error.snap deleted file mode 100644 index 17a424b3..00000000 --- a/full-moon/tests/cases/fail/parser/un-op-1/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/un-op-1 - ---- -UnexpectedToken: - token: - start_position: - bytes: 10 - line: 1 - character: 11 - end_position: - bytes: 10 - line: 1 - character: 11 - token_type: - type: Eof - additional: expected expression - diff --git a/full-moon/tests/cases/fail/parser/un-op-1/error_display.snap b/full-moon/tests/cases/fail/parser/un-op-1/error_display.snap new file mode 100644 index 00000000..f2790f98 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/un-op-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/un-op-1 +--- +error[ast]: expected an expression after not + ┌─ source.lua:1:8 + │ +1 │ return not + │ ^^^ + + diff --git a/full-moon/tests/cases/fail/parser/un-op-1/errors.snap b/full-moon/tests/cases/fail/parser/un-op-1/errors.snap new file mode 100644 index 00000000..859b418d --- /dev/null +++ b/full-moon/tests/cases/fail/parser/un-op-1/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/un-op-1 +--- +- AstError: + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: not + additional: expected an expression after not + diff --git a/full-moon/tests/cases/fail/parser/un-op-2/ast.snap b/full-moon/tests/cases/fail/parser/un-op-2/ast.snap new file mode 100644 index 00000000..d2570e5f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/un-op-2/ast.snap @@ -0,0 +1,54 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/un-op-2 +--- +nodes: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Whitespace + characters: " " + returns: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/un-op-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/un-op-2/ast_to_string.snap new file mode 100644 index 00000000..b3bbbfa0 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/un-op-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/un-op-2 +--- +"return " + diff --git a/full-moon/tests/cases/fail/parser/un-op-2/error.snap b/full-moon/tests/cases/fail/parser/un-op-2/error.snap deleted file mode 100644 index 64e024bf..00000000 --- a/full-moon/tests/cases/fail/parser/un-op-2/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/un-op-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 11 - line: 1 - character: 12 - end_position: - bytes: 14 - line: 1 - character: 15 - token_type: - type: Symbol - symbol: end - additional: expected expression - diff --git a/full-moon/tests/cases/fail/parser/un-op-2/error_display.snap b/full-moon/tests/cases/fail/parser/un-op-2/error_display.snap new file mode 100644 index 00000000..dd20efda --- /dev/null +++ b/full-moon/tests/cases/fail/parser/un-op-2/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/un-op-2 +--- +error[ast]: expected an expression after not + ┌─ source.lua:1:8 + │ +1 │ return not end + │ ^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:12 + │ +1 │ return not end + │ ^^^ + + diff --git a/full-moon/tests/cases/fail/parser/un-op-2/errors.snap b/full-moon/tests/cases/fail/parser/un-op-2/errors.snap new file mode 100644 index 00000000..c08fea06 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/un-op-2/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/un-op-2 +--- +- AstError: + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: not + additional: expected an expression after not +- AstError: + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: end + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/while-1/error.snap b/full-moon/tests/cases/fail/parser/while-1/ast.snap similarity index 71% rename from full-moon/tests/cases/fail/parser/while-1/error.snap rename to full-moon/tests/cases/fail/parser/while-1/ast.snap index 87665b4f..6a48f01d 100644 --- a/full-moon/tests/cases/fail/parser/while-1/error.snap +++ b/full-moon/tests/cases/fail/parser/while-1/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 27 +expression: result.ast input_file: full-moon/tests/cases/fail/parser/while-1 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 5 @@ -16,5 +19,5 @@ UnexpectedToken: character: 6 token_type: type: Eof - additional: expected condition + trailing_trivia: [] diff --git a/full-moon/tests/cases/fail/parser/while-1/ast_to_string.snap b/full-moon/tests/cases/fail/parser/while-1/ast_to_string.snap new file mode 100644 index 00000000..beefc6e2 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/while-1 +--- +"" + diff --git a/full-moon/tests/cases/fail/parser/while-1/error_display.snap b/full-moon/tests/cases/fail/parser/while-1/error_display.snap new file mode 100644 index 00000000..48e07b49 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/while-1 +--- +error[ast]: expected a condition after `while` + ┌─ source.lua:1:1 + │ +1 │ while + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/while-1/errors.snap b/full-moon/tests/cases/fail/parser/while-1/errors.snap new file mode 100644 index 00000000..d8515702 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-1/errors.snap @@ -0,0 +1,20 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/while-1 +--- +- AstError: + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: while + additional: "expected a condition after `while`" + diff --git a/full-moon/tests/cases/fail/parser/while-2/ast.snap b/full-moon/tests/cases/fail/parser/while-2/ast.snap new file mode 100644 index 00000000..adaf1c40 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-2/ast.snap @@ -0,0 +1,68 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/while-2 +--- +nodes: + stmts: + - - Do: + do_token: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/while-2/ast_to_string.snap b/full-moon/tests/cases/fail/parser/while-2/ast_to_string.snap new file mode 100644 index 00000000..3f5daac5 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/while-2 +--- +do end + diff --git a/full-moon/tests/cases/fail/parser/while-2/error.snap b/full-moon/tests/cases/fail/parser/while-2/error.snap deleted file mode 100644 index c5752d23..00000000 --- a/full-moon/tests/cases/fail/parser/while-2/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/while-2 - ---- -UnexpectedToken: - token: - start_position: - bytes: 6 - line: 1 - character: 7 - end_position: - bytes: 11 - line: 1 - character: 12 - token_type: - type: Symbol - symbol: until - additional: expected condition - diff --git a/full-moon/tests/cases/fail/parser/while-2/error_display.snap b/full-moon/tests/cases/fail/parser/while-2/error_display.snap new file mode 100644 index 00000000..e9620dbd --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-2/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/while-2 +--- +error[ast]: expected a condition after `while` + ┌─ source.lua:1:1 + │ +1 │ while until do end + │ ^^^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:7 + │ +1 │ while until do end + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/while-2/errors.snap b/full-moon/tests/cases/fail/parser/while-2/errors.snap new file mode 100644 index 00000000..b7c0b69f --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-2/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/while-2 +--- +- AstError: + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: while + additional: "expected a condition after `while`" +- AstError: + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Symbol + symbol: until + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/parser/while-3/ast.snap b/full-moon/tests/cases/fail/parser/while-3/ast.snap new file mode 100644 index 00000000..b7c92c2e --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-3/ast.snap @@ -0,0 +1,186 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/while-3 +--- +nodes: + stmts: + - - While: + while_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: while + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + condition: + Symbol: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "true" + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " + do_token: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 14 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 14 + line: 2 + character: 1 + end_position: + bytes: 15 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 15 + line: 2 + character: 2 + end_position: + bytes: 19 + line: 2 + character: 6 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 19 + line: 2 + character: 6 + end_position: + bytes: 20 + line: 2 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 20 + line: 2 + character: 7 + end_position: + bytes: 21 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: [] + - ~ + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 21 + line: 2 + character: 8 + end_position: + bytes: 21 + line: 2 + character: 8 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/while-3/ast_to_string.snap b/full-moon/tests/cases/fail/parser/while-3/ast_to_string.snap new file mode 100644 index 00000000..8e0097b5 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-3/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/while-3 +--- +"while true do\n\tcall()end" + diff --git a/full-moon/tests/cases/fail/parser/while-3/error.snap b/full-moon/tests/cases/fail/parser/while-3/error.snap deleted file mode 100644 index 844405a3..00000000 --- a/full-moon/tests/cases/fail/parser/while-3/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/while-3 - ---- -UnexpectedToken: - token: - start_position: - bytes: 21 - line: 2 - character: 8 - end_position: - bytes: 21 - line: 2 - character: 8 - token_type: - type: Eof - additional: "expected 'end'" - diff --git a/full-moon/tests/cases/fail/parser/while-3/error_display.snap b/full-moon/tests/cases/fail/parser/while-3/error_display.snap new file mode 100644 index 00000000..ded292d9 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-3/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/while-3 +--- +error[ast]: expected `end` to close while loop block + ┌─ source.lua:2:2 + │ +2 │ call() + │ ^^^^^^ + + diff --git a/full-moon/tests/cases/fail/parser/while-3/errors.snap b/full-moon/tests/cases/fail/parser/while-3/errors.snap new file mode 100644 index 00000000..772a07f7 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-3/errors.snap @@ -0,0 +1,26 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/while-3 +--- +- AstError: + token: + start_position: + bytes: 21 + line: 2 + character: 8 + end_position: + bytes: 21 + line: 2 + character: 8 + token_type: + type: Eof + additional: "expected `end` to close while loop block" + range: + - bytes: 15 + line: 2 + character: 2 + - bytes: 21 + line: 2 + character: 8 + diff --git a/full-moon/tests/cases/fail/parser/while-4/ast.snap b/full-moon/tests/cases/fail/parser/while-4/ast.snap new file mode 100644 index 00000000..1333b843 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-4/ast.snap @@ -0,0 +1,219 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 27 +expression: result.ast +input_file: full-moon/tests/cases/fail/parser/while-4 +--- +nodes: + stmts: + - - While: + while_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: while + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + condition: + Symbol: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "true" + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: "\n" + do_token: + leading_trivia: + - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Whitespace + characters: " " + token: + start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 4 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: + - start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 4 + token_type: + type: Whitespace + characters: "\n" + - ~ + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 11 + line: 2 + character: 1 + end_position: + bytes: 12 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 12 + line: 2 + character: 2 + end_position: + bytes: 16 + line: 2 + character: 6 + token_type: + type: Identifier + identifier: call + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 16 + line: 2 + character: 6 + end_position: + bytes: 17 + line: 2 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 17 + line: 2 + character: 7 + end_position: + bytes: 18 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 18 + line: 2 + character: 8 + end_position: + bytes: 19 + line: 2 + character: 8 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 22 + line: 3 + character: 4 + end_position: + bytes: 22 + line: 3 + character: 4 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/parser/while-4/ast_to_string.snap b/full-moon/tests/cases/fail/parser/while-4/ast_to_string.snap new file mode 100644 index 00000000..c5614829 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 30 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/parser/while-4 +--- +"while true\n do\nend\n\tcall()\n" + diff --git a/full-moon/tests/cases/fail/parser/while-4/error.snap b/full-moon/tests/cases/fail/parser/while-4/error.snap deleted file mode 100644 index 310e5145..00000000 --- a/full-moon/tests/cases/fail/parser/while-4/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/parser/while-4 - ---- -UnexpectedToken: - token: - start_position: - bytes: 12 - line: 2 - character: 2 - end_position: - bytes: 16 - line: 2 - character: 6 - token_type: - type: Identifier - identifier: call - additional: "expected 'do'" - diff --git a/full-moon/tests/cases/fail/parser/while-4/error_display.snap b/full-moon/tests/cases/fail/parser/while-4/error_display.snap new file mode 100644 index 00000000..db15cbd6 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-4/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/parser/while-4 +--- +error[ast]: expected `do` after condition + ┌─ source.lua:2:2 + │ +2 │ call() + │ ^^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:3:1 + │ +3 │ end + │ ^^^ + + diff --git a/full-moon/tests/cases/fail/parser/while-4/errors.snap b/full-moon/tests/cases/fail/parser/while-4/errors.snap new file mode 100644 index 00000000..65f22470 --- /dev/null +++ b/full-moon/tests/cases/fail/parser/while-4/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/parser/while-4 +--- +- AstError: + token: + start_position: + bytes: 12 + line: 2 + character: 2 + end_position: + bytes: 16 + line: 2 + character: 6 + token_type: + type: Identifier + identifier: call + additional: "expected `do` after condition" +- AstError: + token: + start_position: + bytes: 19 + line: 3 + character: 1 + end_position: + bytes: 22 + line: 3 + character: 4 + token_type: + type: Symbol + symbol: end + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/ast.snap b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/ast.snap new file mode 100644 index 00000000..b453902a --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/ast.snap @@ -0,0 +1,98 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 19 +expression: result.ast +input_file: full-moon/tests/cases/fail/tokenizer/bad-numbers-1 +--- +nodes: + stmts: + - - Assignment: + var_list: + pairs: + - End: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Identifier + identifier: _ + trailing_trivia: + - start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Number + text: 1edoge + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/ast_to_string.snap b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/ast_to_string.snap new file mode 100644 index 00000000..25f3ae4a --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 22 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/tokenizer/bad-numbers-1 +--- +_ = 1edoge + diff --git a/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/error_display.snap b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/error_display.snap new file mode 100644 index 00000000..b61cd582 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/tokenizer/bad-numbers-1 +--- +error[tokenizer]: invalid number (1:5 to 1:11) + ┌─ source.lua:1:5 + │ +1 │ _ = 1edoge + │ ^^^^^^ + + diff --git a/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/errors.snap b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/errors.snap new file mode 100644 index 00000000..0f3c48c8 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/errors.snap @@ -0,0 +1,16 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 15 +expression: result.errors +input_file: full-moon/tests/cases/fail/tokenizer/bad-numbers-1 +--- +- TokenizerError: + error: InvalidNumber + range: + - bytes: 4 + line: 1 + character: 5 + - bytes: 10 + line: 1 + character: 11 + diff --git a/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/source.lua b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/source.lua new file mode 100644 index 00000000..56135fcb --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/source.lua @@ -0,0 +1 @@ +_ = 1edoge \ No newline at end of file diff --git a/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/tokens_result.snap b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/tokens_result.snap new file mode 100644 index 00000000..b0e88e72 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/bad-numbers-1/tokens_result.snap @@ -0,0 +1,81 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 42 +expression: tokens +input_file: full-moon/tests/cases/fail/tokenizer/bad-numbers-1 +--- +Recovered: + - - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Identifier + identifier: _ + - start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "=" + - start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Number + text: 1edoge + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Eof + - - error: InvalidNumber + range: + - bytes: 4 + line: 1 + character: 5 + - bytes: 10 + line: 1 + character: 11 + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/ast.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/ast.snap new file mode 100644 index 00000000..2acc2d98 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/ast.snap @@ -0,0 +1,35 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 19 +expression: result.ast +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-comment-1 +--- +nodes: + stmts: [] +eof: + leading_trivia: + - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: MultiLineComment + blocks: 0 + comment: "" + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/error.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/ast_to_string.snap similarity index 55% rename from full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/error.snap rename to full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/ast_to_string.snap index f9c84505..77860b75 100644 --- a/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/error.snap +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/ast_to_string.snap @@ -1,12 +1,8 @@ --- source: full-moon/tests/fail_cases.rs -expression: error -input_file: full-moon/tests/cases/fail/tokenizer/unclosed-comment - +assertion_line: 22 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-comment-1 --- -error: UnclosedComment -position: - bytes: 0 - line: 1 - character: 1 +"--[[]]" diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/error_display.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/error_display.snap new file mode 100644 index 00000000..55c576c7 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-comment-1 +--- +error[tokenizer]: unclosed comment (1:1 to 1:5) + ┌─ source.lua:1:1 + │ +1 │ --[[ + │ ^^^^ + + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/errors.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/errors.snap new file mode 100644 index 00000000..d9190a80 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/errors.snap @@ -0,0 +1,16 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 15 +expression: result.errors +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-comment-1 +--- +- TokenizerError: + error: UnclosedComment + range: + - bytes: 0 + line: 1 + character: 1 + - bytes: 4 + line: 1 + character: 5 + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/tokens_result.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/tokens_result.snap new file mode 100644 index 00000000..7fa651a6 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-comment-1/tokens_result.snap @@ -0,0 +1,38 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 42 +expression: tokens +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-comment-1 +--- +Recovered: + - - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: MultiLineComment + blocks: 0 + comment: "" + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Eof + - - error: UnclosedComment + range: + - bytes: 0 + line: 1 + character: 1 + - bytes: 4 + line: 1 + character: 5 + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/ast.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/ast.snap new file mode 100644 index 00000000..000f9980 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/ast.snap @@ -0,0 +1,124 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 19 +expression: result.ast +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-1 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + String: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: StringLiteral + literal: hello + quote_type: Double + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/error.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/ast_to_string.snap similarity index 56% rename from full-moon/tests/cases/fail/tokenizer/unclosed-string-1/error.snap rename to full-moon/tests/cases/fail/tokenizer/unclosed-string-1/ast_to_string.snap index ea6fba90..5b680f7c 100644 --- a/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/error.snap +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/ast_to_string.snap @@ -1,12 +1,8 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 22 +expression: "full_moon::print(&ast)" input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-1 - --- -error: UnclosedString -position: - bytes: 10 - line: 1 - character: 11 +"local x = \"hello\"" diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/error_display.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/error_display.snap new file mode 100644 index 00000000..a9aee9e1 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-1 +--- +error[tokenizer]: unclosed string (1:11 to 1:17) + ┌─ source.lua:1:11 + │ +1 │ local x = "hello + │ ^^^^^^ + + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/errors.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/errors.snap new file mode 100644 index 00000000..3b7b839d --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/errors.snap @@ -0,0 +1,16 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 15 +expression: result.errors +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-1 +--- +- TokenizerError: + error: UnclosedString + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 16 + line: 1 + character: 17 + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/tokens_result.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/tokens_result.snap new file mode 100644 index 00000000..ca212c39 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-1/tokens_result.snap @@ -0,0 +1,104 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 42 +expression: tokens +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-1 +--- +Recovered: + - - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: StringLiteral + literal: hello + quote_type: Double + - start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Eof + - - error: UnclosedString + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 16 + line: 1 + character: 17 + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/ast.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/ast.snap new file mode 100644 index 00000000..364ec714 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/ast.snap @@ -0,0 +1,124 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 19 +expression: result.ast +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-2 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + String: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: StringLiteral + literal: hello + quote_type: Single + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/error.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/ast_to_string.snap similarity index 56% rename from full-moon/tests/cases/fail/tokenizer/unclosed-string-2/error.snap rename to full-moon/tests/cases/fail/tokenizer/unclosed-string-2/ast_to_string.snap index cb934401..d83f4a67 100644 --- a/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/error.snap +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/ast_to_string.snap @@ -1,12 +1,8 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 22 +expression: "full_moon::print(&ast)" input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-2 - --- -error: UnclosedString -position: - bytes: 10 - line: 1 - character: 11 +"local x = 'hello'" diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/error_display.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/error_display.snap new file mode 100644 index 00000000..b082d0e2 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-2 +--- +error[tokenizer]: unclosed string (1:11 to 1:17) + ┌─ source.lua:1:11 + │ +1 │ local x = 'hello + │ ^^^^^^ + + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/errors.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/errors.snap new file mode 100644 index 00000000..3a8b885f --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/errors.snap @@ -0,0 +1,16 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 15 +expression: result.errors +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-2 +--- +- TokenizerError: + error: UnclosedString + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 16 + line: 1 + character: 17 + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/tokens_result.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/tokens_result.snap new file mode 100644 index 00000000..32fb822d --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-2/tokens_result.snap @@ -0,0 +1,104 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 42 +expression: tokens +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-2 +--- +Recovered: + - - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: StringLiteral + literal: hello + quote_type: Single + - start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Eof + - - error: UnclosedString + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 16 + line: 1 + character: 17 + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/ast.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/ast.snap new file mode 100644 index 00000000..3a413e59 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/ast.snap @@ -0,0 +1,122 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + String: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 23 + line: 2 + character: 6 + token_type: + type: StringLiteral + literal: "hello\nworld" + quote_type: Brackets + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 23 + line: 2 + character: 6 + end_position: + bytes: 23 + line: 2 + character: 6 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/error.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/ast_to_string.snap similarity index 56% rename from full-moon/tests/cases/fail/tokenizer/unclosed-string-3/error.snap rename to full-moon/tests/cases/fail/tokenizer/unclosed-string-3/ast_to_string.snap index 63362447..29857077 100644 --- a/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/error.snap +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/ast_to_string.snap @@ -1,12 +1,8 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 22 +expression: "full_moon::print(&ast)" input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-3 - --- -error: UnclosedString -position: - bytes: 10 - line: 1 - character: 11 +"local x = [[hello\nworld]]" diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/error_display.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/error_display.snap new file mode 100644 index 00000000..6621bcaf --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/error_display.snap @@ -0,0 +1,15 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-3 +--- +error[tokenizer]: unclosed string (1:11 to 2:6) + ┌─ source.lua:1:11 + │ +1 │ local x = [[hello + │ ╭───────────^ +2 │ │ world + │ ╰─────^ + + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/errors.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/errors.snap new file mode 100644 index 00000000..8abe8a49 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/errors.snap @@ -0,0 +1,16 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 15 +expression: result.errors +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-3 +--- +- TokenizerError: + error: UnclosedString + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 23 + line: 2 + character: 6 + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/tokens_result.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/tokens_result.snap new file mode 100644 index 00000000..515ed292 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-3/tokens_result.snap @@ -0,0 +1,102 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: tokens +--- +Recovered: + - - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 23 + line: 2 + character: 6 + token_type: + type: StringLiteral + literal: "hello\nworld" + quote_type: Brackets + - start_position: + bytes: 23 + line: 2 + character: 6 + end_position: + bytes: 23 + line: 2 + character: 6 + token_type: + type: Eof + - - error: UnclosedString + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 23 + line: 2 + character: 6 + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/ast.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/ast.snap new file mode 100644 index 00000000..ee77f72c --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/ast.snap @@ -0,0 +1,134 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 16 +expression: result.ast +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-4 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 2 + character: 1 + end_position: + bytes: 14 + line: 2 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 14 + line: 2 + character: 6 + end_position: + bytes: 15 + line: 2 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 2 + character: 7 + end_position: + bytes: 16 + line: 2 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 16 + line: 2 + character: 8 + end_position: + bytes: 17 + line: 2 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 17 + line: 2 + character: 9 + end_position: + bytes: 18 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 18 + line: 2 + character: 10 + end_position: + bytes: 19 + line: 2 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 19 + line: 2 + character: 11 + end_position: + bytes: 20 + line: 2 + character: 12 + token_type: + type: Number + text: "1" + trailing_trivia: + - start_position: + bytes: 20 + line: 2 + character: 12 + end_position: + bytes: 21 + line: 2 + character: 12 + token_type: + type: Whitespace + characters: "\n" + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 21 + line: 3 + character: 1 + end_position: + bytes: 21 + line: 3 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/ast_to_string.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/ast_to_string.snap new file mode 100644 index 00000000..dfa852fb --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 19 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-4 +--- +"local x = 1\n" + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/error_display.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/error_display.snap new file mode 100644 index 00000000..8f4a56d8 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/error_display.snap @@ -0,0 +1,21 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-4 +--- +error[tokenizer]: unclosed string (1:1 to 2:1) + ┌─ source.lua:1:1 + │ +1 │ ╭ "recover +2 │ │ local x = 1 + │ ╰^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:1 + │ +1 │ ╭ "recover +2 │ │ local x = 1 + │ ╰^ + + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/errors.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/errors.snap new file mode 100644 index 00000000..3e25c8d0 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/errors.snap @@ -0,0 +1,30 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-4 +--- +- TokenizerError: + error: UnclosedString + range: + - bytes: 0 + line: 1 + character: 1 + - bytes: 9 + line: 2 + character: 1 +- AstError: + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 9 + line: 2 + character: 1 + token_type: + type: StringLiteral + literal: recover + quote_type: Double + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/source.lua b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/source.lua new file mode 100644 index 00000000..743fa914 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/source.lua @@ -0,0 +1,2 @@ +"recover +local x = 1 diff --git a/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/tokens_result.snap b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/tokens_result.snap new file mode 100644 index 00000000..be8a9872 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unclosed-string-4/tokens_result.snap @@ -0,0 +1,126 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 42 +expression: tokens +input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-4 +--- +Recovered: + - - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 9 + line: 2 + character: 1 + token_type: + type: StringLiteral + literal: recover + quote_type: Double + - start_position: + bytes: 9 + line: 2 + character: 1 + end_position: + bytes: 14 + line: 2 + character: 6 + token_type: + type: Symbol + symbol: local + - start_position: + bytes: 14 + line: 2 + character: 6 + end_position: + bytes: 15 + line: 2 + character: 7 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 15 + line: 2 + character: 7 + end_position: + bytes: 16 + line: 2 + character: 8 + token_type: + type: Identifier + identifier: x + - start_position: + bytes: 16 + line: 2 + character: 8 + end_position: + bytes: 17 + line: 2 + character: 9 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 17 + line: 2 + character: 9 + end_position: + bytes: 18 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: "=" + - start_position: + bytes: 18 + line: 2 + character: 10 + end_position: + bytes: 19 + line: 2 + character: 11 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 19 + line: 2 + character: 11 + end_position: + bytes: 20 + line: 2 + character: 12 + token_type: + type: Number + text: "1" + - start_position: + bytes: 20 + line: 2 + character: 12 + end_position: + bytes: 21 + line: 2 + character: 12 + token_type: + type: Whitespace + characters: "\n" + - start_position: + bytes: 21 + line: 3 + character: 1 + end_position: + bytes: 21 + line: 3 + character: 1 + token_type: + type: Eof + - - error: UnclosedString + range: + - bytes: 0 + line: 1 + character: 1 + - bytes: 9 + line: 2 + character: 1 + diff --git a/full-moon/tests/cases/fail/tokenizer/unexpected-character/ast.snap b/full-moon/tests/cases/fail/tokenizer/unexpected-character/ast.snap new file mode 100644 index 00000000..1c975d69 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unexpected-character/ast.snap @@ -0,0 +1,107 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 19 +expression: result.ast +input_file: full-moon/tests/cases/fail/tokenizer/unexpected-character +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 12 + end_position: + bytes: 14 + line: 1 + character: 12 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/tokenizer/unexpected-character/error.snap b/full-moon/tests/cases/fail/tokenizer/unexpected-character/ast_to_string.snap similarity index 54% rename from full-moon/tests/cases/fail/tokenizer/unexpected-character/error.snap rename to full-moon/tests/cases/fail/tokenizer/unexpected-character/ast_to_string.snap index ab696ab7..ffd9a894 100644 --- a/full-moon/tests/cases/fail/tokenizer/unexpected-character/error.snap +++ b/full-moon/tests/cases/fail/tokenizer/unexpected-character/ast_to_string.snap @@ -1,13 +1,8 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 22 +expression: "full_moon::print(&ast)" input_file: full-moon/tests/cases/fail/tokenizer/unexpected-character - --- -error: - UnexpectedToken: 🤔 -position: - bytes: 10 - line: 1 - character: 11 +"local x = " diff --git a/full-moon/tests/cases/fail/tokenizer/unexpected-character/error_display.snap b/full-moon/tests/cases/fail/tokenizer/unexpected-character/error_display.snap new file mode 100644 index 00000000..651118bb --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unexpected-character/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/tokenizer/unexpected-character +--- +error[ast]: expected an expression + ┌─ source.lua:1:9 + │ +1 │ local x = 🤔 + │ ^ + +error[tokenizer]: unexpected character 🤔 (1:11 to 1:12) + ┌─ source.lua:1:11 + │ +1 │ local x = 🤔 + │ ^^ + + diff --git a/full-moon/tests/cases/fail/tokenizer/unexpected-character/errors.snap b/full-moon/tests/cases/fail/tokenizer/unexpected-character/errors.snap new file mode 100644 index 00000000..3c99633f --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unexpected-character/errors.snap @@ -0,0 +1,30 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/tokenizer/unexpected-character +--- +- AstError: + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + additional: expected an expression +- TokenizerError: + error: + UnexpectedToken: 🤔 + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 14 + line: 1 + character: 12 + diff --git a/full-moon/tests/cases/fail/tokenizer/unexpected-character/tokens_result.snap b/full-moon/tests/cases/fail/tokenizer/unexpected-character/tokens_result.snap new file mode 100644 index 00000000..b7d68acf --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/unexpected-character/tokens_result.snap @@ -0,0 +1,93 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 42 +expression: tokens +input_file: full-moon/tests/cases/fail/tokenizer/unexpected-character +--- +Recovered: + - - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 14 + line: 1 + character: 12 + end_position: + bytes: 14 + line: 1 + character: 12 + token_type: + type: Eof + - - error: + UnexpectedToken: 🤔 + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 14 + line: 1 + character: 12 + diff --git a/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/ast.snap b/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/ast.snap new file mode 100644 index 00000000..8e9236e8 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/ast.snap @@ -0,0 +1,129 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 19 +expression: result.ast +input_file: full-moon/tests/cases/fail/tokenizer/wrong-place-shebang +--- +nodes: + stmts: + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 23 + line: 3 + character: 1 + end_position: + bytes: 24 + line: 3 + character: 1 + token_type: + type: Whitespace + characters: "\n" + token: + start_position: + bytes: 24 + line: 4 + character: 1 + end_position: + bytes: 29 + line: 4 + character: 6 + token_type: + type: Identifier + identifier: print + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 29 + line: 4 + character: 6 + end_position: + bytes: 30 + line: 4 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 37 + line: 4 + character: 14 + end_position: + bytes: 38 + line: 4 + character: 15 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + arguments: + pairs: + - End: + String: + leading_trivia: [] + token: + start_position: + bytes: 30 + line: 4 + character: 7 + end_position: + bytes: 37 + line: 4 + character: 14 + token_type: + type: StringLiteral + literal: hello + quote_type: Double + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 38 + line: 4 + character: 15 + end_position: + bytes: 39 + line: 4 + character: 16 + token_type: + type: Symbol + symbol: ; + trailing_trivia: + - start_position: + bytes: 39 + line: 4 + character: 16 + end_position: + bytes: 40 + line: 4 + character: 16 + token_type: + type: Whitespace + characters: "\n" +eof: + leading_trivia: [] + token: + start_position: + bytes: 40 + line: 5 + character: 1 + end_position: + bytes: 40 + line: 5 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/error.snap b/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/ast_to_string.snap similarity index 56% rename from full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/error.snap rename to full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/ast_to_string.snap index ea55b16a..36c547b0 100644 --- a/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/error.snap +++ b/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/ast_to_string.snap @@ -1,12 +1,8 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 22 +expression: "full_moon::print(&ast)" input_file: full-moon/tests/cases/fail/tokenizer/wrong-place-shebang - --- -error: UnexpectedShebang -position: - bytes: 1 - line: 2 - character: 1 +"\nprint(\"hello\");\n" diff --git a/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/error_display.snap b/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/error_display.snap new file mode 100644 index 00000000..bf153f55 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/error_display.snap @@ -0,0 +1,61 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/cases/fail/tokenizer/wrong-place-shebang +--- +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:1 + │ +2 │ #!/usr/bin/env luajit + │ ^ + +error[tokenizer]: unexpected character ! (2:2 to 2:3) + ┌─ source.lua:2:2 + │ +2 │ #!/usr/bin/env luajit + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:3 + │ +2 │ #!/usr/bin/env luajit + │ ^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:2:7 + │ +2 │ #!/usr/bin/env luajit + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:7 + │ +2 │ #!/usr/bin/env luajit + │ ^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:2:11 + │ +2 │ #!/usr/bin/env luajit + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:11 + │ +2 │ #!/usr/bin/env luajit + │ ^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:2:16 + │ +2 │ #!/usr/bin/env luajit + │ ^^^^^^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:4:1 + │ +4 │ print("hello"); + │ ^^^^^ + + diff --git a/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/errors.snap b/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/errors.snap new file mode 100644 index 00000000..e4ebedfe --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/errors.snap @@ -0,0 +1,128 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/cases/fail/tokenizer/wrong-place-shebang +--- +- AstError: + token: + start_position: + bytes: 1 + line: 2 + character: 1 + end_position: + bytes: 2 + line: 2 + character: 2 + token_type: + type: Symbol + symbol: "#" + additional: "unexpected token, this needs to be a statement" +- TokenizerError: + error: + UnexpectedToken: "!" + range: + - bytes: 2 + line: 2 + character: 2 + - bytes: 3 + line: 2 + character: 3 +- AstError: + token: + start_position: + bytes: 3 + line: 2 + character: 3 + end_position: + bytes: 4 + line: 2 + character: 4 + token_type: + type: Symbol + symbol: / + additional: "unexpected token, this needs to be a statement" +- AstError: + token: + start_position: + bytes: 7 + line: 2 + character: 7 + end_position: + bytes: 8 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: / + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 7 + line: 2 + character: 7 + end_position: + bytes: 8 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: / + additional: "unexpected token, this needs to be a statement" +- AstError: + token: + start_position: + bytes: 11 + line: 2 + character: 11 + end_position: + bytes: 12 + line: 2 + character: 12 + token_type: + type: Symbol + symbol: / + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 11 + line: 2 + character: 11 + end_position: + bytes: 12 + line: 2 + character: 12 + token_type: + type: Symbol + symbol: / + additional: "unexpected token, this needs to be a statement" +- AstError: + token: + start_position: + bytes: 16 + line: 2 + character: 16 + end_position: + bytes: 22 + line: 2 + character: 22 + token_type: + type: Identifier + identifier: luajit + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 24 + line: 4 + character: 1 + end_position: + bytes: 29 + line: 4 + character: 6 + token_type: + type: Identifier + identifier: print + additional: unexpected expression when looking for a statement + diff --git a/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/tokens_result.snap b/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/tokens_result.snap new file mode 100644 index 00000000..57db51e3 --- /dev/null +++ b/full-moon/tests/cases/fail/tokenizer/wrong-place-shebang/tokens_result.snap @@ -0,0 +1,226 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 42 +expression: tokens +input_file: full-moon/tests/cases/fail/tokenizer/wrong-place-shebang +--- +Recovered: + - - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 1 + token_type: + type: Whitespace + characters: "\n" + - start_position: + bytes: 1 + line: 2 + character: 1 + end_position: + bytes: 2 + line: 2 + character: 2 + token_type: + type: Symbol + symbol: "#" + - start_position: + bytes: 3 + line: 2 + character: 3 + end_position: + bytes: 4 + line: 2 + character: 4 + token_type: + type: Symbol + symbol: / + - start_position: + bytes: 4 + line: 2 + character: 4 + end_position: + bytes: 7 + line: 2 + character: 7 + token_type: + type: Identifier + identifier: usr + - start_position: + bytes: 7 + line: 2 + character: 7 + end_position: + bytes: 8 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: / + - start_position: + bytes: 8 + line: 2 + character: 8 + end_position: + bytes: 11 + line: 2 + character: 11 + token_type: + type: Identifier + identifier: bin + - start_position: + bytes: 11 + line: 2 + character: 11 + end_position: + bytes: 12 + line: 2 + character: 12 + token_type: + type: Symbol + symbol: / + - start_position: + bytes: 12 + line: 2 + character: 12 + end_position: + bytes: 15 + line: 2 + character: 15 + token_type: + type: Identifier + identifier: env + - start_position: + bytes: 15 + line: 2 + character: 15 + end_position: + bytes: 16 + line: 2 + character: 16 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 16 + line: 2 + character: 16 + end_position: + bytes: 22 + line: 2 + character: 22 + token_type: + type: Identifier + identifier: luajit + - start_position: + bytes: 22 + line: 2 + character: 22 + end_position: + bytes: 23 + line: 2 + character: 22 + token_type: + type: Whitespace + characters: "\n" + - start_position: + bytes: 23 + line: 3 + character: 1 + end_position: + bytes: 24 + line: 3 + character: 1 + token_type: + type: Whitespace + characters: "\n" + - start_position: + bytes: 24 + line: 4 + character: 1 + end_position: + bytes: 29 + line: 4 + character: 6 + token_type: + type: Identifier + identifier: print + - start_position: + bytes: 29 + line: 4 + character: 6 + end_position: + bytes: 30 + line: 4 + character: 7 + token_type: + type: Symbol + symbol: ( + - start_position: + bytes: 30 + line: 4 + character: 7 + end_position: + bytes: 37 + line: 4 + character: 14 + token_type: + type: StringLiteral + literal: hello + quote_type: Double + - start_position: + bytes: 37 + line: 4 + character: 14 + end_position: + bytes: 38 + line: 4 + character: 15 + token_type: + type: Symbol + symbol: ) + - start_position: + bytes: 38 + line: 4 + character: 15 + end_position: + bytes: 39 + line: 4 + character: 16 + token_type: + type: Symbol + symbol: ; + - start_position: + bytes: 39 + line: 4 + character: 16 + end_position: + bytes: 40 + line: 4 + character: 16 + token_type: + type: Whitespace + characters: "\n" + - start_position: + bytes: 40 + line: 5 + character: 1 + end_position: + bytes: 40 + line: 5 + character: 1 + token_type: + type: Eof + - - error: + UnexpectedToken: "!" + range: + - bytes: 2 + line: 2 + character: 2 + - bytes: 3 + line: 2 + character: 3 + diff --git a/full-moon/tests/cases/pass/assignment-4/ast.snap b/full-moon/tests/cases/pass/assignment-4/ast.snap new file mode 100644 index 00000000..2dae33e5 --- /dev/null +++ b/full-moon/tests/cases/pass/assignment-4/ast.snap @@ -0,0 +1,180 @@ +--- +source: full-moon/tests/pass_cases.rs +assertion_line: 54 +expression: ast.nodes() +input_file: full-moon/tests/cases/pass/assignment-4 +--- +stmts: + - - Assignment: + var_list: + pairs: + - End: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Identifier + identifier: a + trailing_trivia: + - start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Number + text: "1" + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: "\n" + - ~ + - - Assignment: + var_list: + pairs: + - End: + Name: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 2 + character: 1 + end_position: + bytes: 7 + line: 2 + character: 2 + token_type: + type: Identifier + identifier: b + trailing_trivia: + - start_position: + bytes: 7 + line: 2 + character: 2 + end_position: + bytes: 8 + line: 2 + character: 3 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 2 + character: 3 + end_position: + bytes: 9 + line: 2 + character: 4 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 2 + character: 4 + end_position: + bytes: 10 + line: 2 + character: 5 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 2 + character: 5 + end_position: + bytes: 11 + line: 2 + character: 6 + token_type: + type: Number + text: "2" + trailing_trivia: + - start_position: + bytes: 11 + line: 2 + character: 6 + end_position: + bytes: 12 + line: 2 + character: 6 + token_type: + type: Whitespace + characters: "\n" + - ~ + diff --git a/full-moon/tests/cases/pass/assignment-4/source.lua b/full-moon/tests/cases/pass/assignment-4/source.lua new file mode 100644 index 00000000..223ca50d --- /dev/null +++ b/full-moon/tests/cases/pass/assignment-4/source.lua @@ -0,0 +1,2 @@ +a = 1 +b = 2 diff --git a/full-moon/tests/cases/pass/assignment-4/tokens.snap b/full-moon/tests/cases/pass/assignment-4/tokens.snap new file mode 100644 index 00000000..afabdf98 --- /dev/null +++ b/full-moon/tests/cases/pass/assignment-4/tokens.snap @@ -0,0 +1,149 @@ +--- +source: full-moon/tests/pass_cases.rs +assertion_line: 40 +expression: tokens +input_file: full-moon/tests/cases/pass/assignment-4 +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Identifier + identifier: a +- start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Number + text: "1" +- start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 6 + line: 2 + character: 1 + end_position: + bytes: 7 + line: 2 + character: 2 + token_type: + type: Identifier + identifier: b +- start_position: + bytes: 7 + line: 2 + character: 2 + end_position: + bytes: 8 + line: 2 + character: 3 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 8 + line: 2 + character: 3 + end_position: + bytes: 9 + line: 2 + character: 4 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 9 + line: 2 + character: 4 + end_position: + bytes: 10 + line: 2 + character: 5 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 10 + line: 2 + character: 5 + end_position: + bytes: 11 + line: 2 + character: 6 + token_type: + type: Number + text: "2" +- start_position: + bytes: 11 + line: 2 + character: 6 + end_position: + bytes: 12 + line: 2 + character: 6 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 12 + line: 3 + character: 1 + end_position: + bytes: 12 + line: 3 + character: 1 + token_type: + type: Eof + diff --git a/full-moon/tests/cases/pass/assignment-5/ast.snap b/full-moon/tests/cases/pass/assignment-5/ast.snap new file mode 100644 index 00000000..a97a907a --- /dev/null +++ b/full-moon/tests/cases/pass/assignment-5/ast.snap @@ -0,0 +1,338 @@ +--- +source: full-moon/tests/pass_cases.rs +assertion_line: 47 +expression: ast.nodes() +input_file: full-moon/tests/cases/pass/assignment-5 +--- +stmts: + - - Assignment: + var_list: + pairs: + - End: + Expression: + prefix: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Identifier + identifier: gui + trailing_trivia: [] + suffixes: + - Index: + Dot: + dot: + leading_trivia: [] + token: + start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Symbol + symbol: "." + trailing_trivia: [] + name: + leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Identifier + identifier: Label + trailing_trivia: [] + - Index: + Dot: + dot: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "." + trailing_trivia: [] + name: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Identifier + identifier: Text + trailing_trivia: + - start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + BinaryOperator: + lhs: + String: + leading_trivia: [] + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 31 + line: 1 + character: 32 + token_type: + type: StringLiteral + literal: LOADING DATA + quote_type: Double + trailing_trivia: + - start_position: + bytes: 31 + line: 1 + character: 32 + end_position: + bytes: 32 + line: 1 + character: 33 + token_type: + type: Whitespace + characters: " " + binop: + TwoDots: + leading_trivia: [] + token: + start_position: + bytes: 32 + line: 1 + character: 33 + end_position: + bytes: 34 + line: 1 + character: 35 + token_type: + type: Symbol + symbol: ".." + trailing_trivia: + - start_position: + bytes: 34 + line: 1 + character: 35 + end_position: + bytes: 35 + line: 1 + character: 36 + token_type: + type: Whitespace + characters: " " + rhs: + FunctionCall: + prefix: + Expression: + Parentheses: + contained: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 35 + line: 1 + character: 36 + end_position: + bytes: 36 + line: 1 + character: 37 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 39 + line: 1 + character: 40 + end_position: + bytes: 40 + line: 1 + character: 41 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + expression: + String: + leading_trivia: [] + token: + start_position: + bytes: 36 + line: 1 + character: 37 + end_position: + bytes: 39 + line: 1 + character: 40 + token_type: + type: StringLiteral + literal: "." + quote_type: Double + trailing_trivia: [] + suffixes: + - Call: + MethodCall: + colon_token: + leading_trivia: [] + token: + start_position: + bytes: 40 + line: 1 + character: 41 + end_position: + bytes: 41 + line: 1 + character: 42 + token_type: + type: Symbol + symbol: ":" + trailing_trivia: [] + name: + leading_trivia: [] + token: + start_position: + bytes: 41 + line: 1 + character: 42 + end_position: + bytes: 44 + line: 1 + character: 45 + token_type: + type: Identifier + identifier: rep + trailing_trivia: [] + args: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 44 + line: 1 + character: 45 + end_position: + bytes: 45 + line: 1 + character: 46 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 53 + line: 1 + character: 54 + end_position: + bytes: 54 + line: 1 + character: 55 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 54 + line: 1 + character: 55 + end_position: + bytes: 55 + line: 1 + character: 55 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: + - End: + Var: + Name: + leading_trivia: [] + token: + start_position: + bytes: 45 + line: 1 + character: 46 + end_position: + bytes: 53 + line: 1 + character: 54 + token_type: + type: Identifier + identifier: dotCount + trailing_trivia: [] + - ~ + diff --git a/full-moon/tests/cases/pass/assignment-5/source.lua b/full-moon/tests/cases/pass/assignment-5/source.lua new file mode 100644 index 00000000..8a751ba0 --- /dev/null +++ b/full-moon/tests/cases/pass/assignment-5/source.lua @@ -0,0 +1 @@ +gui.Label.Text = "LOADING DATA" .. ("."):rep(dotCount) diff --git a/full-moon/tests/cases/pass/assignment-5/tokens.snap b/full-moon/tests/cases/pass/assignment-5/tokens.snap new file mode 100644 index 00000000..7006f66c --- /dev/null +++ b/full-moon/tests/cases/pass/assignment-5/tokens.snap @@ -0,0 +1,250 @@ +--- +source: full-moon/tests/pass_cases.rs +assertion_line: 40 +expression: tokens +input_file: full-moon/tests/cases/pass/assignment-5 +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Identifier + identifier: gui +- start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Symbol + symbol: "." +- start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Identifier + identifier: Label +- start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "." +- start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Identifier + identifier: Text +- start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 31 + line: 1 + character: 32 + token_type: + type: StringLiteral + literal: LOADING DATA + quote_type: Double +- start_position: + bytes: 31 + line: 1 + character: 32 + end_position: + bytes: 32 + line: 1 + character: 33 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 32 + line: 1 + character: 33 + end_position: + bytes: 34 + line: 1 + character: 35 + token_type: + type: Symbol + symbol: ".." +- start_position: + bytes: 34 + line: 1 + character: 35 + end_position: + bytes: 35 + line: 1 + character: 36 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 35 + line: 1 + character: 36 + end_position: + bytes: 36 + line: 1 + character: 37 + token_type: + type: Symbol + symbol: ( +- start_position: + bytes: 36 + line: 1 + character: 37 + end_position: + bytes: 39 + line: 1 + character: 40 + token_type: + type: StringLiteral + literal: "." + quote_type: Double +- start_position: + bytes: 39 + line: 1 + character: 40 + end_position: + bytes: 40 + line: 1 + character: 41 + token_type: + type: Symbol + symbol: ) +- start_position: + bytes: 40 + line: 1 + character: 41 + end_position: + bytes: 41 + line: 1 + character: 42 + token_type: + type: Symbol + symbol: ":" +- start_position: + bytes: 41 + line: 1 + character: 42 + end_position: + bytes: 44 + line: 1 + character: 45 + token_type: + type: Identifier + identifier: rep +- start_position: + bytes: 44 + line: 1 + character: 45 + end_position: + bytes: 45 + line: 1 + character: 46 + token_type: + type: Symbol + symbol: ( +- start_position: + bytes: 45 + line: 1 + character: 46 + end_position: + bytes: 53 + line: 1 + character: 54 + token_type: + type: Identifier + identifier: dotCount +- start_position: + bytes: 53 + line: 1 + character: 54 + end_position: + bytes: 54 + line: 1 + character: 55 + token_type: + type: Symbol + symbol: ) +- start_position: + bytes: 54 + line: 1 + character: 55 + end_position: + bytes: 55 + line: 1 + character: 55 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 55 + line: 2 + character: 1 + end_position: + bytes: 55 + line: 2 + character: 1 + token_type: + type: Eof + diff --git a/full-moon/tests/cases/pass/body-with-spaces/ast.snap b/full-moon/tests/cases/pass/body-with-spaces/ast.snap new file mode 100644 index 00000000..46d33fda --- /dev/null +++ b/full-moon/tests/cases/pass/body-with-spaces/ast.snap @@ -0,0 +1,62 @@ +--- +source: full-moon/tests/pass_cases.rs +expression: ast.nodes() +--- +stmts: + - - Do: + do_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: do + trailing_trivia: + - start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: [] + end_token: + leading_trivia: + - start_position: + bytes: 3 + line: 2 + character: 1 + end_position: + bytes: 8 + line: 2 + character: 5 + token_type: + type: Whitespace + characters: " \n" + token: + start_position: + bytes: 8 + line: 3 + character: 1 + end_position: + bytes: 11 + line: 3 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ + diff --git a/full-moon/tests/cases/pass/body-with-spaces/source.lua b/full-moon/tests/cases/pass/body-with-spaces/source.lua new file mode 100644 index 00000000..c0697c93 --- /dev/null +++ b/full-moon/tests/cases/pass/body-with-spaces/source.lua @@ -0,0 +1,3 @@ +do + +end \ No newline at end of file diff --git a/full-moon/tests/cases/pass/body-with-spaces/tokens.snap b/full-moon/tests/cases/pass/body-with-spaces/tokens.snap new file mode 100644 index 00000000..841093a4 --- /dev/null +++ b/full-moon/tests/cases/pass/body-with-spaces/tokens.snap @@ -0,0 +1,59 @@ +--- +source: full-moon/tests/pass_cases.rs +expression: tokens +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: do +- start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 3 + line: 2 + character: 1 + end_position: + bytes: 8 + line: 2 + character: 5 + token_type: + type: Whitespace + characters: " \n" +- start_position: + bytes: 8 + line: 3 + character: 1 + end_position: + bytes: 11 + line: 3 + character: 4 + token_type: + type: Symbol + symbol: end +- start_position: + bytes: 11 + line: 3 + character: 4 + end_position: + bytes: 11 + line: 3 + character: 4 + token_type: + type: Eof + diff --git a/full-moon/tests/cases/pass/multi-line-string-1/ast.snap b/full-moon/tests/cases/pass/multi-line-string-1/ast.snap index 76a18070..56c703f6 100644 --- a/full-moon/tests/cases/pass/multi-line-string-1/ast.snap +++ b/full-moon/tests/cases/pass/multi-line-string-1/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/cases/pass/multi-line-string-1 --- stmts: - - LocalAssignment: @@ -103,7 +101,6 @@ stmts: token_type: type: StringLiteral literal: "Full Moon\nis a\nlossless\nLua parser" - multi_line: 0 quote_type: Brackets trailing_trivia: [] - ~ diff --git a/full-moon/tests/cases/pass/multi-line-string-1/tokens.snap b/full-moon/tests/cases/pass/multi-line-string-1/tokens.snap index 66e57c6d..cdb29fb3 100644 --- a/full-moon/tests/cases/pass/multi-line-string-1/tokens.snap +++ b/full-moon/tests/cases/pass/multi-line-string-1/tokens.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs expression: tokens -input_file: full-moon/tests/cases/pass/multi-line-string-1 - --- - start_position: bytes: 0 @@ -81,7 +79,6 @@ input_file: full-moon/tests/cases/pass/multi-line-string-1 token_type: type: StringLiteral literal: "Full Moon\nis a\nlossless\nLua parser" - multi_line: 0 quote_type: Brackets - start_position: bytes: 48 diff --git a/full-moon/tests/cases/pass/multi-line-string-2/ast.snap b/full-moon/tests/cases/pass/multi-line-string-2/ast.snap index 12097f91..e0c6de1e 100644 --- a/full-moon/tests/cases/pass/multi-line-string-2/ast.snap +++ b/full-moon/tests/cases/pass/multi-line-string-2/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/cases/pass/multi-line-string-2 --- stmts: - - LocalAssignment: @@ -103,7 +101,7 @@ stmts: token_type: type: StringLiteral literal: "This is\nseveral equal\nsigns" - multi_line: 1 + multi_line_depth: 1 quote_type: Brackets trailing_trivia: [] - ~ diff --git a/full-moon/tests/cases/pass/multi-line-string-2/tokens.snap b/full-moon/tests/cases/pass/multi-line-string-2/tokens.snap index a15ac5a6..9254ab63 100644 --- a/full-moon/tests/cases/pass/multi-line-string-2/tokens.snap +++ b/full-moon/tests/cases/pass/multi-line-string-2/tokens.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs expression: tokens -input_file: full-moon/tests/cases/pass/multi-line-string-2 - --- - start_position: bytes: 0 @@ -81,7 +79,7 @@ input_file: full-moon/tests/cases/pass/multi-line-string-2 token_type: type: StringLiteral literal: "This is\nseveral equal\nsigns" - multi_line: 1 + multi_line_depth: 1 quote_type: Brackets - start_position: bytes: 43 diff --git a/full-moon/tests/cases/pass/multi-line-string-3/ast.snap b/full-moon/tests/cases/pass/multi-line-string-3/ast.snap index 54cb5a03..c71df3ec 100644 --- a/full-moon/tests/cases/pass/multi-line-string-3/ast.snap +++ b/full-moon/tests/cases/pass/multi-line-string-3/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/cases/pass/multi-line-string-3 --- stmts: - - LocalAssignment: @@ -103,7 +101,6 @@ stmts: token_type: type: StringLiteral literal: "\nlocal emotes = {\n\t[\":thinking:\"] = \"http://www.roblox.com/asset/?id=643340245\",\n\t[\":bug:\"] = \"http://www.roblox.com/asset/?id=860037275\"\n}\n" - multi_line: 0 quote_type: Brackets trailing_trivia: [] - ~ diff --git a/full-moon/tests/cases/pass/multi-line-string-3/tokens.snap b/full-moon/tests/cases/pass/multi-line-string-3/tokens.snap index 0f32a8cc..ec9dc295 100644 --- a/full-moon/tests/cases/pass/multi-line-string-3/tokens.snap +++ b/full-moon/tests/cases/pass/multi-line-string-3/tokens.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs expression: tokens -input_file: full-moon/tests/cases/pass/multi-line-string-3 - --- - start_position: bytes: 0 @@ -81,7 +79,6 @@ input_file: full-moon/tests/cases/pass/multi-line-string-3 token_type: type: StringLiteral literal: "\nlocal emotes = {\n\t[\":thinking:\"] = \"http://www.roblox.com/asset/?id=643340245\",\n\t[\":bug:\"] = \"http://www.roblox.com/asset/?id=860037275\"\n}\n" - multi_line: 0 quote_type: Brackets - start_position: bytes: 154 diff --git a/full-moon/tests/cases/pass/multi-line-string-4/ast.snap b/full-moon/tests/cases/pass/multi-line-string-4/ast.snap index 66185907..af33a16f 100644 --- a/full-moon/tests/cases/pass/multi-line-string-4/ast.snap +++ b/full-moon/tests/cases/pass/multi-line-string-4/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/cases/pass/multi-line-string-4 --- stmts: - - FunctionCall: @@ -73,7 +71,6 @@ stmts: token_type: type: StringLiteral literal: doge - multi_line: 0 quote_type: Brackets trailing_trivia: [] - ~ diff --git a/full-moon/tests/cases/pass/multi-line-string-4/tokens.snap b/full-moon/tests/cases/pass/multi-line-string-4/tokens.snap index 46cb8e0d..cf929dfd 100644 --- a/full-moon/tests/cases/pass/multi-line-string-4/tokens.snap +++ b/full-moon/tests/cases/pass/multi-line-string-4/tokens.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs expression: tokens -input_file: full-moon/tests/cases/pass/multi-line-string-4 - --- - start_position: bytes: 0 @@ -37,7 +35,6 @@ input_file: full-moon/tests/cases/pass/multi-line-string-4 token_type: type: StringLiteral literal: doge - multi_line: 0 quote_type: Brackets - start_position: bytes: 13 diff --git a/full-moon/tests/cases/pass/multi-line-string-5/ast.snap b/full-moon/tests/cases/pass/multi-line-string-5/ast.snap index 933be7b2..3f3efe1e 100644 --- a/full-moon/tests/cases/pass/multi-line-string-5/ast.snap +++ b/full-moon/tests/cases/pass/multi-line-string-5/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/cases/pass/multi-line-string-5 --- stmts: - - LocalAssignment: @@ -103,7 +101,6 @@ stmts: token_type: type: StringLiteral literal: 🧓🏽 - multi_line: 0 quote_type: Brackets trailing_trivia: - start_position: diff --git a/full-moon/tests/cases/pass/multi-line-string-5/tokens.snap b/full-moon/tests/cases/pass/multi-line-string-5/tokens.snap index 3e0bd714..034d5f0c 100644 --- a/full-moon/tests/cases/pass/multi-line-string-5/tokens.snap +++ b/full-moon/tests/cases/pass/multi-line-string-5/tokens.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs expression: tokens -input_file: full-moon/tests/cases/pass/multi-line-string-5 - --- - start_position: bytes: 0 @@ -81,7 +79,6 @@ input_file: full-moon/tests/cases/pass/multi-line-string-5 token_type: type: StringLiteral literal: 🧓🏽 - multi_line: 0 quote_type: Brackets - start_position: bytes: 26 diff --git a/full-moon/tests/cases/pass/multi-line-string-7/ast.snap b/full-moon/tests/cases/pass/multi-line-string-7/ast.snap index be4714c1..5fd0d30f 100644 --- a/full-moon/tests/cases/pass/multi-line-string-7/ast.snap +++ b/full-moon/tests/cases/pass/multi-line-string-7/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/cases/pass/multi-line-string-7 --- stmts: - - LocalAssignment: @@ -103,7 +101,7 @@ stmts: token_type: type: StringLiteral literal: "[%s]" - multi_line: 1 + multi_line_depth: 1 quote_type: Brackets trailing_trivia: [] - ~ diff --git a/full-moon/tests/cases/pass/multi-line-string-7/tokens.snap b/full-moon/tests/cases/pass/multi-line-string-7/tokens.snap index e6c40a71..3babacfa 100644 --- a/full-moon/tests/cases/pass/multi-line-string-7/tokens.snap +++ b/full-moon/tests/cases/pass/multi-line-string-7/tokens.snap @@ -1,6 +1,5 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 38 expression: tokens --- - start_position: @@ -80,7 +79,7 @@ expression: tokens token_type: type: StringLiteral literal: "[%s]" - multi_line: 1 + multi_line_depth: 1 quote_type: Brackets - start_position: bytes: 20 diff --git a/full-moon/tests/cases/pass/multi-line-string-8/ast.snap b/full-moon/tests/cases/pass/multi-line-string-8/ast.snap index 32977d88..a89e03a8 100644 --- a/full-moon/tests/cases/pass/multi-line-string-8/ast.snap +++ b/full-moon/tests/cases/pass/multi-line-string-8/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/cases/pass/multi-line-string-8 --- stmts: - - LocalAssignment: @@ -103,7 +101,7 @@ stmts: token_type: type: StringLiteral literal: "\\v<((do|load)file|require)\\s*\\(?['\"]\\zs[^'\"]+\\ze['\"]" - multi_line: 1 + multi_line_depth: 1 quote_type: Brackets trailing_trivia: [] - ~ diff --git a/full-moon/tests/cases/pass/multi-line-string-8/tokens.snap b/full-moon/tests/cases/pass/multi-line-string-8/tokens.snap index f7f84d1d..eefcaa22 100644 --- a/full-moon/tests/cases/pass/multi-line-string-8/tokens.snap +++ b/full-moon/tests/cases/pass/multi-line-string-8/tokens.snap @@ -1,6 +1,5 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 38 expression: tokens --- - start_position: @@ -80,7 +79,7 @@ expression: tokens token_type: type: StringLiteral literal: "\\v<((do|load)file|require)\\s*\\(?['\"]\\zs[^'\"]+\\ze['\"]" - multi_line: 1 + multi_line_depth: 1 quote_type: Brackets - start_position: bytes: 68 diff --git a/full-moon/tests/cases/pass/numbers-1/ast.snap b/full-moon/tests/cases/pass/numbers-1/ast.snap new file mode 100644 index 00000000..af82c9c1 --- /dev/null +++ b/full-moon/tests/cases/pass/numbers-1/ast.snap @@ -0,0 +1,94 @@ +--- +source: full-moon/tests/pass_cases.rs +assertion_line: 47 +expression: ast.nodes() +input_file: full-moon/tests/cases/pass/numbers-1 +--- +stmts: + - - Assignment: + var_list: + pairs: + - End: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Identifier + identifier: _ + trailing_trivia: + - start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Number + text: "0x02" + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: "\n" + - ~ + diff --git a/full-moon/tests/cases/pass/numbers-1/source.lua b/full-moon/tests/cases/pass/numbers-1/source.lua new file mode 100644 index 00000000..71e00d7f --- /dev/null +++ b/full-moon/tests/cases/pass/numbers-1/source.lua @@ -0,0 +1 @@ +_ = 0x02 diff --git a/full-moon/tests/cases/pass/numbers-1/tokens.snap b/full-moon/tests/cases/pass/numbers-1/tokens.snap new file mode 100644 index 00000000..6abe86fa --- /dev/null +++ b/full-moon/tests/cases/pass/numbers-1/tokens.snap @@ -0,0 +1,83 @@ +--- +source: full-moon/tests/pass_cases.rs +assertion_line: 40 +expression: tokens +input_file: full-moon/tests/cases/pass/numbers-1 +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Identifier + identifier: _ +- start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Number + text: "0x02" +- start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 9 + line: 2 + character: 1 + end_position: + bytes: 9 + line: 2 + character: 1 + token_type: + type: Eof + diff --git a/full-moon/tests/cases/pass/shebang/ast.snap b/full-moon/tests/cases/pass/shebang/ast.snap index fe9da9bf..6b459033 100644 --- a/full-moon/tests/cases/pass/shebang/ast.snap +++ b/full-moon/tests/cases/pass/shebang/ast.snap @@ -1,6 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 +assertion_line: 47 expression: ast.nodes() input_file: full-moon/tests/cases/pass/shebang --- @@ -14,12 +14,23 @@ stmts: line: 1 character: 1 end_position: - bytes: 19 + bytes: 18 line: 1 character: 19 token_type: type: Shebang - line: "#!/usr/bin/env lua\n" + line: "#!/usr/bin/env lua" + - start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 19 + token_type: + type: Whitespace + characters: "\n" - start_position: bytes: 19 line: 2 diff --git a/full-moon/tests/cases/pass/shebang/tokens.snap b/full-moon/tests/cases/pass/shebang/tokens.snap index 09b72a98..2cea7643 100644 --- a/full-moon/tests/cases/pass/shebang/tokens.snap +++ b/full-moon/tests/cases/pass/shebang/tokens.snap @@ -1,20 +1,31 @@ --- source: full-moon/tests/pass_cases.rs +assertion_line: 40 expression: tokens input_file: full-moon/tests/cases/pass/shebang - --- - start_position: bytes: 0 line: 1 character: 1 end_position: - bytes: 19 + bytes: 18 line: 1 character: 19 token_type: type: Shebang - line: "#!/usr/bin/env lua\n" + line: "#!/usr/bin/env lua" +- start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 19 + token_type: + type: Whitespace + characters: "\n" - start_position: bytes: 19 line: 2 diff --git a/full-moon/tests/cases/pass/single-line-comment-6/tokens.snap b/full-moon/tests/cases/pass/single-line-comment-6/tokens.snap index 08eb1ae9..223fb990 100644 --- a/full-moon/tests/cases/pass/single-line-comment-6/tokens.snap +++ b/full-moon/tests/cases/pass/single-line-comment-6/tokens.snap @@ -1,6 +1,8 @@ --- source: full-moon/tests/pass_cases.rs +assertion_line: 40 expression: tokens +input_file: full-moon/tests/cases/pass/single-line-comment-6 --- - start_position: bytes: 0 @@ -9,18 +11,18 @@ expression: tokens end_position: bytes: 20 line: 1 - character: 21 + character: 9 token_type: type: SingleLineComment comment: 随便写点中文 - start_position: bytes: 20 line: 1 - character: 21 + character: 9 end_position: bytes: 21 line: 1 - character: 21 + character: 9 token_type: type: Whitespace characters: "\n" diff --git a/full-moon/tests/cases/pass/single-line-comment-7/tokens.snap b/full-moon/tests/cases/pass/single-line-comment-7/tokens.snap index 283078e5..87f28442 100644 --- a/full-moon/tests/cases/pass/single-line-comment-7/tokens.snap +++ b/full-moon/tests/cases/pass/single-line-comment-7/tokens.snap @@ -1,6 +1,8 @@ --- source: full-moon/tests/pass_cases.rs +assertion_line: 40 expression: tokens +input_file: full-moon/tests/cases/pass/single-line-comment-7 --- - start_position: bytes: 0 @@ -108,18 +110,18 @@ expression: tokens end_position: bytes: 86 line: 3 - character: 74 + character: 56 token_type: type: SingleLineComment comment: "}}封装方便访问的接口==========================================" - start_position: bytes: 86 line: 3 - character: 74 + character: 56 end_position: bytes: 86 line: 3 - character: 74 + character: 56 token_type: type: Eof diff --git a/full-moon/tests/comments_around_functions.rs b/full-moon/tests/comments_around_functions.rs index ba3cab5c..35ba73cb 100644 --- a/full-moon/tests/comments_around_functions.rs +++ b/full-moon/tests/comments_around_functions.rs @@ -1,7 +1,6 @@ // This is code from a real life usage of full-moon use full_moon::{self, ast::*, node::Node, tokenizer::TokenKind, visitors::Visitor}; -use std::error::Error; const CODE: &str = r#" @@ -43,7 +42,7 @@ impl Visitor for MemberVisitor { } } -fn generate() -> Result<(), Box> { +fn generate() -> Result<(), Vec> { let ast = full_moon::parse(CODE)?; let mut visitor = MemberVisitor { diff --git a/full-moon/tests/fail_cases.rs b/full-moon/tests/fail_cases.rs index f7836c4e..610b9d46 100644 --- a/full-moon/tests/fail_cases.rs +++ b/full-moon/tests/fail_cases.rs @@ -1,79 +1,117 @@ -use full_moon::{ast, tokenizer}; -use insta::assert_yaml_snapshot; -use std::fs; +use codespan_reporting::{ + diagnostic::{Diagnostic, Label}, + files::SimpleFiles, +}; +use full_moon::{ + ast::{AstResult, LuaVersion}, + tokenizer::{self, LexerResult}, +}; +use insta::{assert_display_snapshot, assert_yaml_snapshot}; +use std::{fs, path::Path}; mod common; use common::run_test_folder; -#[test] -#[cfg_attr(feature = "no-source-tests", ignore)] -fn test_parser_fail_cases() { - run_test_folder("./tests/cases/fail/parser", |path| { - let source = fs::read_to_string(path.join("source.lua")).expect("couldn't read source.lua"); +fn process_fail_case(path: &Path, source: &str, lua_version: LuaVersion) { + let result = full_moon::parse_fallible(source, lua_version); + + if result.errors().is_empty() { + panic!("fail case passed for {path:?}"); + } + + assert_yaml_snapshot!("errors", result.errors()); + assert_yaml_snapshot!("ast", result.ast()); + + process_codespan_display(source, &result); + + let ast = result.into_ast().update_positions(); + assert_yaml_snapshot!("ast_to_string", full_moon::print(&ast)); +} + +fn process_codespan_display(source: &str, result: &AstResult) { + let mut files = SimpleFiles::new(); + + let file_id = files.add("source.lua", source); + + let config = codespan_reporting::term::Config::default(); + let mut output = termcolor::NoColor::new(Vec::new()); + + for error in result.errors() { + let range = error.range(); - let tokens = tokenizer::tokens(&source).expect("couldn't tokenize"); + let diagnostic = Diagnostic::error() + .with_message(error.error_message()) + .with_code(match error { + full_moon::Error::AstError(_) => "ast", + full_moon::Error::TokenizerError(_) => "tokenizer", + }) + .with_labels(vec![Label::primary( + file_id, + (range.0.bytes())..(range.1.bytes()), + )]); + codespan_reporting::term::emit(&mut output, &config, &files, &diagnostic).unwrap(); + } + + assert_display_snapshot!( + "error_display", + String::from_utf8(output.into_inner()).unwrap() + ); +} + +fn run_parser_fail_cases(folder: &str, lua_version: LuaVersion) { + run_test_folder(folder, |path| { + let source = fs::read_to_string(path.join("source.lua")).expect("couldn't read source.lua"); + let tokens = tokenizer::Lexer::new(&source, lua_version) + .collect() + .unwrap(); assert_yaml_snapshot!("tokens", tokens); - match ast::Ast::from_tokens(tokens) { - Ok(_) => panic!("fail case passed for {path:?}"), - Err(error) => { - println!("error {error:#?}"); - assert_yaml_snapshot!("error", error); - } - } - }) + process_fail_case(path, &source, lua_version); + }); +} + +#[test] +#[cfg(not(feature = "luau"))] // exclude extra nodes added to yaml +#[cfg_attr(feature = "no-source-tests", ignore)] +fn test_parser_fail_cases() { + run_parser_fail_cases("./tests/cases/fail/parser", LuaVersion::lua51()); } #[test] +#[cfg(not(feature = "luau"))] // exclude extra nodes added to yaml #[cfg_attr(feature = "no-source-tests", ignore)] fn test_tokenizer_fail_cases() { run_test_folder("./tests/cases/fail/tokenizer", |path| { let source = fs::read_to_string(path.join("source.lua")).expect("couldn't read source.lua"); - match tokenizer::tokens(&source) { - Ok(tokens) => panic!("fail case passed for {path:?}\n{tokens:#?}"), - Err(error) => { - assert_yaml_snapshot!("error", error); - } - } - }) + let tokens = tokenizer::Lexer::new(&source, LuaVersion::lua51()).collect(); + assert!(!matches!(tokens, LexerResult::Ok(_))); + assert_yaml_snapshot!("tokens_result", tokens); + + process_fail_case(path, &source, LuaVersion::lua51()); + }); } #[test] -#[cfg(feature = "roblox")] +#[cfg(feature = "luau")] #[cfg_attr(feature = "no-source-tests", ignore)] fn test_roblox_parser_fail_cases() { - run_test_folder("./tests/roblox_cases/fail/parser", |path| { - let source = fs::read_to_string(path.join("source.lua")).expect("couldn't read source.lua"); - - let tokens = tokenizer::tokens(&source).expect("couldn't tokenize"); - - assert_yaml_snapshot!("tokens", tokens); - - match ast::Ast::from_tokens(tokens) { - Ok(_) => panic!("fail case passed for {:?}", path), - Err(error) => { - println!("error {:#?}", error); - assert_yaml_snapshot!("error", error); - } - } - }) + run_parser_fail_cases("./tests/roblox_cases/fail/parser", LuaVersion::luau()); } #[test] -#[cfg(feature = "roblox")] +#[cfg(feature = "luau")] #[cfg_attr(feature = "no-source-tests", ignore)] fn test_roblox_tokenizer_fail_cases() { run_test_folder("./tests/roblox_cases/fail/tokenizer", |path| { let source = fs::read_to_string(path.join("source.lua")).expect("couldn't read source.lua"); - match tokenizer::tokens(&source) { - Ok(tokens) => panic!("fail case passed for {:?}\n{tokens:#?}", path), - Err(error) => { - assert_yaml_snapshot!("error", error); - } - } + let tokens = tokenizer::Lexer::new(&source, LuaVersion::luau()).collect(); + assert!(!matches!(tokens, LexerResult::Ok(_))); + assert_yaml_snapshot!("tokens_result", tokens); + + process_fail_case(path, &source, LuaVersion::luau()); }) } @@ -81,61 +119,19 @@ fn test_roblox_tokenizer_fail_cases() { #[cfg(feature = "lua52")] #[cfg_attr(feature = "no-source-tests", ignore)] fn test_lua52_parser_fail_cases() { - run_test_folder("./tests/lua52_cases/fail/parser", |path| { - let source = fs::read_to_string(path.join("source.lua")).expect("couldn't read source.lua"); - - let tokens = tokenizer::tokens(&source).expect("couldn't tokenize"); - - assert_yaml_snapshot!("tokens", tokens); - - match ast::Ast::from_tokens(tokens) { - Ok(_) => panic!("fail case passed for {:?}", path), - Err(error) => { - println!("error {:#?}", error); - assert_yaml_snapshot!("error", error); - } - } - }) + run_parser_fail_cases("./tests/lua52_cases/fail/parser", LuaVersion::lua52()); } #[test] #[cfg(feature = "lua53")] #[cfg_attr(feature = "no-source-tests", ignore)] fn test_lua53_parser_fail_cases() { - run_test_folder("./tests/lua53_cases/fail/parser", |path| { - let source = fs::read_to_string(path.join("source.lua")).expect("couldn't read source.lua"); - - let tokens = tokenizer::tokens(&source).expect("couldn't tokenize"); - - assert_yaml_snapshot!("tokens", tokens); - - match ast::Ast::from_tokens(tokens) { - Ok(_) => panic!("fail case passed for {:?}", path), - Err(error) => { - println!("error {:#?}", error); - assert_yaml_snapshot!("error", error); - } - } - }) + run_parser_fail_cases("./tests/lua53_cases/fail/parser", LuaVersion::lua53()); } #[test] #[cfg(feature = "lua54")] #[cfg_attr(feature = "no-source-tests", ignore)] fn test_lua54_parser_fail_cases() { - run_test_folder("./tests/lua54_cases/fail/parser", |path| { - let source = fs::read_to_string(path.join("source.lua")).expect("couldn't read source.lua"); - - let tokens = tokenizer::tokens(&source).expect("couldn't tokenize"); - - assert_yaml_snapshot!("tokens", tokens); - - match ast::Ast::from_tokens(tokens) { - Ok(_) => panic!("fail case passed for {:?}", path), - Err(error) => { - println!("error {:#?}", error); - assert_yaml_snapshot!("error", error); - } - } - }) + run_parser_fail_cases("./tests/lua54_cases/fail/parser", LuaVersion::lua54()); } diff --git a/full-moon/tests/lua52_cases/fail/parser/goto-1/error.snap b/full-moon/tests/lua52_cases/fail/parser/goto-1/ast.snap similarity index 72% rename from full-moon/tests/lua52_cases/fail/parser/goto-1/error.snap rename to full-moon/tests/lua52_cases/fail/parser/goto-1/ast.snap index 288b4a18..b43eda27 100644 --- a/full-moon/tests/lua52_cases/fail/parser/goto-1/error.snap +++ b/full-moon/tests/lua52_cases/fail/parser/goto-1/ast.snap @@ -1,10 +1,13 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 23 +expression: result.ast input_file: full-moon/tests/lua52_cases/fail/parser/goto-1 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: bytes: 4 @@ -16,5 +19,5 @@ UnexpectedToken: character: 5 token_type: type: Eof - additional: "expected identifier after `goto`" + trailing_trivia: [] diff --git a/full-moon/tests/lua52_cases/fail/parser/goto-1/ast_to_string.snap b/full-moon/tests/lua52_cases/fail/parser/goto-1/ast_to_string.snap new file mode 100644 index 00000000..28061eb2 --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/goto-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/lua52_cases/fail/parser/goto-1 +--- +"" + diff --git a/full-moon/tests/lua52_cases/fail/parser/goto-1/error_display.snap b/full-moon/tests/lua52_cases/fail/parser/goto-1/error_display.snap new file mode 100644 index 00000000..fb4943f8 --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/goto-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/lua52_cases/fail/parser/goto-1 +--- +error[ast]: expected label name after `goto` + ┌─ source.lua:1:1 + │ +1 │ goto + │ ^^^^ + + diff --git a/full-moon/tests/lua52_cases/fail/parser/goto-1/errors.snap b/full-moon/tests/lua52_cases/fail/parser/goto-1/errors.snap new file mode 100644 index 00000000..e2dba726 --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/goto-1/errors.snap @@ -0,0 +1,26 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/lua52_cases/fail/parser/goto-1 +--- +- AstError: + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Eof + additional: "expected label name after `goto`" + range: + - bytes: 0 + line: 1 + character: 1 + - bytes: 4 + line: 1 + character: 5 + diff --git a/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/ast.snap b/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/ast.snap new file mode 100644 index 00000000..7c00f184 --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/ast.snap @@ -0,0 +1,23 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 23 +expression: result.ast +input_file: full-moon/tests/lua52_cases/fail/parser/goto-as-identifier +--- +nodes: + stmts: [] +eof: + leading_trivia: [] + token: + start_position: + bytes: 69 + line: 2 + character: 17 + end_position: + bytes: 69 + line: 2 + character: 17 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/ast_to_string.snap b/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/ast_to_string.snap new file mode 100644 index 00000000..17567701 --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/lua52_cases/fail/parser/goto-as-identifier +--- +"" + diff --git a/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/error.snap b/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/error.snap deleted file mode 100644 index af0fff58..00000000 --- a/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/error.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -expression: error - ---- -UnexpectedToken: - token: - start_position: - bytes: 58 - line: 2 - character: 6 - end_position: - bytes: 62 - line: 2 - character: 10 - token_type: - type: Symbol - symbol: goto - additional: expected name - diff --git a/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/error_display.snap b/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/error_display.snap new file mode 100644 index 00000000..4edd9ae2 --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/error_display.snap @@ -0,0 +1,31 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/lua52_cases/fail/parser/goto-as-identifier +--- +error[ast]: expected identifier after `.` + ┌─ source.lua:2:5 + │ +2 │ self.goto("foo") + │ ^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:2:6 + │ +2 │ self.goto("foo") + │ ^^^^ + +error[ast]: expected label name after `goto` + ┌─ source.lua:2:6 + │ +2 │ self.goto("foo") + │ ^^^^^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:2:17 + │ +2 │ self.goto("foo") + │ ^ + + diff --git a/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/errors.snap b/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/errors.snap new file mode 100644 index 00000000..3d8ec54e --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/goto-as-identifier/errors.snap @@ -0,0 +1,68 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/lua52_cases/fail/parser/goto-as-identifier +--- +- AstError: + token: + start_position: + bytes: 57 + line: 2 + character: 5 + end_position: + bytes: 58 + line: 2 + character: 6 + token_type: + type: Symbol + symbol: "." + additional: "expected identifier after `.`" +- AstError: + token: + start_position: + bytes: 58 + line: 2 + character: 6 + end_position: + bytes: 62 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: goto + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 62 + line: 2 + character: 10 + end_position: + bytes: 63 + line: 2 + character: 11 + token_type: + type: Symbol + symbol: ( + additional: "expected label name after `goto`" + range: + - bytes: 58 + line: 2 + character: 6 + - bytes: 63 + line: 2 + character: 11 +- AstError: + token: + start_position: + bytes: 69 + line: 2 + character: 17 + end_position: + bytes: 69 + line: 2 + character: 17 + token_type: + type: Eof + additional: unexpected expression when looking for a statement + diff --git a/full-moon/tests/lua52_cases/fail/parser/label-1/ast.snap b/full-moon/tests/lua52_cases/fail/parser/label-1/ast.snap new file mode 100644 index 00000000..b1bc165f --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/label-1/ast.snap @@ -0,0 +1,70 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 23 +expression: result.ast +input_file: full-moon/tests/lua52_cases/fail/parser/label-1 +--- +nodes: + stmts: + - - Label: + left_colons: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: "::" + trailing_trivia: [] + name: + leading_trivia: [] + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: label + trailing_trivia: [] + right_colons: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Symbol + symbol: "::" + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/lua52_cases/fail/parser/label-1/ast_to_string.snap b/full-moon/tests/lua52_cases/fail/parser/label-1/ast_to_string.snap new file mode 100644 index 00000000..cf56a01c --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/label-1/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/lua52_cases/fail/parser/label-1 +--- +"::label::" + diff --git a/full-moon/tests/lua52_cases/fail/parser/label-1/error_display.snap b/full-moon/tests/lua52_cases/fail/parser/label-1/error_display.snap new file mode 100644 index 00000000..619b441e --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/label-1/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/lua52_cases/fail/parser/label-1 +--- +error[ast]: expected `::` after label + ┌─ source.lua:1:8 + │ +1 │ ::label + │ ^ + + diff --git a/full-moon/tests/lua52_cases/fail/parser/label-1/errors.snap b/full-moon/tests/lua52_cases/fail/parser/label-1/errors.snap new file mode 100644 index 00000000..18e6df95 --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/label-1/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/lua52_cases/fail/parser/label-1 +--- +- AstError: + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Eof + additional: "expected `::` after label" + diff --git a/full-moon/tests/lua52_cases/fail/parser/label-2/error.snap b/full-moon/tests/lua52_cases/fail/parser/label-2/ast.snap similarity index 50% rename from full-moon/tests/lua52_cases/fail/parser/label-2/error.snap rename to full-moon/tests/lua52_cases/fail/parser/label-2/ast.snap index 1faa91d8..978cd6d9 100644 --- a/full-moon/tests/lua52_cases/fail/parser/label-2/error.snap +++ b/full-moon/tests/lua52_cases/fail/parser/label-2/ast.snap @@ -1,21 +1,23 @@ --- source: full-moon/tests/fail_cases.rs -expression: error +assertion_line: 23 +expression: result.ast input_file: full-moon/tests/lua52_cases/fail/parser/label-2 - --- -UnexpectedToken: +nodes: + stmts: [] +eof: + leading_trivia: [] token: start_position: - bytes: 0 + bytes: 7 line: 1 - character: 1 + character: 8 end_position: - bytes: 5 + bytes: 7 line: 1 - character: 6 + character: 8 token_type: - type: Identifier - identifier: label - additional: leftover token + type: Eof + trailing_trivia: [] diff --git a/full-moon/tests/lua52_cases/fail/parser/label-2/ast_to_string.snap b/full-moon/tests/lua52_cases/fail/parser/label-2/ast_to_string.snap new file mode 100644 index 00000000..143f45ec --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/label-2/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/lua52_cases/fail/parser/label-2 +--- +"" + diff --git a/full-moon/tests/lua52_cases/fail/parser/label-2/error_display.snap b/full-moon/tests/lua52_cases/fail/parser/label-2/error_display.snap new file mode 100644 index 00000000..47332a91 --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/label-2/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/lua52_cases/fail/parser/label-2 +--- +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:1:6 + │ +1 │ label:: + │ ^^ + +error[ast]: expected label name after `::` + ┌─ source.lua:1:6 + │ +1 │ label:: + │ ^^ + + diff --git a/full-moon/tests/lua52_cases/fail/parser/label-2/errors.snap b/full-moon/tests/lua52_cases/fail/parser/label-2/errors.snap new file mode 100644 index 00000000..b032c04c --- /dev/null +++ b/full-moon/tests/lua52_cases/fail/parser/label-2/errors.snap @@ -0,0 +1,40 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/lua52_cases/fail/parser/label-2 +--- +- AstError: + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Symbol + symbol: "::" + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Eof + additional: "expected label name after `::`" + range: + - bytes: 5 + line: 1 + character: 6 + - bytes: 7 + line: 1 + character: 8 + diff --git a/full-moon/tests/lua52_cases/pass/numbers/ast.snap b/full-moon/tests/lua52_cases/pass/numbers/ast.snap index 31a92092..59fb072d 100644 --- a/full-moon/tests/lua52_cases/pass/numbers/ast.snap +++ b/full-moon/tests/lua52_cases/pass/numbers/ast.snap @@ -1,6 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 +assertion_line: 47 expression: ast.nodes() input_file: full-moon/tests/lua52_cases/pass/numbers --- @@ -426,381 +426,4 @@ stmts: type: Whitespace characters: "\n" - ~ - - - LocalAssignment: - local_token: - leading_trivia: - - start_position: - bytes: 150 - line: 9 - character: 1 - end_position: - bytes: 151 - line: 9 - character: 1 - token_type: - type: Whitespace - characters: "\n" - - start_position: - bytes: 151 - line: 10 - character: 1 - end_position: - bytes: 231 - line: 10 - character: 81 - token_type: - type: SingleLineComment - comment: " LuaJIT numbers (ULL/LL ending for both decimal and hexidecimal, or imaginary)" - - start_position: - bytes: 231 - line: 10 - character: 81 - end_position: - bytes: 232 - line: 10 - character: 81 - token_type: - type: Whitespace - characters: "\n" - - start_position: - bytes: 232 - line: 11 - character: 1 - end_position: - bytes: 274 - line: 11 - character: 43 - token_type: - type: SingleLineComment - comment: " This is in Lua 5.2 tests for simplicity" - - start_position: - bytes: 274 - line: 11 - character: 43 - end_position: - bytes: 275 - line: 11 - character: 43 - token_type: - type: Whitespace - characters: "\n" - token: - start_position: - bytes: 275 - line: 12 - character: 1 - end_position: - bytes: 280 - line: 12 - character: 6 - token_type: - type: Symbol - symbol: local - trailing_trivia: - - start_position: - bytes: 280 - line: 12 - character: 6 - end_position: - bytes: 281 - line: 12 - character: 7 - token_type: - type: Whitespace - characters: " " - name_list: - pairs: - - End: - leading_trivia: [] - token: - start_position: - bytes: 281 - line: 12 - character: 7 - end_position: - bytes: 282 - line: 12 - character: 8 - token_type: - type: Identifier - identifier: d - trailing_trivia: - - start_position: - bytes: 282 - line: 12 - character: 8 - end_position: - bytes: 283 - line: 12 - character: 9 - token_type: - type: Whitespace - characters: " " - equal_token: - leading_trivia: [] - token: - start_position: - bytes: 283 - line: 12 - character: 9 - end_position: - bytes: 284 - line: 12 - character: 10 - token_type: - type: Symbol - symbol: "=" - trailing_trivia: - - start_position: - bytes: 284 - line: 12 - character: 10 - end_position: - bytes: 285 - line: 12 - character: 11 - token_type: - type: Whitespace - characters: " " - expr_list: - pairs: - - End: - Number: - leading_trivia: [] - token: - start_position: - bytes: 285 - line: 12 - character: 11 - end_position: - bytes: 289 - line: 12 - character: 15 - token_type: - type: Number - text: 42LL - trailing_trivia: - - start_position: - bytes: 289 - line: 12 - character: 15 - end_position: - bytes: 290 - line: 12 - character: 15 - token_type: - type: Whitespace - characters: "\n" - - ~ - - - LocalAssignment: - local_token: - leading_trivia: [] - token: - start_position: - bytes: 290 - line: 13 - character: 1 - end_position: - bytes: 295 - line: 13 - character: 6 - token_type: - type: Symbol - symbol: local - trailing_trivia: - - start_position: - bytes: 295 - line: 13 - character: 6 - end_position: - bytes: 296 - line: 13 - character: 7 - token_type: - type: Whitespace - characters: " " - name_list: - pairs: - - End: - leading_trivia: [] - token: - start_position: - bytes: 296 - line: 13 - character: 7 - end_position: - bytes: 297 - line: 13 - character: 8 - token_type: - type: Identifier - identifier: e - trailing_trivia: - - start_position: - bytes: 297 - line: 13 - character: 8 - end_position: - bytes: 298 - line: 13 - character: 9 - token_type: - type: Whitespace - characters: " " - equal_token: - leading_trivia: [] - token: - start_position: - bytes: 298 - line: 13 - character: 9 - end_position: - bytes: 299 - line: 13 - character: 10 - token_type: - type: Symbol - symbol: "=" - trailing_trivia: - - start_position: - bytes: 299 - line: 13 - character: 10 - end_position: - bytes: 300 - line: 13 - character: 11 - token_type: - type: Whitespace - characters: " " - expr_list: - pairs: - - End: - Number: - leading_trivia: [] - token: - start_position: - bytes: 300 - line: 13 - character: 11 - end_position: - bytes: 306 - line: 13 - character: 17 - token_type: - type: Number - text: "0x2aLL" - trailing_trivia: - - start_position: - bytes: 306 - line: 13 - character: 17 - end_position: - bytes: 307 - line: 13 - character: 17 - token_type: - type: Whitespace - characters: "\n" - - ~ - - - LocalAssignment: - local_token: - leading_trivia: [] - token: - start_position: - bytes: 307 - line: 14 - character: 1 - end_position: - bytes: 312 - line: 14 - character: 6 - token_type: - type: Symbol - symbol: local - trailing_trivia: - - start_position: - bytes: 312 - line: 14 - character: 6 - end_position: - bytes: 313 - line: 14 - character: 7 - token_type: - type: Whitespace - characters: " " - name_list: - pairs: - - End: - leading_trivia: [] - token: - start_position: - bytes: 313 - line: 14 - character: 7 - end_position: - bytes: 314 - line: 14 - character: 8 - token_type: - type: Identifier - identifier: f - trailing_trivia: - - start_position: - bytes: 314 - line: 14 - character: 8 - end_position: - bytes: 315 - line: 14 - character: 9 - token_type: - type: Whitespace - characters: " " - equal_token: - leading_trivia: [] - token: - start_position: - bytes: 315 - line: 14 - character: 9 - end_position: - bytes: 316 - line: 14 - character: 10 - token_type: - type: Symbol - symbol: "=" - trailing_trivia: - - start_position: - bytes: 316 - line: 14 - character: 10 - end_position: - bytes: 317 - line: 14 - character: 11 - token_type: - type: Whitespace - characters: " " - expr_list: - pairs: - - End: - Number: - leading_trivia: [] - token: - start_position: - bytes: 317 - line: 14 - character: 11 - end_position: - bytes: 322 - line: 14 - character: 16 - token_type: - type: Number - text: 12.5i - trailing_trivia: [] - - ~ diff --git a/full-moon/tests/lua52_cases/pass/numbers/source.lua b/full-moon/tests/lua52_cases/pass/numbers/source.lua index bd6d6c07..ef1430c4 100644 --- a/full-moon/tests/lua52_cases/pass/numbers/source.lua +++ b/full-moon/tests/lua52_cases/pass/numbers/source.lua @@ -9,6 +9,7 @@ local c = 0X1.921FB54442D18P+1 -- LuaJIT numbers (ULL/LL ending for both decimal and hexidecimal, or imaginary) -- This is in Lua 5.2 tests for simplicity -local d = 42LL -local e = 0x2aLL -local f = 12.5i \ No newline at end of file +-- rewrite todo: add this back, but in a separate luajit pass folder +-- local d = 42LL +-- local e = 0x2aLL +-- local f = 12.5i diff --git a/full-moon/tests/lua52_cases/pass/numbers/tokens.snap b/full-moon/tests/lua52_cases/pass/numbers/tokens.snap index fe07587e..f8b26543 100644 --- a/full-moon/tests/lua52_cases/pass/numbers/tokens.snap +++ b/full-moon/tests/lua52_cases/pass/numbers/tokens.snap @@ -1,6 +1,8 @@ --- source: full-moon/tests/pass_cases.rs +assertion_line: 40 expression: tokens +input_file: full-moon/tests/lua52_cases/pass/numbers --- - start_position: bytes: 0 @@ -414,262 +416,97 @@ expression: tokens line: 12 character: 1 end_position: - bytes: 280 + bytes: 343 line: 12 - character: 6 - token_type: - type: Symbol - symbol: local -- start_position: - bytes: 280 - line: 12 - character: 6 - end_position: - bytes: 281 - line: 12 - character: 7 - token_type: - type: Whitespace - characters: " " -- start_position: - bytes: 281 - line: 12 - character: 7 - end_position: - bytes: 282 - line: 12 - character: 8 - token_type: - type: Identifier - identifier: d -- start_position: - bytes: 282 - line: 12 - character: 8 - end_position: - bytes: 283 - line: 12 - character: 9 + character: 69 token_type: - type: Whitespace - characters: " " -- start_position: - bytes: 283 - line: 12 - character: 9 - end_position: - bytes: 284 - line: 12 - character: 10 - token_type: - type: Symbol - symbol: "=" -- start_position: - bytes: 284 - line: 12 - character: 10 - end_position: - bytes: 285 - line: 12 - character: 11 - token_type: - type: Whitespace - characters: " " -- start_position: - bytes: 285 - line: 12 - character: 11 - end_position: - bytes: 289 - line: 12 - character: 15 - token_type: - type: Number - text: 42LL + type: SingleLineComment + comment: " rewrite todo: add this back, but in a separate luajit pass folder" - start_position: - bytes: 289 + bytes: 343 line: 12 - character: 15 + character: 69 end_position: - bytes: 290 + bytes: 344 line: 12 - character: 15 + character: 69 token_type: type: Whitespace characters: "\n" - start_position: - bytes: 290 + bytes: 344 line: 13 character: 1 end_position: - bytes: 295 - line: 13 - character: 6 - token_type: - type: Symbol - symbol: local -- start_position: - bytes: 295 - line: 13 - character: 6 - end_position: - bytes: 296 - line: 13 - character: 7 - token_type: - type: Whitespace - characters: " " -- start_position: - bytes: 296 - line: 13 - character: 7 - end_position: - bytes: 297 - line: 13 - character: 8 - token_type: - type: Identifier - identifier: e -- start_position: - bytes: 297 - line: 13 - character: 8 - end_position: - bytes: 298 - line: 13 - character: 9 - token_type: - type: Whitespace - characters: " " -- start_position: - bytes: 298 - line: 13 - character: 9 - end_position: - bytes: 299 - line: 13 - character: 10 - token_type: - type: Symbol - symbol: "=" -- start_position: - bytes: 299 - line: 13 - character: 10 - end_position: - bytes: 300 - line: 13 - character: 11 - token_type: - type: Whitespace - characters: " " -- start_position: - bytes: 300 - line: 13 - character: 11 - end_position: - bytes: 306 + bytes: 361 line: 13 - character: 17 + character: 18 token_type: - type: Number - text: "0x2aLL" + type: SingleLineComment + comment: " local d = 42LL" - start_position: - bytes: 306 + bytes: 361 line: 13 - character: 17 + character: 18 end_position: - bytes: 307 + bytes: 362 line: 13 - character: 17 + character: 18 token_type: type: Whitespace characters: "\n" - start_position: - bytes: 307 + bytes: 362 line: 14 character: 1 end_position: - bytes: 312 + bytes: 381 line: 14 - character: 6 + character: 20 token_type: - type: Symbol - symbol: local -- start_position: - bytes: 312 - line: 14 - character: 6 - end_position: - bytes: 313 - line: 14 - character: 7 - token_type: - type: Whitespace - characters: " " -- start_position: - bytes: 313 - line: 14 - character: 7 - end_position: - bytes: 314 - line: 14 - character: 8 - token_type: - type: Identifier - identifier: f + type: SingleLineComment + comment: " local e = 0x2aLL" - start_position: - bytes: 314 + bytes: 381 line: 14 - character: 8 + character: 20 end_position: - bytes: 315 + bytes: 382 line: 14 - character: 9 + character: 20 token_type: type: Whitespace - characters: " " + characters: "\n" - start_position: - bytes: 315 - line: 14 - character: 9 + bytes: 382 + line: 15 + character: 1 end_position: - bytes: 316 - line: 14 - character: 10 + bytes: 400 + line: 15 + character: 19 token_type: - type: Symbol - symbol: "=" + type: SingleLineComment + comment: " local f = 12.5i" - start_position: - bytes: 316 - line: 14 - character: 10 + bytes: 400 + line: 15 + character: 19 end_position: - bytes: 317 - line: 14 - character: 11 + bytes: 401 + line: 15 + character: 19 token_type: type: Whitespace - characters: " " -- start_position: - bytes: 317 - line: 14 - character: 11 - end_position: - bytes: 322 - line: 14 - character: 16 - token_type: - type: Number - text: 12.5i + characters: "\n" - start_position: - bytes: 322 - line: 14 - character: 16 + bytes: 401 + line: 16 + character: 1 end_position: - bytes: 322 - line: 14 - character: 16 + bytes: 401 + line: 16 + character: 1 token_type: type: Eof diff --git a/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/ast.snap b/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/ast.snap new file mode 100644 index 00000000..c7c48185 --- /dev/null +++ b/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/ast.snap @@ -0,0 +1,156 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 23 +expression: result.ast +input_file: full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: + - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 64 + line: 1 + character: 65 + token_type: + type: SingleLineComment + comment: " We shouldn't parse this as >> since it has a space in between" + - start_position: + bytes: 64 + line: 1 + character: 65 + end_position: + bytes: 65 + line: 1 + character: 65 + token_type: + type: Whitespace + characters: "\n" + token: + start_position: + bytes: 65 + line: 2 + character: 1 + end_position: + bytes: 70 + line: 2 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 70 + line: 2 + character: 6 + end_position: + bytes: 71 + line: 2 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 71 + line: 2 + character: 7 + end_position: + bytes: 72 + line: 2 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 72 + line: 2 + character: 8 + end_position: + bytes: 73 + line: 2 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 73 + line: 2 + character: 9 + end_position: + bytes: 74 + line: 2 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 74 + line: 2 + character: 10 + end_position: + bytes: 75 + line: 2 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 75 + line: 2 + character: 11 + end_position: + bytes: 76 + line: 2 + character: 12 + token_type: + type: Number + text: "1" + trailing_trivia: + - start_position: + bytes: 76 + line: 2 + character: 12 + end_position: + bytes: 77 + line: 2 + character: 13 + token_type: + type: Whitespace + characters: " " + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 82 + line: 2 + character: 18 + end_position: + bytes: 82 + line: 2 + character: 18 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/ast_to_string.snap b/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/ast_to_string.snap new file mode 100644 index 00000000..ec7b30e8 --- /dev/null +++ b/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop +--- +"-- We shouldn't parse this as >> since it has a space in between\nlocal x = 1 " + diff --git a/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/error_display.snap b/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/error_display.snap new file mode 100644 index 00000000..afad8718 --- /dev/null +++ b/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/error_display.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop +--- +error[ast]: expected expression after binary operator + ┌─ source.lua:2:13 + │ +2 │ local x = 1 > > 2 + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:15 + │ +2 │ local x = 1 > > 2 + │ ^ + + diff --git a/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/errors.snap b/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/errors.snap new file mode 100644 index 00000000..dc4ec410 --- /dev/null +++ b/full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop/errors.snap @@ -0,0 +1,34 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +input_file: full-moon/tests/lua53_cases/fail/parser/double-greater-than-binop +--- +- AstError: + token: + start_position: + bytes: 77 + line: 2 + character: 13 + end_position: + bytes: 78 + line: 2 + character: 14 + token_type: + type: Symbol + symbol: ">" + additional: expected expression after binary operator +- AstError: + token: + start_position: + bytes: 79 + line: 2 + character: 15 + end_position: + bytes: 80 + line: 2 + character: 16 + token_type: + type: Symbol + symbol: ">" + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/lua53_cases/pass/binary-operators/tokens.snap b/full-moon/tests/lua53_cases/pass/binary-operators/tokens.snap index 3180308b..27545183 100644 --- a/full-moon/tests/lua53_cases/pass/binary-operators/tokens.snap +++ b/full-moon/tests/lua53_cases/pass/binary-operators/tokens.snap @@ -1,6 +1,8 @@ --- source: full-moon/tests/pass_cases.rs +assertion_line: 40 expression: tokens +input_file: full-moon/tests/lua53_cases/pass/binary-operators --- - start_position: bytes: 0 @@ -490,24 +492,13 @@ expression: tokens bytes: 61 line: 4 character: 13 - end_position: - bytes: 62 - line: 4 - character: 14 - token_type: - type: Symbol - symbol: ">" -- start_position: - bytes: 62 - line: 4 - character: 14 end_position: bytes: 63 line: 4 character: 15 token_type: type: Symbol - symbol: ">" + symbol: ">>" - start_position: bytes: 63 line: 4 diff --git a/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast.snap b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast.snap new file mode 100644 index 00000000..2b426b0b --- /dev/null +++ b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast.snap @@ -0,0 +1,127 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +input_file: full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Identifier + identifier: name + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " + attributes: + - brackets: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: "<" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ">" + trailing_trivia: [] + name: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Identifier + identifier: const + trailing_trivia: [] + equal_token: ~ + expr_list: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast_to_string.snap b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast_to_string.snap new file mode 100644 index 00000000..3d1b20d3 --- /dev/null +++ b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast_to_string.snap @@ -0,0 +1,7 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1 +--- +local name + diff --git a/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/error_display.snap b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/error_display.snap new file mode 100644 index 00000000..59128ce5 --- /dev/null +++ b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1/error_display.snap @@ -0,0 +1,12 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1 +--- +error[ast]: expected `>` to close attribute + ┌─ source.lua:1:18 + │ +1 │ local name ` to close attribute" + diff --git a/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast.snap b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast.snap new file mode 100644 index 00000000..bc5e7f75 --- /dev/null +++ b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast.snap @@ -0,0 +1,179 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +input_file: full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2 +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Identifier + identifier: name + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " + attributes: + - brackets: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: "<" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ">" + trailing_trivia: [] + name: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Identifier + identifier: const + trailing_trivia: + - start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 19 + line: 1 + character: 20 + end_position: + bytes: 20 + line: 1 + character: 21 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 20 + line: 1 + character: 21 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Number + text: "10" + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 22 + line: 1 + character: 23 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast_to_string.snap b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast_to_string.snap new file mode 100644 index 00000000..04850cdf --- /dev/null +++ b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast_to_string.snap @@ -0,0 +1,7 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2 +--- +local name = 10 + diff --git a/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/error_display.snap b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/error_display.snap new file mode 100644 index 00000000..b93f53ce --- /dev/null +++ b/full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2/error_display.snap @@ -0,0 +1,12 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2 +--- +error[ast]: expected `>` to close attribute + ┌─ source.lua:1:19 + │ +1 │ local name ` to close attribute" + diff --git a/full-moon/tests/pass_cases.rs b/full-moon/tests/pass_cases.rs index 8112b726..45adb907 100644 --- a/full-moon/tests/pass_cases.rs +++ b/full-moon/tests/pass_cases.rs @@ -1,5 +1,5 @@ use full_moon::{ - ast, + ast::LuaVersion, node::Node, print, tokenizer::{self, Token, TokenReference}, @@ -30,17 +30,24 @@ fn unpack_token_reference(token: &TokenReference) -> Vec { .collect() } -fn test_pass_case(path: &Path) { +fn test_pass_case(path: &Path, lua_version: LuaVersion) { let source = fs::read_to_string(path.join("source.lua")).expect("couldn't read source.lua"); - let tokens = tokenizer::tokens(&source).expect("couldn't tokenize"); + let tokens = tokenizer::Lexer::new(&source, lua_version) + .collect() + .unwrap(); assert_yaml_snapshot!("tokens", tokens); - let ast = ast::Ast::from_tokens(tokens) - .unwrap_or_else(|error| panic!("couldn't make ast for {path:?} - {error:?}")); + let ast = full_moon::parse_fallible(&source, lua_version) + .into_result() + .unwrap_or_else(|error| panic!("couldn't make ast for {path:?} - {error:#?}")); let old_positions: Vec<_> = ast.tokens().flat_map(unpack_token_reference).collect(); + + assert_yaml_snapshot!("ast", ast.nodes()); + assert_eq!(PrettyString(&print(&ast)), PrettyString(&source)); + let ast = ast.update_positions(); assert_eq!( old_positions, @@ -48,43 +55,49 @@ fn test_pass_case(path: &Path) { .flat_map(unpack_token_reference) .collect::>(), ); - - assert_yaml_snapshot!("ast", ast.nodes()); - assert_eq!(PrettyString(&print(&ast)), PrettyString(&source)); } #[test] -#[cfg_attr(feature = "roblox", ignore)] // We don't want Roblox fields in JSON -#[cfg_attr(feature = "lua52", ignore)] // Lua 5.2 collides with this implementation +#[cfg(not(feature = "luau"))] // exclude extra nodes added to yaml #[cfg_attr(feature = "no-source-tests", ignore)] fn test_pass_cases() { - run_test_folder("./tests/cases/pass", test_pass_case); + run_test_folder("./tests/cases/pass", |path| { + test_pass_case(path, LuaVersion::lua51()) + }); } #[test] -#[cfg(feature = "roblox")] +#[cfg(feature = "luau")] #[cfg_attr(feature = "no-source-tests", ignore)] fn test_roblox_pass_cases() { - run_test_folder("./tests/roblox_cases/pass", test_pass_case); + run_test_folder("./tests/roblox_cases/pass", |path| { + test_pass_case(path, LuaVersion::luau()) + }); } #[test] #[cfg(feature = "lua52")] #[cfg_attr(feature = "no-source-tests", ignore)] fn test_lua52_pass_cases() { - run_test_folder("./tests/lua52_cases/pass", test_pass_case); + run_test_folder("./tests/lua52_cases/pass", |path| { + test_pass_case(path, LuaVersion::lua52()) + }); } #[test] #[cfg(feature = "lua53")] #[cfg_attr(feature = "no-source-tests", ignore)] fn test_lua53_pass_cases() { - run_test_folder("./tests/lua53_cases/pass", test_pass_case); + run_test_folder("./tests/lua53_cases/pass", |path| { + test_pass_case(path, LuaVersion::lua53()) + }); } #[test] #[cfg(feature = "lua54")] #[cfg_attr(feature = "no-source-tests", ignore)] fn test_lua54_pass_cases() { - run_test_folder("./tests/lua54_cases/pass", test_pass_case); + run_test_folder("./tests/lua54_cases/pass", |path| { + test_pass_case(path, LuaVersion::lua54()) + }); } diff --git a/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast.snap b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast.snap new file mode 100644 index 00000000..f1b7cba8 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast.snap @@ -0,0 +1,255 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - FunctionDeclaration: + function_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: function + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + name: + names: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Identifier + identifier: foo + trailing_trivia: [] + colon_name: ~ + body: + generics: ~ + parameters_parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " + parameters: + pairs: [] + type_specifiers: [] + return_type: + punctuation: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: "->" + trailing_trivia: + - start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Whitespace + characters: " " + type_info: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Identifier + identifier: string + trailing_trivia: + - start_position: + bytes: 24 + line: 1 + character: 25 + end_position: + bytes: 25 + line: 1 + character: 25 + token_type: + type: Whitespace + characters: "\n" + block: + stmts: [] + last_stmt: + - Return: + token: + leading_trivia: + - start_position: + bytes: 25 + line: 2 + character: 1 + end_position: + bytes: 26 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" + token: + start_position: + bytes: 26 + line: 2 + character: 2 + end_position: + bytes: 32 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: return + trailing_trivia: + - start_position: + bytes: 32 + line: 2 + character: 8 + end_position: + bytes: 33 + line: 2 + character: 9 + token_type: + type: Whitespace + characters: " " + returns: + pairs: + - End: + String: + leading_trivia: [] + token: + start_position: + bytes: 33 + line: 2 + character: 9 + end_position: + bytes: 35 + line: 2 + character: 11 + token_type: + type: StringLiteral + literal: "" + quote_type: Double + trailing_trivia: + - start_position: + bytes: 35 + line: 2 + character: 11 + end_position: + bytes: 36 + line: 2 + character: 11 + token_type: + type: Whitespace + characters: "\n" + - ~ + end_token: + leading_trivia: [] + token: + start_position: + bytes: 36 + line: 3 + character: 1 + end_position: + bytes: 39 + line: 3 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 39 + line: 3 + character: 4 + end_position: + bytes: 39 + line: 3 + character: 4 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast_to_string.snap new file mode 100644 index 00000000..66b24343 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +"function foo() -> string\n\treturn \"\"\nend" + diff --git a/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/error_display.snap new file mode 100644 index 00000000..875e2441 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/error_display.snap @@ -0,0 +1,11 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: function return type annotations should use `:` instead of `->` + ┌─ source.lua:1:16 + │ +1 │ function foo() -> string + │ ^^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/errors.snap b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/errors.snap new file mode 100644 index 00000000..6e7cbe65 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: "->" + additional: "function return type annotations should use `:` instead of `->`" + diff --git a/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/source.lua b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/source.lua new file mode 100644 index 00000000..165392c0 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/source.lua @@ -0,0 +1,3 @@ +function foo() -> string + return "" +end \ No newline at end of file diff --git a/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/tokens.snap b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/tokens.snap new file mode 100644 index 00000000..8c807bd8 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/tokens.snap @@ -0,0 +1,192 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: tokens +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: function +- start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Identifier + identifier: foo +- start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: ( +- start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: ) +- start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: "->" +- start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Identifier + identifier: string +- start_position: + bytes: 24 + line: 1 + character: 25 + end_position: + bytes: 25 + line: 1 + character: 25 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 25 + line: 2 + character: 1 + end_position: + bytes: 26 + line: 2 + character: 2 + token_type: + type: Whitespace + characters: "\t" +- start_position: + bytes: 26 + line: 2 + character: 2 + end_position: + bytes: 32 + line: 2 + character: 8 + token_type: + type: Symbol + symbol: return +- start_position: + bytes: 32 + line: 2 + character: 8 + end_position: + bytes: 33 + line: 2 + character: 9 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 33 + line: 2 + character: 9 + end_position: + bytes: 35 + line: 2 + character: 11 + token_type: + type: StringLiteral + literal: "" + quote_type: Double +- start_position: + bytes: 35 + line: 2 + character: 11 + end_position: + bytes: 36 + line: 2 + character: 11 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 36 + line: 3 + character: 1 + end_position: + bytes: 39 + line: 3 + character: 4 + token_type: + type: Symbol + symbol: end +- start_position: + bytes: 39 + line: 3 + character: 4 + end_position: + bytes: 39 + line: 3 + character: 4 + token_type: + type: Eof + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/ast.snap b/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/ast.snap new file mode 100644 index 00000000..4cfdecc7 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/ast.snap @@ -0,0 +1,258 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - TypeDeclaration: + type_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Identifier + identifier: Foo + trailing_trivia: [] + generics: + arrows: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "<" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: ">" + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " + generics: + pairs: + - End: + parameter: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 0 + character: 0 + end_position: + bytes: 0 + line: 0 + character: 0 + token_type: + type: Identifier + identifier: "%error-id%" + trailing_trivia: [] + default: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Whitespace + characters: " " + declare_as: + Callback: + generics: ~ + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Whitespace + characters: " " + arguments: + pairs: [] + arrow: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: "->" + trailing_trivia: + - start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Whitespace + characters: " " + return_type: + Tuple: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 19 + line: 1 + character: 20 + end_position: + bytes: 20 + line: 1 + character: 21 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 20 + line: 1 + character: 21 + end_position: + bytes: 21 + line: 1 + character: 22 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + types: + pairs: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 21 + line: 1 + character: 22 + end_position: + bytes: 21 + line: 1 + character: 22 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/ast_to_string.snap new file mode 100644 index 00000000..3d43c90a --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +type Foo<%error-id%> = () -> () + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/error_display.snap new file mode 100644 index 00000000..bc22d934 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/error_display.snap @@ -0,0 +1,11 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: expected a generic type name + ┌─ source.lua:1:10 + │ +1 │ type Foo<> = () -> () + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/errors.snap b/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/errors.snap new file mode 100644 index 00000000..199c2b24 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_declare_no_parameters/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: ">" + additional: expected a generic type name + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/ast.snap b/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/ast.snap new file mode 100644 index 00000000..84637b61 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/ast.snap @@ -0,0 +1,243 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - TypeDeclaration: + type_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Identifier + identifier: Bar + trailing_trivia: [] + generics: + arrows: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "<" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: ">" + trailing_trivia: + - start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Whitespace + characters: " " + generics: + pairs: + - Punctuated: + - parameter: + Variadic: + name: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Identifier + identifier: T + trailing_trivia: [] + ellipse: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: "..." + trailing_trivia: [] + default: ~ + - leading_trivia: [] + token: + start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " + - End: + parameter: + Variadic: + name: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Identifier + identifier: U + trailing_trivia: [] + ellipse: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "..." + trailing_trivia: [] + default: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 19 + line: 1 + character: 20 + end_position: + bytes: 20 + line: 1 + character: 21 + token_type: + type: Whitespace + characters: " " + declare_as: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 20 + line: 1 + character: 21 + end_position: + bytes: 23 + line: 1 + character: 24 + token_type: + type: Symbol + symbol: nil + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 23 + line: 1 + character: 24 + end_position: + bytes: 23 + line: 1 + character: 24 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/ast_to_string.snap new file mode 100644 index 00000000..8d67e1ef --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +"type Bar = nil" + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/error_display.snap new file mode 100644 index 00000000..2fccc332 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/error_display.snap @@ -0,0 +1,11 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: generic types come before generic type packs + ┌─ source.lua:1:16 + │ +1 │ type Bar = nil + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/errors.snap b/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/errors.snap new file mode 100644 index 00000000..0cc239d8 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_declare_packs_last/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Identifier + identifier: U + additional: generic types come before generic type packs + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/ast.snap b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/ast.snap new file mode 100644 index 00000000..ff1726ba --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/ast.snap @@ -0,0 +1,246 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - TypeDeclaration: + type_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Identifier + identifier: Foo + trailing_trivia: [] + generics: + arrows: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "<" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 22 + line: 1 + character: 23 + end_position: + bytes: 23 + line: 1 + character: 24 + token_type: + type: Symbol + symbol: ">" + trailing_trivia: + - start_position: + bytes: 23 + line: 1 + character: 24 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Whitespace + characters: " " + generics: + pairs: + - End: + parameter: + Variadic: + name: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Identifier + identifier: T + trailing_trivia: [] + ellipse: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: "..." + trailing_trivia: + - start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Whitespace + characters: " " + default: + - leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Whitespace + characters: " " + - Basic: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Identifier + identifier: string + trailing_trivia: [] + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 24 + line: 1 + character: 25 + end_position: + bytes: 25 + line: 1 + character: 26 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Whitespace + characters: " " + declare_as: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 26 + line: 1 + character: 27 + end_position: + bytes: 29 + line: 1 + character: 30 + token_type: + type: Symbol + symbol: nil + trailing_trivia: + - start_position: + bytes: 29 + line: 1 + character: 30 + end_position: + bytes: 30 + line: 1 + character: 30 + token_type: + type: Whitespace + characters: "\n" + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 30 + line: 2 + character: 1 + end_position: + bytes: 30 + line: 2 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/ast_to_string.snap new file mode 100644 index 00000000..47730000 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +"type Foo = nil\n" + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/error_display.snap new file mode 100644 index 00000000..21efa6d8 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/error_display.snap @@ -0,0 +1,11 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: expected type pack after `=` but got type instead + ┌─ source.lua:1:17 + │ +1 │ type Foo = nil + │ ^^^^^^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/errors.snap b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/errors.snap new file mode 100644 index 00000000..1e4553d3 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/errors.snap @@ -0,0 +1,26 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: "=" + additional: "expected type pack after `=` but got type instead" + range: + - bytes: 16 + line: 1 + character: 17 + - bytes: 22 + line: 1 + character: 23 + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/source.lua b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/source.lua new file mode 100644 index 00000000..e5f55764 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/source.lua @@ -0,0 +1 @@ +type Foo = nil diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/tokens.snap b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/tokens.snap new file mode 100644 index 00000000..7c168e5f --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_default_not_a_type_pack/tokens.snap @@ -0,0 +1,191 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: tokens +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type +- start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Identifier + identifier: Foo +- start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "<" +- start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Identifier + identifier: T +- start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: "..." +- start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Identifier + identifier: string +- start_position: + bytes: 22 + line: 1 + character: 23 + end_position: + bytes: 23 + line: 1 + character: 24 + token_type: + type: Symbol + symbol: ">" +- start_position: + bytes: 23 + line: 1 + character: 24 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 24 + line: 1 + character: 25 + end_position: + bytes: 25 + line: 1 + character: 26 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 26 + line: 1 + character: 27 + end_position: + bytes: 29 + line: 1 + character: 30 + token_type: + type: Symbol + symbol: nil +- start_position: + bytes: 29 + line: 1 + character: 30 + end_position: + bytes: 30 + line: 1 + character: 30 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 30 + line: 2 + character: 1 + end_position: + bytes: 30 + line: 2 + character: 1 + token_type: + type: Eof + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/ast.snap b/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/ast.snap new file mode 100644 index 00000000..40d6eeab --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/ast.snap @@ -0,0 +1,348 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - TypeDeclaration: + type_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Identifier + identifier: Foo + trailing_trivia: [] + generics: + arrows: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "<" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 28 + line: 1 + character: 29 + end_position: + bytes: 29 + line: 1 + character: 30 + token_type: + type: Symbol + symbol: ">" + trailing_trivia: + - start_position: + bytes: 29 + line: 1 + character: 30 + end_position: + bytes: 30 + line: 1 + character: 31 + token_type: + type: Whitespace + characters: " " + generics: + pairs: + - Punctuated: + - parameter: + Name: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Identifier + identifier: X + trailing_trivia: [] + default: ~ + - leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Whitespace + characters: " " + - Punctuated: + - parameter: + Name: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Identifier + identifier: Y + trailing_trivia: [] + default: ~ + - leading_trivia: [] + token: + start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: " " + - Punctuated: + - parameter: + Name: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Identifier + identifier: Z + trailing_trivia: + - start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Whitespace + characters: " " + default: + - leading_trivia: [] + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Whitespace + characters: " " + - Basic: + leading_trivia: [] + token: + start_position: + bytes: 19 + line: 1 + character: 20 + end_position: + bytes: 25 + line: 1 + character: 26 + token_type: + type: Identifier + identifier: string + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 26 + line: 1 + character: 27 + end_position: + bytes: 27 + line: 1 + character: 28 + token_type: + type: Whitespace + characters: " " + - End: + parameter: + Name: + leading_trivia: [] + token: + start_position: + bytes: 27 + line: 1 + character: 28 + end_position: + bytes: 28 + line: 1 + character: 29 + token_type: + type: Identifier + identifier: P + trailing_trivia: [] + default: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 30 + line: 1 + character: 31 + end_position: + bytes: 31 + line: 1 + character: 32 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 31 + line: 1 + character: 32 + end_position: + bytes: 32 + line: 1 + character: 33 + token_type: + type: Whitespace + characters: " " + declare_as: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 32 + line: 1 + character: 33 + end_position: + bytes: 35 + line: 1 + character: 36 + token_type: + type: Symbol + symbol: nil + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 35 + line: 1 + character: 36 + end_position: + bytes: 35 + line: 1 + character: 36 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/ast_to_string.snap new file mode 100644 index 00000000..2f89630d --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +"type Foo = nil" + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/error_display.snap new file mode 100644 index 00000000..4e85ede4 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/error_display.snap @@ -0,0 +1,11 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: expected default type after type name + ┌─ source.lua:1:29 + │ +1 │ type Foo = nil + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/errors.snap b/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/errors.snap new file mode 100644 index 00000000..7e6499f8 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_must_declare_default/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 28 + line: 1 + character: 29 + end_position: + bytes: 29 + line: 1 + character: 30 + token_type: + type: Symbol + symbol: ">" + additional: expected default type after type name + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_nil/ast.snap b/full-moon/tests/roblox_cases/fail/parser/generic_nil/ast.snap new file mode 100644 index 00000000..c3747b8a --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_nil/ast.snap @@ -0,0 +1,118 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - TypeDeclaration: + type_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Identifier + identifier: Foo + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + generics: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " + declare_as: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: nil + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 23 + line: 2 + character: 1 + end_position: + bytes: 23 + line: 2 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_nil/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/generic_nil/ast_to_string.snap new file mode 100644 index 00000000..8878d984 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_nil/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +type Foo = nil + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_nil/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/generic_nil/error_display.snap new file mode 100644 index 00000000..bd14c61a --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_nil/error_display.snap @@ -0,0 +1,23 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:15 + │ +1 │ type Foo = nil + │ ^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:1:22 + │ +1 │ type Foo = nil + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:22 + │ +1 │ type Foo = nil + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_nil/errors.snap b/full-moon/tests/roblox_cases/fail/parser/generic_nil/errors.snap new file mode 100644 index 00000000..94c1bbb2 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_nil/errors.snap @@ -0,0 +1,47 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: "<" + additional: "unexpected token, this needs to be a statement" +- AstError: + token: + start_position: + bytes: 21 + line: 1 + character: 22 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Symbol + symbol: ">" + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 21 + line: 1 + character: 22 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Symbol + symbol: ">" + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_string/ast.snap b/full-moon/tests/roblox_cases/fail/parser/generic_string/ast.snap new file mode 100644 index 00000000..ca8fa501 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_string/ast.snap @@ -0,0 +1,119 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - TypeDeclaration: + type_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Identifier + identifier: Foo + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + generics: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " + declare_as: + String: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: StringLiteral + literal: bar + quote_type: Double + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 25 + line: 2 + character: 1 + end_position: + bytes: 25 + line: 2 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_string/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/generic_string/ast_to_string.snap new file mode 100644 index 00000000..44d94364 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_string/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +"type Foo = \"bar\"" + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_string/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/generic_string/error_display.snap new file mode 100644 index 00000000..e2d8f5f1 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_string/error_display.snap @@ -0,0 +1,23 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:17 + │ +1 │ type Foo = "bar" + │ ^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:1:24 + │ +1 │ type Foo = "bar" + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:24 + │ +1 │ type Foo = "bar" + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/generic_string/errors.snap b/full-moon/tests/roblox_cases/fail/parser/generic_string/errors.snap new file mode 100644 index 00000000..6630fae1 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/generic_string/errors.snap @@ -0,0 +1,47 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Symbol + symbol: "<" + additional: "unexpected token, this needs to be a statement" +- AstError: + token: + start_position: + bytes: 23 + line: 1 + character: 24 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Symbol + symbol: ">" + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 23 + line: 1 + character: 24 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Symbol + symbol: ">" + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/ast.snap b/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/ast.snap new file mode 100644 index 00000000..cbaa915d --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/ast.snap @@ -0,0 +1,21 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: [] +eof: + leading_trivia: [] + token: + start_position: + bytes: 26 + line: 1 + character: 27 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/ast_to_string.snap new file mode 100644 index 00000000..94726381 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +"" + diff --git a/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/error_display.snap new file mode 100644 index 00000000..9179dfeb --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/error_display.snap @@ -0,0 +1,11 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: expected `->` after `()` for function type + ┌─ source.lua:1:27 + │ +1 │ type Foo = (count: number) + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/errors.snap b/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/errors.snap new file mode 100644 index 00000000..ff46da5c --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/named_function_arg_types/errors.snap @@ -0,0 +1,18 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 26 + line: 1 + character: 27 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Eof + additional: "expected `->` after `()` for function type" + diff --git a/full-moon/tests/roblox_cases/fail/parser/nil_dot/ast.snap b/full-moon/tests/roblox_cases/fail/parser/nil_dot/ast.snap new file mode 100644 index 00000000..1db975be --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/nil_dot/ast.snap @@ -0,0 +1,118 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - TypeDeclaration: + type_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Identifier + identifier: Foo + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + generics: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " + declare_as: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Symbol + symbol: nil + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 27 + line: 2 + character: 1 + end_position: + bytes: 27 + line: 2 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/nil_dot/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/nil_dot/ast_to_string.snap new file mode 100644 index 00000000..8878d984 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/nil_dot/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +type Foo = nil + diff --git a/full-moon/tests/roblox_cases/fail/parser/nil_dot/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/nil_dot/error_display.snap new file mode 100644 index 00000000..0e6b920e --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/nil_dot/error_display.snap @@ -0,0 +1,35 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:15 + │ +1 │ type Foo = nil.bar + │ ^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:1:19 + │ +1 │ type Foo = nil.bar + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:19 + │ +1 │ type Foo = nil.bar + │ ^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:1:26 + │ +1 │ type Foo = nil.bar + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:26 + │ +1 │ type Foo = nil.bar + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/nil_dot/errors.snap b/full-moon/tests/roblox_cases/fail/parser/nil_dot/errors.snap new file mode 100644 index 00000000..47554f28 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/nil_dot/errors.snap @@ -0,0 +1,75 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: "." + additional: "unexpected token, this needs to be a statement" +- AstError: + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Symbol + symbol: "<" + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 18 + line: 1 + character: 19 + end_position: + bytes: 19 + line: 1 + character: 20 + token_type: + type: Symbol + symbol: "<" + additional: "unexpected token, this needs to be a statement" +- AstError: + token: + start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Symbol + symbol: ">" + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Symbol + symbol: ">" + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/ast.snap b/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/ast.snap new file mode 100644 index 00000000..dbe769f4 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/ast.snap @@ -0,0 +1,148 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - FunctionDeclaration: + function_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: function + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + name: + names: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Identifier + identifier: foo + trailing_trivia: [] + colon_name: ~ + body: + generics: ~ + parameters_parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 35 + line: 1 + character: 36 + end_position: + bytes: 36 + line: 1 + character: 37 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 36 + line: 1 + character: 37 + end_position: + bytes: 37 + line: 1 + character: 37 + token_type: + type: Whitespace + characters: "\n" + parameters: + pairs: + - End: + Name: + leading_trivia: [] + token: + start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Identifier + identifier: test + trailing_trivia: [] + type_specifiers: + - ~ + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 37 + line: 2 + character: 1 + end_position: + bytes: 40 + line: 2 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 40 + line: 2 + character: 4 + end_position: + bytes: 40 + line: 2 + character: 4 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/ast_to_string.snap new file mode 100644 index 00000000..e9161b7b --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +"function foo(test)\nend" + diff --git a/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/error_display.snap new file mode 100644 index 00000000..b6408063 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/error_display.snap @@ -0,0 +1,17 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: expected `->` after `()` for function type + ┌─ source.lua:1:36 + │ +1 │ function foo(test: (number, number)) + │ ^ + +error[ast]: expected type info after `:` + ┌─ source.lua:1:18 + │ +1 │ function foo(test: (number, number)) + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/errors.snap b/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/errors.snap new file mode 100644 index 00000000..a7430465 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/param_tuple_types/errors.snap @@ -0,0 +1,33 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 35 + line: 1 + character: 36 + end_position: + bytes: 36 + line: 1 + character: 37 + token_type: + type: Symbol + symbol: ) + additional: "expected `->` after `()` for function type" +- AstError: + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: ":" + additional: "expected type info after `:`" + diff --git a/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/ast.snap b/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/ast.snap new file mode 100644 index 00000000..88030751 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/ast.snap @@ -0,0 +1,136 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - FunctionDeclaration: + function_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: function + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + name: + names: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Identifier + identifier: bar + trailing_trivia: [] + colon_name: ~ + body: + generics: ~ + parameters_parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + parameters: + pairs: + - End: + Name: + leading_trivia: [] + token: + start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 17 + line: 1 + character: 18 + token_type: + type: Identifier + identifier: test + trailing_trivia: [] + type_specifiers: [] + block: + stmts: [] + end_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: end + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 34 + line: 3 + character: 1 + end_position: + bytes: 34 + line: 3 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/ast_to_string.snap new file mode 100644 index 00000000..7a2b65a3 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +function bar(test)end + diff --git a/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/error_display.snap new file mode 100644 index 00000000..c63a1508 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/error_display.snap @@ -0,0 +1,35 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: expected type info after `:` + ┌─ source.lua:1:18 + │ +1 │ function bar(test: ...number) + │ ^ + +error[ast]: expected a `)` + ┌─ source.lua:1:20 + │ +1 │ function bar(test: ...number) + │ ^^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:20 + │ +1 │ function bar(test: ...number) + │ ^^^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:1:29 + │ +1 │ function bar(test: ...number) + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:29 + │ +1 │ function bar(test: ...number) + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/errors.snap b/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/errors.snap new file mode 100644 index 00000000..83841cab --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/param_variadic_types/errors.snap @@ -0,0 +1,75 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 17 + line: 1 + character: 18 + end_position: + bytes: 18 + line: 1 + character: 19 + token_type: + type: Symbol + symbol: ":" + additional: "expected type info after `:`" +- AstError: + token: + start_position: + bytes: 19 + line: 1 + character: 20 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Symbol + symbol: "..." + additional: "expected a `)`" +- AstError: + token: + start_position: + bytes: 19 + line: 1 + character: 20 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Symbol + symbol: "..." + additional: "unexpected token, this needs to be a statement" +- AstError: + token: + start_position: + bytes: 28 + line: 1 + character: 29 + end_position: + bytes: 29 + line: 1 + character: 30 + token_type: + type: Symbol + symbol: ) + additional: unexpected expression when looking for a statement +- AstError: + token: + start_position: + bytes: 28 + line: 1 + character: 29 + end_position: + bytes: 29 + line: 1 + character: 30 + token_type: + type: Symbol + symbol: ) + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/ast.snap b/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/ast.snap new file mode 100644 index 00000000..4844e917 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/ast.snap @@ -0,0 +1,21 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: [] +eof: + leading_trivia: [] + token: + start_position: + bytes: 22 + line: 1 + character: 23 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/ast_to_string.snap new file mode 100644 index 00000000..94726381 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +"" + diff --git a/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/error_display.snap new file mode 100644 index 00000000..96cd8a18 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/error_display.snap @@ -0,0 +1,11 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: expected `->` after `()` for function type + ┌─ source.lua:1:23 + │ +1 │ type Foo = (...number) + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/errors.snap b/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/errors.snap new file mode 100644 index 00000000..d58764b2 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/parentheses_variadic_types/errors.snap @@ -0,0 +1,18 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 22 + line: 1 + character: 23 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Eof + additional: "expected `->` after `()` for function type" + diff --git a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/ast.snap b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/ast.snap new file mode 100644 index 00000000..32a2a1c5 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/ast.snap @@ -0,0 +1,225 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 23 +expression: result.ast +input_file: full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: _ + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + InterpolatedString: + segments: + - literal: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 20 + line: 1 + character: 21 + token_type: + type: InterpolatedString + literal: "2 + 2 = " + kind: Begin + trailing_trivia: [] + expression: + BinaryOperator: + lhs: + Number: + leading_trivia: [] + token: + start_position: + bytes: 21 + line: 1 + character: 22 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Number + text: "2" + trailing_trivia: + - start_position: + bytes: 22 + line: 1 + character: 23 + end_position: + bytes: 23 + line: 1 + character: 24 + token_type: + type: Whitespace + characters: " " + binop: + Plus: + leading_trivia: [] + token: + start_position: + bytes: 23 + line: 1 + character: 24 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Symbol + symbol: + + trailing_trivia: + - start_position: + bytes: 24 + line: 1 + character: 25 + end_position: + bytes: 25 + line: 1 + character: 26 + token_type: + type: Whitespace + characters: " " + rhs: + Number: + leading_trivia: [] + token: + start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Number + text: "2" + trailing_trivia: [] + last_string: + leading_trivia: [] + token: + start_position: + bytes: 27 + line: 1 + character: 28 + end_position: + bytes: 29 + line: 1 + character: 30 + token_type: + type: InterpolatedString + literal: "" + kind: End + trailing_trivia: + - start_position: + bytes: 29 + line: 1 + character: 30 + end_position: + bytes: 30 + line: 1 + character: 30 + token_type: + type: Whitespace + characters: "\n" + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 30 + line: 2 + character: 1 + end_position: + bytes: 30 + line: 2 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/ast_to_string.snap new file mode 100644 index 00000000..f427119d --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery +--- +"local _ = `2 + 2 = {2 + 2}`\n" + diff --git a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/error_display.snap new file mode 100644 index 00000000..928a1074 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery +--- +error[ast]: unexpected double brace, try \{ if you meant to escape + ┌─ source.lua:1:21 + │ +1 │ local _ = `2 + 2 = {{2 + 2}}` + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/errors.snap b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/errors.snap new file mode 100644 index 00000000..c6653f8b --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/errors.snap @@ -0,0 +1,21 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 22 +expression: result.errors +input_file: full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery +--- +- AstError: + token: + start_position: + bytes: 20 + line: 1 + character: 21 + end_position: + bytes: 21 + line: 1 + character: 22 + token_type: + type: Symbol + symbol: "{" + additional: "unexpected double brace, try \\{ if you meant to escape" + diff --git a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/source.lua b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/source.lua new file mode 100644 index 00000000..892d9b52 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/source.lua @@ -0,0 +1 @@ +local _ = `2 + 2 = {{2 + 2}}` diff --git a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/tokens.snap b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/tokens.snap new file mode 100644 index 00000000..ed8e6e1a --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery/tokens.snap @@ -0,0 +1,195 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 68 +expression: tokens +input_file: full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace-recovery +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local +- start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: _ +- start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 20 + line: 1 + character: 21 + token_type: + type: InterpolatedString + literal: "2 + 2 = " + kind: Begin +- start_position: + bytes: 20 + line: 1 + character: 21 + end_position: + bytes: 21 + line: 1 + character: 22 + token_type: + type: Symbol + symbol: "{" +- start_position: + bytes: 21 + line: 1 + character: 22 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Number + text: "2" +- start_position: + bytes: 22 + line: 1 + character: 23 + end_position: + bytes: 23 + line: 1 + character: 24 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 23 + line: 1 + character: 24 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Symbol + symbol: + +- start_position: + bytes: 24 + line: 1 + character: 25 + end_position: + bytes: 25 + line: 1 + character: 26 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Number + text: "2" +- start_position: + bytes: 26 + line: 1 + character: 27 + end_position: + bytes: 27 + line: 1 + character: 28 + token_type: + type: Symbol + symbol: "}" +- start_position: + bytes: 27 + line: 1 + character: 28 + end_position: + bytes: 29 + line: 1 + character: 30 + token_type: + type: InterpolatedString + literal: "" + kind: End +- start_position: + bytes: 29 + line: 1 + character: 30 + end_position: + bytes: 30 + line: 1 + character: 30 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 30 + line: 2 + character: 1 + end_position: + bytes: 30 + line: 2 + character: 1 + token_type: + type: Eof + diff --git a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/ast.snap b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/ast.snap new file mode 100644 index 00000000..a7289af8 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/ast.snap @@ -0,0 +1,101 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 23 +expression: result.ast +input_file: full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace +--- +nodes: + stmts: + - - Assignment: + var_list: + pairs: + - End: + Name: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Identifier + identifier: _ + trailing_trivia: + - start_position: + bytes: 1 + line: 1 + character: 2 + end_position: + bytes: 2 + line: 1 + character: 3 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 2 + line: 1 + character: 3 + end_position: + bytes: 3 + line: 1 + character: 4 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 3 + line: 1 + character: 4 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + InterpolatedString: + segments: [] + last_string: + leading_trivia: [] + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: InterpolatedString + literal: "" + kind: Begin + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 11 + line: 2 + character: 1 + end_position: + bytes: 11 + line: 2 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/ast_to_string.snap new file mode 100644 index 00000000..74b562c2 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace +--- +"_ = `{" + diff --git a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/error.snap b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/error.snap deleted file mode 100644 index d077032e..00000000 --- a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/error.snap +++ /dev/null @@ -1,21 +0,0 @@ ---- -source: full-moon/tests/fail_cases.rs -assertion_line: 58 -expression: error -input_file: full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace ---- -UnexpectedToken: - token: - start_position: - bytes: 6 - line: 1 - character: 7 - end_position: - bytes: 7 - line: 1 - character: 8 - token_type: - type: Symbol - symbol: "{" - additional: "unexpected double brace for interpolated string. try \\{ if you meant to escape" - diff --git a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/error_display.snap new file mode 100644 index 00000000..e4b74a6a --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/error_display.snap @@ -0,0 +1,25 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace +--- +error[ast]: unexpected double brace, try \{ if you meant to escape + ┌─ source.lua:1:7 + │ +1 │ _ = `{{}}` + │ ^ + +error[ast]: expected expression after `{` + ┌─ source.lua:1:5 + │ +1 │ _ = `{{}}` + │ ^^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:1:8 + │ +1 │ _ = `{{}}` + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/errors.snap b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/errors.snap new file mode 100644 index 00000000..ab39e02d --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace/errors.snap @@ -0,0 +1,50 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 22 +expression: result.errors +input_file: full-moon/tests/roblox_cases/fail/parser/string-interpolation-double-brace +--- +- AstError: + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Symbol + symbol: "{" + additional: "unexpected double brace, try \\{ if you meant to escape" +- AstError: + token: + start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: InterpolatedString + literal: "" + kind: Begin + additional: "expected expression after `{`" +- AstError: + token: + start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Symbol + symbol: "}" + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast.snap b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast.snap new file mode 100644 index 00000000..a92add7d --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast.snap @@ -0,0 +1,412 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.ast +--- +nodes: + stmts: + - - TypeDeclaration: + type_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Identifier + identifier: Foo + trailing_trivia: + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " + generics: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " + declare_as: + Table: + braces: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: "{" + trailing_trivia: + - start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Whitespace + characters: " " + - leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 1 + line: 1 + character: 2 + token_type: + type: Symbol + symbol: "}" + trailing_trivia: [] + fields: + pairs: + - Punctuated: + - key: + Name: + leading_trivia: [] + token: + start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Identifier + identifier: x + trailing_trivia: [] + colon: + leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: ":" + trailing_trivia: + - start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Whitespace + characters: " " + value: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Identifier + identifier: string + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 22 + line: 1 + character: 23 + end_position: + bytes: 23 + line: 1 + character: 24 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 23 + line: 1 + character: 24 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Whitespace + characters: " " + - End: + key: + Name: + leading_trivia: [] + token: + start_position: + bytes: 24 + line: 1 + character: 25 + end_position: + bytes: 25 + line: 1 + character: 26 + token_type: + type: Identifier + identifier: y + trailing_trivia: [] + colon: + leading_trivia: [] + token: + start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Symbol + symbol: ":" + trailing_trivia: + - start_position: + bytes: 26 + line: 1 + character: 27 + end_position: + bytes: 27 + line: 1 + character: 28 + token_type: + type: Whitespace + characters: " " + value: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 27 + line: 1 + character: 28 + end_position: + bytes: 33 + line: 1 + character: 34 + token_type: + type: Identifier + identifier: string + trailing_trivia: + - start_position: + bytes: 33 + line: 1 + character: 34 + end_position: + bytes: 34 + line: 1 + character: 34 + token_type: + type: Whitespace + characters: "\n" + - ~ + - - LocalAssignment: + local_token: + leading_trivia: + - start_position: + bytes: 34 + line: 2 + character: 1 + end_position: + bytes: 35 + line: 2 + character: 1 + token_type: + type: Whitespace + characters: "\n" + token: + start_position: + bytes: 35 + line: 3 + character: 1 + end_position: + bytes: 40 + line: 3 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 40 + line: 3 + character: 6 + end_position: + bytes: 41 + line: 3 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 41 + line: 3 + character: 7 + end_position: + bytes: 42 + line: 3 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 42 + line: 3 + character: 8 + end_position: + bytes: 43 + line: 3 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 43 + line: 3 + character: 9 + end_position: + bytes: 44 + line: 3 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 44 + line: 3 + character: 10 + end_position: + bytes: 45 + line: 3 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 45 + line: 3 + character: 11 + end_position: + bytes: 46 + line: 3 + character: 12 + token_type: + type: Number + text: "1" + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 46 + line: 3 + character: 12 + end_position: + bytes: 46 + line: 3 + character: 12 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast_to_string.snap new file mode 100644 index 00000000..94f70dd7 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast_to_string.snap @@ -0,0 +1,6 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "full_moon::print(&ast)" +--- +"type Foo = { x: string, y: string\n}\nlocal x = 1" + diff --git a/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/error_display.snap b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/error_display.snap new file mode 100644 index 00000000..dc218d2c --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/error_display.snap @@ -0,0 +1,11 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: "String::from_utf8(output.into_inner()).unwrap()" +--- +error[ast]: expected `}` to close type table + ┌─ source.lua:3:1 + │ +3 │ local x = 1 + │ ^^^^^ + + diff --git a/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/errors.snap b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/errors.snap new file mode 100644 index 00000000..91e6c7c6 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/errors.snap @@ -0,0 +1,19 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: result.errors +--- +- AstError: + token: + start_position: + bytes: 35 + line: 3 + character: 1 + end_position: + bytes: 40 + line: 3 + character: 6 + token_type: + type: Symbol + symbol: local + additional: "expected `}` to close type table" + diff --git a/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/source.lua b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/source.lua new file mode 100644 index 00000000..c882c335 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/source.lua @@ -0,0 +1,3 @@ +type Foo = { x: string, y: string + +local x = 1 \ No newline at end of file diff --git a/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/tokens.snap b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/tokens.snap new file mode 100644 index 00000000..fc10df6d --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/parser/type_table_no_right_brace/tokens.snap @@ -0,0 +1,312 @@ +--- +source: full-moon/tests/fail_cases.rs +expression: tokens +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type +- start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Identifier + identifier: Foo +- start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Symbol + symbol: "{" +- start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Identifier + identifier: x +- start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: ":" +- start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 17 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 22 + line: 1 + character: 23 + token_type: + type: Identifier + identifier: string +- start_position: + bytes: 22 + line: 1 + character: 23 + end_position: + bytes: 23 + line: 1 + character: 24 + token_type: + type: Symbol + symbol: "," +- start_position: + bytes: 23 + line: 1 + character: 24 + end_position: + bytes: 24 + line: 1 + character: 25 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 24 + line: 1 + character: 25 + end_position: + bytes: 25 + line: 1 + character: 26 + token_type: + type: Identifier + identifier: y +- start_position: + bytes: 25 + line: 1 + character: 26 + end_position: + bytes: 26 + line: 1 + character: 27 + token_type: + type: Symbol + symbol: ":" +- start_position: + bytes: 26 + line: 1 + character: 27 + end_position: + bytes: 27 + line: 1 + character: 28 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 27 + line: 1 + character: 28 + end_position: + bytes: 33 + line: 1 + character: 34 + token_type: + type: Identifier + identifier: string +- start_position: + bytes: 33 + line: 1 + character: 34 + end_position: + bytes: 34 + line: 1 + character: 34 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 34 + line: 2 + character: 1 + end_position: + bytes: 35 + line: 2 + character: 1 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 35 + line: 3 + character: 1 + end_position: + bytes: 40 + line: 3 + character: 6 + token_type: + type: Symbol + symbol: local +- start_position: + bytes: 40 + line: 3 + character: 6 + end_position: + bytes: 41 + line: 3 + character: 7 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 41 + line: 3 + character: 7 + end_position: + bytes: 42 + line: 3 + character: 8 + token_type: + type: Identifier + identifier: x +- start_position: + bytes: 42 + line: 3 + character: 8 + end_position: + bytes: 43 + line: 3 + character: 9 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 43 + line: 3 + character: 9 + end_position: + bytes: 44 + line: 3 + character: 10 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 44 + line: 3 + character: 10 + end_position: + bytes: 45 + line: 3 + character: 11 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 45 + line: 3 + character: 11 + end_position: + bytes: 46 + line: 3 + character: 12 + token_type: + type: Number + text: "1" +- start_position: + bytes: 46 + line: 3 + character: 12 + end_position: + bytes: 46 + line: 3 + character: 12 + token_type: + type: Eof + diff --git a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/ast.snap b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/ast.snap new file mode 100644 index 00000000..6274d0ad --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/ast.snap @@ -0,0 +1,218 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 23 +expression: result.ast +input_file: full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + InterpolatedString: + segments: [] + last_string: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: InterpolatedString + literal: ab + kind: Simple + trailing_trivia: + - start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 14 + token_type: + type: Whitespace + characters: "\n" + - ~ + - - FunctionCall: + prefix: + Name: + leading_trivia: [] + token: + start_position: + bytes: 18 + line: 3 + character: 1 + end_position: + bytes: 23 + line: 3 + character: 6 + token_type: + type: Identifier + identifier: print + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 23 + line: 3 + character: 6 + end_position: + bytes: 24 + line: 3 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 25 + line: 3 + character: 8 + end_position: + bytes: 26 + line: 3 + character: 9 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 26 + line: 3 + character: 9 + end_position: + bytes: 27 + line: 3 + character: 9 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: + - End: + Number: + leading_trivia: [] + token: + start_position: + bytes: 24 + line: 3 + character: 7 + end_position: + bytes: 25 + line: 3 + character: 8 + token_type: + type: Number + text: "1" + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 27 + line: 4 + character: 1 + end_position: + bytes: 27 + line: 4 + character: 1 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/ast_to_string.snap b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/ast_to_string.snap new file mode 100644 index 00000000..be0a61d2 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/ast_to_string.snap @@ -0,0 +1,8 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 28 +expression: "full_moon::print(&ast)" +input_file: full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line +--- +"local x = `ab`\nprint(1)\n" + diff --git a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/error_display.snap b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/error_display.snap new file mode 100644 index 00000000..8ebb2e52 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/error_display.snap @@ -0,0 +1,31 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line +--- +error[tokenizer]: unclosed string (1:11 to 1:14) + ┌─ source.lua:1:11 + │ +1 │ local x = `ab + │ ^^^ + +error[ast]: unexpected expression when looking for a statement + ┌─ source.lua:2:3 + │ +2 │ cd` + │ ^ + +error[tokenizer]: unclosed string (2:3 to 2:4) + ┌─ source.lua:2:3 + │ +2 │ cd` + │ ^ + +error[ast]: unexpected token, this needs to be a statement + ┌─ source.lua:2:3 + │ +2 │ cd` + │ ^ + + diff --git a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/errors.snap b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/errors.snap new file mode 100644 index 00000000..0fd7b8a5 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/errors.snap @@ -0,0 +1,55 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 22 +expression: result.errors +input_file: full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line +--- +- TokenizerError: + error: UnclosedString + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 13 + line: 1 + character: 14 +- AstError: + token: + start_position: + bytes: 16 + line: 2 + character: 3 + end_position: + bytes: 17 + line: 2 + character: 4 + token_type: + type: InterpolatedString + literal: "" + kind: Simple + additional: unexpected expression when looking for a statement +- TokenizerError: + error: UnclosedString + range: + - bytes: 16 + line: 2 + character: 3 + - bytes: 17 + line: 2 + character: 4 +- AstError: + token: + start_position: + bytes: 16 + line: 2 + character: 3 + end_position: + bytes: 17 + line: 2 + character: 4 + token_type: + type: InterpolatedString + literal: "" + kind: Simple + additional: "unexpected token, this needs to be a statement" + diff --git a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/source.lua b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/source.lua new file mode 100644 index 00000000..2ff47718 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/source.lua @@ -0,0 +1,3 @@ +local x = `ab +cd` +print(1) diff --git a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/tokens_result.snap b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/tokens_result.snap new file mode 100644 index 00000000..b1930fca --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line/tokens_result.snap @@ -0,0 +1,212 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 112 +expression: tokens +input_file: full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation-with-new-line +--- +Recovered: + - - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: x + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: InterpolatedString + literal: ab + kind: Simple + - start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 14 + token_type: + type: Whitespace + characters: "\n" + - start_position: + bytes: 14 + line: 2 + character: 1 + end_position: + bytes: 16 + line: 2 + character: 3 + token_type: + type: Identifier + identifier: cd + - start_position: + bytes: 16 + line: 2 + character: 3 + end_position: + bytes: 17 + line: 2 + character: 4 + token_type: + type: InterpolatedString + literal: "" + kind: Simple + - start_position: + bytes: 17 + line: 2 + character: 4 + end_position: + bytes: 18 + line: 2 + character: 4 + token_type: + type: Whitespace + characters: "\n" + - start_position: + bytes: 18 + line: 3 + character: 1 + end_position: + bytes: 23 + line: 3 + character: 6 + token_type: + type: Identifier + identifier: print + - start_position: + bytes: 23 + line: 3 + character: 6 + end_position: + bytes: 24 + line: 3 + character: 7 + token_type: + type: Symbol + symbol: ( + - start_position: + bytes: 24 + line: 3 + character: 7 + end_position: + bytes: 25 + line: 3 + character: 8 + token_type: + type: Number + text: "1" + - start_position: + bytes: 25 + line: 3 + character: 8 + end_position: + bytes: 26 + line: 3 + character: 9 + token_type: + type: Symbol + symbol: ) + - start_position: + bytes: 26 + line: 3 + character: 9 + end_position: + bytes: 27 + line: 3 + character: 9 + token_type: + type: Whitespace + characters: "\n" + - start_position: + bytes: 27 + line: 4 + character: 1 + end_position: + bytes: 27 + line: 4 + character: 1 + token_type: + type: Eof + - - error: UnclosedString + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 13 + line: 1 + character: 14 + - error: UnclosedString + range: + - bytes: 16 + line: 2 + character: 3 + - bytes: 17 + line: 2 + character: 4 + diff --git a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/ast.snap b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/ast.snap new file mode 100644 index 00000000..0a9f0906 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/ast.snap @@ -0,0 +1,126 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 23 +expression: result.ast +input_file: full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation +--- +nodes: + stmts: + - - LocalAssignment: + local_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + trailing_trivia: + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + name_list: + pairs: + - End: + leading_trivia: [] + token: + start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: _ + trailing_trivia: + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + expr_list: + pairs: + - End: + InterpolatedString: + segments: [] + last_string: + leading_trivia: [] + token: + start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: InterpolatedString + literal: asdf + kind: Simple + trailing_trivia: [] + - ~ +eof: + leading_trivia: [] + token: + start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Eof + trailing_trivia: [] + diff --git a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/error.snap b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/ast_to_string.snap similarity index 55% rename from full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/error.snap rename to full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/ast_to_string.snap index 3548efc5..311a440a 100644 --- a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/error.snap +++ b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/ast_to_string.snap @@ -1,12 +1,8 @@ --- source: full-moon/tests/fail_cases.rs -assertion_line: 74 -expression: error +assertion_line: 28 +expression: "full_moon::print(&ast)" input_file: full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation --- -error: UnclosedString -position: - bytes: 10 - line: 1 - character: 11 +"local _ = `asdf`" diff --git a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/error_display.snap b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/error_display.snap new file mode 100644 index 00000000..9f863b5f --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/error_display.snap @@ -0,0 +1,13 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 56 +expression: "String::from_utf8(output.into_inner()).unwrap()" +input_file: full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation +--- +error[tokenizer]: unclosed string (1:11 to 1:16) + ┌─ source.lua:1:11 + │ +1 │ local _ = `asdf + │ ^^^^^ + + diff --git a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/errors.snap b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/errors.snap new file mode 100644 index 00000000..b996775d --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/errors.snap @@ -0,0 +1,16 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 22 +expression: result.errors +input_file: full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation +--- +- TokenizerError: + error: UnclosedString + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 15 + line: 1 + character: 16 + diff --git a/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/tokens_result.snap b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/tokens_result.snap new file mode 100644 index 00000000..a2c3ea94 --- /dev/null +++ b/full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation/tokens_result.snap @@ -0,0 +1,104 @@ +--- +source: full-moon/tests/fail_cases.rs +assertion_line: 113 +expression: tokens +input_file: full-moon/tests/roblox_cases/fail/tokenizer/unfinished-string-interpolation +--- +Recovered: + - - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Symbol + symbol: local + - start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 6 + line: 1 + character: 7 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 6 + line: 1 + character: 7 + end_position: + bytes: 7 + line: 1 + character: 8 + token_type: + type: Identifier + identifier: _ + - start_position: + bytes: 7 + line: 1 + character: 8 + end_position: + bytes: 8 + line: 1 + character: 9 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 8 + line: 1 + character: 9 + end_position: + bytes: 9 + line: 1 + character: 10 + token_type: + type: Symbol + symbol: "=" + - start_position: + bytes: 9 + line: 1 + character: 10 + end_position: + bytes: 10 + line: 1 + character: 11 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 10 + line: 1 + character: 11 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: InterpolatedString + literal: asdf + kind: Simple + - start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Eof + - - error: UnclosedString + range: + - bytes: 10 + line: 1 + character: 11 + - bytes: 15 + line: 1 + character: 16 + diff --git a/full-moon/tests/roblox_cases/pass/generic_functions/ast.snap b/full-moon/tests/roblox_cases/pass/generic_functions/ast.snap index f627ed93..363b446b 100644 --- a/full-moon/tests/roblox_cases/pass/generic_functions/ast.snap +++ b/full-moon/tests/roblox_cases/pass/generic_functions/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/roblox_cases/pass/generic_functions --- stmts: - - FunctionDeclaration: @@ -939,84 +937,31 @@ stmts: type_info: Union: left: - Basic: - leading_trivia: [] - token: - start_position: - bytes: 112 - line: 11 - character: 6 - end_position: - bytes: 115 - line: 11 - character: 9 - token_type: - type: Symbol - symbol: nil - trailing_trivia: - - start_position: - bytes: 115 - line: 11 - character: 9 - end_position: - bytes: 116 - line: 11 - character: 10 - token_type: - type: Whitespace - characters: " " - pipe: - leading_trivia: [] - token: - start_position: - bytes: 116 - line: 11 - character: 10 - end_position: - bytes: 117 - line: 11 - character: 11 - token_type: - type: Symbol - symbol: "|" - trailing_trivia: - - start_position: - bytes: 117 - line: 11 - character: 11 - end_position: - bytes: 118 - line: 11 - character: 12 - token_type: - type: Whitespace - characters: " " - right: Union: left: Basic: leading_trivia: [] token: start_position: - bytes: 118 + bytes: 112 line: 11 - character: 12 + character: 6 end_position: - bytes: 124 + bytes: 115 line: 11 - character: 18 + character: 9 token_type: - type: Identifier - identifier: number + type: Symbol + symbol: nil trailing_trivia: - start_position: - bytes: 124 + bytes: 115 line: 11 - character: 18 + character: 9 end_position: - bytes: 125 + bytes: 116 line: 11 - character: 19 + character: 10 token_type: type: Whitespace characters: " " @@ -1024,25 +969,25 @@ stmts: leading_trivia: [] token: start_position: - bytes: 125 + bytes: 116 line: 11 - character: 19 + character: 10 end_position: - bytes: 126 + bytes: 117 line: 11 - character: 20 + character: 11 token_type: type: Symbol symbol: "|" trailing_trivia: - start_position: - bytes: 126 + bytes: 117 line: 11 - character: 20 + character: 11 end_position: - bytes: 127 + bytes: 118 line: 11 - character: 21 + character: 12 token_type: type: Whitespace characters: " " @@ -1051,28 +996,81 @@ stmts: leading_trivia: [] token: start_position: - bytes: 127 + bytes: 118 line: 11 - character: 21 + character: 12 end_position: - bytes: 134 + bytes: 124 line: 11 - character: 28 + character: 18 token_type: type: Identifier - identifier: boolean + identifier: number trailing_trivia: - start_position: - bytes: 134 + bytes: 124 line: 11 - character: 28 + character: 18 end_position: - bytes: 135 + bytes: 125 line: 11 - character: 28 + character: 19 token_type: type: Whitespace - characters: "\n" + characters: " " + pipe: + leading_trivia: [] + token: + start_position: + bytes: 125 + line: 11 + character: 19 + end_position: + bytes: 126 + line: 11 + character: 20 + token_type: + type: Symbol + symbol: "|" + trailing_trivia: + - start_position: + bytes: 126 + line: 11 + character: 20 + end_position: + bytes: 127 + line: 11 + character: 21 + token_type: + type: Whitespace + characters: " " + right: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 127 + line: 11 + character: 21 + end_position: + bytes: 134 + line: 11 + character: 28 + token_type: + type: Identifier + identifier: boolean + trailing_trivia: + - start_position: + bytes: 134 + line: 11 + character: 28 + end_position: + bytes: 135 + line: 11 + character: 28 + token_type: + type: Whitespace + characters: "\n" arrow: leading_trivia: [] token: @@ -1683,84 +1681,31 @@ stmts: type_info: Union: left: - Basic: - leading_trivia: [] - token: - start_position: - bytes: 202 - line: 18 - character: 6 - end_position: - bytes: 205 - line: 18 - character: 9 - token_type: - type: Symbol - symbol: nil - trailing_trivia: - - start_position: - bytes: 205 - line: 18 - character: 9 - end_position: - bytes: 206 - line: 18 - character: 10 - token_type: - type: Whitespace - characters: " " - pipe: - leading_trivia: [] - token: - start_position: - bytes: 206 - line: 18 - character: 10 - end_position: - bytes: 207 - line: 18 - character: 11 - token_type: - type: Symbol - symbol: "|" - trailing_trivia: - - start_position: - bytes: 207 - line: 18 - character: 11 - end_position: - bytes: 208 - line: 18 - character: 12 - token_type: - type: Whitespace - characters: " " - right: Union: left: Basic: leading_trivia: [] token: start_position: - bytes: 208 + bytes: 202 line: 18 - character: 12 + character: 6 end_position: - bytes: 214 + bytes: 205 line: 18 - character: 18 + character: 9 token_type: - type: Identifier - identifier: number + type: Symbol + symbol: nil trailing_trivia: - start_position: - bytes: 214 + bytes: 205 line: 18 - character: 18 + character: 9 end_position: - bytes: 215 + bytes: 206 line: 18 - character: 19 + character: 10 token_type: type: Whitespace characters: " " @@ -1768,25 +1713,25 @@ stmts: leading_trivia: [] token: start_position: - bytes: 215 + bytes: 206 line: 18 - character: 19 + character: 10 end_position: - bytes: 216 + bytes: 207 line: 18 - character: 20 + character: 11 token_type: type: Symbol symbol: "|" trailing_trivia: - start_position: - bytes: 216 + bytes: 207 line: 18 - character: 20 + character: 11 end_position: - bytes: 217 + bytes: 208 line: 18 - character: 21 + character: 12 token_type: type: Whitespace characters: " " @@ -1795,28 +1740,81 @@ stmts: leading_trivia: [] token: start_position: - bytes: 217 + bytes: 208 line: 18 - character: 21 + character: 12 end_position: - bytes: 224 + bytes: 214 line: 18 - character: 28 + character: 18 token_type: type: Identifier - identifier: boolean + identifier: number trailing_trivia: - start_position: - bytes: 224 + bytes: 214 line: 18 - character: 28 + character: 18 end_position: - bytes: 225 + bytes: 215 line: 18 - character: 28 + character: 19 token_type: type: Whitespace - characters: "\n" + characters: " " + pipe: + leading_trivia: [] + token: + start_position: + bytes: 215 + line: 18 + character: 19 + end_position: + bytes: 216 + line: 18 + character: 20 + token_type: + type: Symbol + symbol: "|" + trailing_trivia: + - start_position: + bytes: 216 + line: 18 + character: 20 + end_position: + bytes: 217 + line: 18 + character: 21 + token_type: + type: Whitespace + characters: " " + right: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 217 + line: 18 + character: 21 + end_position: + bytes: 224 + line: 18 + character: 28 + token_type: + type: Identifier + identifier: boolean + trailing_trivia: + - start_position: + bytes: 224 + line: 18 + character: 28 + end_position: + bytes: 225 + line: 18 + character: 28 + token_type: + type: Whitespace + characters: "\n" arrow: leading_trivia: [] token: @@ -2380,84 +2378,31 @@ stmts: type_info: Union: left: - Basic: - leading_trivia: [] - token: - start_position: - bytes: 282 - line: 22 - character: 29 - end_position: - bytes: 288 - line: 22 - character: 35 - token_type: - type: Identifier - identifier: number - trailing_trivia: - - start_position: - bytes: 288 - line: 22 - character: 35 - end_position: - bytes: 289 - line: 22 - character: 36 - token_type: - type: Whitespace - characters: " " - pipe: - leading_trivia: [] - token: - start_position: - bytes: 289 - line: 22 - character: 36 - end_position: - bytes: 290 - line: 22 - character: 37 - token_type: - type: Symbol - symbol: "|" - trailing_trivia: - - start_position: - bytes: 290 - line: 22 - character: 37 - end_position: - bytes: 291 - line: 22 - character: 38 - token_type: - type: Whitespace - characters: " " - right: Union: left: Basic: leading_trivia: [] token: start_position: - bytes: 291 + bytes: 282 line: 22 - character: 38 + character: 29 end_position: - bytes: 298 + bytes: 288 line: 22 - character: 45 + character: 35 token_type: type: Identifier - identifier: boolean + identifier: number trailing_trivia: - start_position: - bytes: 298 + bytes: 288 line: 22 - character: 45 + character: 35 end_position: - bytes: 299 + bytes: 289 line: 22 - character: 46 + character: 36 token_type: type: Whitespace characters: " " @@ -2465,25 +2410,25 @@ stmts: leading_trivia: [] token: start_position: - bytes: 299 + bytes: 289 line: 22 - character: 46 + character: 36 end_position: - bytes: 300 + bytes: 290 line: 22 - character: 47 + character: 37 token_type: type: Symbol symbol: "|" trailing_trivia: - start_position: - bytes: 300 + bytes: 290 line: 22 - character: 47 + character: 37 end_position: - bytes: 301 + bytes: 291 line: 22 - character: 48 + character: 38 token_type: type: Whitespace characters: " " @@ -2492,17 +2437,70 @@ stmts: leading_trivia: [] token: start_position: - bytes: 301 + bytes: 291 line: 22 - character: 48 + character: 38 end_position: - bytes: 304 + bytes: 298 line: 22 - character: 51 + character: 45 token_type: - type: Symbol - symbol: nil - trailing_trivia: [] + type: Identifier + identifier: boolean + trailing_trivia: + - start_position: + bytes: 298 + line: 22 + character: 45 + end_position: + bytes: 299 + line: 22 + character: 46 + token_type: + type: Whitespace + characters: " " + pipe: + leading_trivia: [] + token: + start_position: + bytes: 299 + line: 22 + character: 46 + end_position: + bytes: 300 + line: 22 + character: 47 + token_type: + type: Symbol + symbol: "|" + trailing_trivia: + - start_position: + bytes: 300 + line: 22 + character: 47 + end_position: + bytes: 301 + line: 22 + character: 48 + token_type: + type: Whitespace + characters: " " + right: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 301 + line: 22 + character: 48 + end_position: + bytes: 304 + line: 22 + character: 51 + token_type: + type: Symbol + symbol: nil + trailing_trivia: [] return_type: punctuation: leading_trivia: [] diff --git a/full-moon/tests/roblox_cases/pass/no_roblox_syntax/ast.snap b/full-moon/tests/roblox_cases/pass/no_roblox_syntax/ast.snap index e182692b..858f3400 100644 --- a/full-moon/tests/roblox_cases/pass/no_roblox_syntax/ast.snap +++ b/full-moon/tests/roblox_cases/pass/no_roblox_syntax/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/roblox_cases/pass/no_roblox_syntax --- stmts: - - LocalAssignment: @@ -4722,26 +4720,26 @@ last_stmt: type: Whitespace characters: " " expression: - BinaryOperator: - lhs: - UnaryOperator: - unop: - Hash: - leading_trivia: [] - token: - start_position: - bytes: 1056 - line: 41 - character: 15 - end_position: - bytes: 1057 - line: 41 - character: 16 - token_type: - type: Symbol - symbol: "#" - trailing_trivia: [] - expression: + UnaryOperator: + unop: + Hash: + leading_trivia: [] + token: + start_position: + bytes: 1056 + line: 41 + character: 15 + end_position: + bytes: 1057 + line: 41 + character: 16 + token_type: + type: Symbol + symbol: "#" + trailing_trivia: [] + expression: + BinaryOperator: + lhs: Var: Name: leading_trivia: [] @@ -4769,49 +4767,49 @@ last_stmt: token_type: type: Whitespace characters: " " - binop: - Plus: - leading_trivia: [] - token: - start_position: - bytes: 1067 - line: 41 - character: 26 - end_position: - bytes: 1068 - line: 41 - character: 27 - token_type: - type: Symbol - symbol: + - trailing_trivia: - - start_position: - bytes: 1068 - line: 41 - character: 27 - end_position: - bytes: 1069 - line: 41 - character: 28 - token_type: - type: Whitespace - characters: " " - rhs: - Number: - leading_trivia: [] - token: - start_position: - bytes: 1069 - line: 41 - character: 28 - end_position: - bytes: 1070 - line: 41 - character: 29 - token_type: - type: Number - text: "1" - trailing_trivia: [] + binop: + Plus: + leading_trivia: [] + token: + start_position: + bytes: 1067 + line: 41 + character: 26 + end_position: + bytes: 1068 + line: 41 + character: 27 + token_type: + type: Symbol + symbol: + + trailing_trivia: + - start_position: + bytes: 1068 + line: 41 + character: 27 + end_position: + bytes: 1069 + line: 41 + character: 28 + token_type: + type: Whitespace + characters: " " + rhs: + Number: + leading_trivia: [] + token: + start_position: + bytes: 1069 + line: 41 + character: 28 + end_position: + bytes: 1070 + line: 41 + character: 29 + token_type: + type: Number + text: "1" + trailing_trivia: [] equal_token: leading_trivia: [] token: diff --git a/full-moon/tests/roblox_cases/pass/types/ast.snap b/full-moon/tests/roblox_cases/pass/types/ast.snap index 42c5e00c..f51db361 100644 --- a/full-moon/tests/roblox_cases/pass/types/ast.snap +++ b/full-moon/tests/roblox_cases/pass/types/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/roblox_cases/pass/types --- stmts: - - LocalAssignment: @@ -5627,84 +5625,31 @@ stmts: type_info: Union: left: - Basic: - leading_trivia: [] - token: - start_position: - bytes: 885 - line: 32 - character: 20 - end_position: - bytes: 891 - line: 32 - character: 26 - token_type: - type: Identifier - identifier: number - trailing_trivia: - - start_position: - bytes: 891 - line: 32 - character: 26 - end_position: - bytes: 892 - line: 32 - character: 27 - token_type: - type: Whitespace - characters: " " - pipe: - leading_trivia: [] - token: - start_position: - bytes: 892 - line: 32 - character: 27 - end_position: - bytes: 893 - line: 32 - character: 28 - token_type: - type: Symbol - symbol: "|" - trailing_trivia: - - start_position: - bytes: 893 - line: 32 - character: 28 - end_position: - bytes: 894 - line: 32 - character: 29 - token_type: - type: Whitespace - characters: " " - right: Union: left: Basic: leading_trivia: [] token: start_position: - bytes: 894 + bytes: 885 line: 32 - character: 29 + character: 20 end_position: - bytes: 900 + bytes: 891 line: 32 - character: 35 + character: 26 token_type: type: Identifier - identifier: string + identifier: number trailing_trivia: - start_position: - bytes: 900 + bytes: 891 line: 32 - character: 35 + character: 26 end_position: - bytes: 901 + bytes: 892 line: 32 - character: 36 + character: 27 token_type: type: Whitespace characters: " " @@ -5712,25 +5657,25 @@ stmts: leading_trivia: [] token: start_position: - bytes: 901 + bytes: 892 line: 32 - character: 36 + character: 27 end_position: - bytes: 902 + bytes: 893 line: 32 - character: 37 + character: 28 token_type: type: Symbol symbol: "|" trailing_trivia: - start_position: - bytes: 902 + bytes: 893 line: 32 - character: 37 + character: 28 end_position: - bytes: 903 + bytes: 894 line: 32 - character: 38 + character: 29 token_type: type: Whitespace characters: " " @@ -5739,28 +5684,81 @@ stmts: leading_trivia: [] token: start_position: - bytes: 903 + bytes: 894 line: 32 - character: 38 + character: 29 end_position: - bytes: 906 + bytes: 900 line: 32 - character: 41 + character: 35 token_type: - type: Symbol - symbol: nil + type: Identifier + identifier: string trailing_trivia: - start_position: - bytes: 906 + bytes: 900 line: 32 - character: 41 + character: 35 end_position: - bytes: 907 + bytes: 901 line: 32 - character: 41 + character: 36 token_type: type: Whitespace - characters: "\n" + characters: " " + pipe: + leading_trivia: [] + token: + start_position: + bytes: 901 + line: 32 + character: 36 + end_position: + bytes: 902 + line: 32 + character: 37 + token_type: + type: Symbol + symbol: "|" + trailing_trivia: + - start_position: + bytes: 902 + line: 32 + character: 37 + end_position: + bytes: 903 + line: 32 + character: 38 + token_type: + type: Whitespace + characters: " " + right: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 903 + line: 32 + character: 38 + end_position: + bytes: 906 + line: 32 + character: 41 + token_type: + type: Symbol + symbol: nil + trailing_trivia: + - start_position: + bytes: 906 + line: 32 + character: 41 + end_position: + bytes: 907 + line: 32 + character: 41 + token_type: + type: Whitespace + characters: "\n" name_list: pairs: - End: @@ -6007,84 +6005,31 @@ stmts: type_info: Intersection: left: - Basic: - leading_trivia: [] - token: - start_position: - bytes: 971 - line: 35 - character: 27 - end_position: - bytes: 977 - line: 35 - character: 33 - token_type: - type: Identifier - identifier: number - trailing_trivia: - - start_position: - bytes: 977 - line: 35 - character: 33 - end_position: - bytes: 978 - line: 35 - character: 34 - token_type: - type: Whitespace - characters: " " - ampersand: - leading_trivia: [] - token: - start_position: - bytes: 978 - line: 35 - character: 34 - end_position: - bytes: 979 - line: 35 - character: 35 - token_type: - type: Symbol - symbol: "&" - trailing_trivia: - - start_position: - bytes: 979 - line: 35 - character: 35 - end_position: - bytes: 980 - line: 35 - character: 36 - token_type: - type: Whitespace - characters: " " - right: Intersection: left: Basic: leading_trivia: [] token: start_position: - bytes: 980 + bytes: 971 line: 35 - character: 36 + character: 27 end_position: - bytes: 986 + bytes: 977 line: 35 - character: 42 + character: 33 token_type: type: Identifier - identifier: string + identifier: number trailing_trivia: - start_position: - bytes: 986 + bytes: 977 line: 35 - character: 42 + character: 33 end_position: - bytes: 987 + bytes: 978 line: 35 - character: 43 + character: 34 token_type: type: Whitespace characters: " " @@ -6092,25 +6037,25 @@ stmts: leading_trivia: [] token: start_position: - bytes: 987 + bytes: 978 line: 35 - character: 43 + character: 34 end_position: - bytes: 988 + bytes: 979 line: 35 - character: 44 + character: 35 token_type: type: Symbol symbol: "&" trailing_trivia: - start_position: - bytes: 988 + bytes: 979 line: 35 - character: 44 + character: 35 end_position: - bytes: 989 + bytes: 980 line: 35 - character: 45 + character: 36 token_type: type: Whitespace characters: " " @@ -6119,28 +6064,81 @@ stmts: leading_trivia: [] token: start_position: - bytes: 989 + bytes: 980 line: 35 - character: 45 + character: 36 end_position: - bytes: 992 + bytes: 986 line: 35 - character: 48 + character: 42 token_type: - type: Symbol - symbol: nil + type: Identifier + identifier: string trailing_trivia: - start_position: - bytes: 992 + bytes: 986 line: 35 - character: 48 + character: 42 end_position: - bytes: 993 + bytes: 987 line: 35 - character: 48 + character: 43 token_type: type: Whitespace - characters: "\n" + characters: " " + ampersand: + leading_trivia: [] + token: + start_position: + bytes: 987 + line: 35 + character: 43 + end_position: + bytes: 988 + line: 35 + character: 44 + token_type: + type: Symbol + symbol: "&" + trailing_trivia: + - start_position: + bytes: 988 + line: 35 + character: 44 + end_position: + bytes: 989 + line: 35 + character: 45 + token_type: + type: Whitespace + characters: " " + right: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 989 + line: 35 + character: 45 + end_position: + bytes: 992 + line: 35 + character: 48 + token_type: + type: Symbol + symbol: nil + trailing_trivia: + - start_position: + bytes: 992 + line: 35 + character: 48 + end_position: + bytes: 993 + line: 35 + character: 48 + token_type: + type: Whitespace + characters: "\n" name_list: pairs: - End: diff --git a/full-moon/tests/roblox_cases/pass/types_chained_optionals/ast.snap b/full-moon/tests/roblox_cases/pass/types_chained_optionals/ast.snap new file mode 100644 index 00000000..67ae112b --- /dev/null +++ b/full-moon/tests/roblox_cases/pass/types_chained_optionals/ast.snap @@ -0,0 +1,656 @@ +--- +source: full-moon/tests/pass_cases.rs +expression: ast.nodes() +--- +stmts: + - - TypeDeclaration: + type_token: + leading_trivia: [] + token: + start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Identifier + identifier: Config + trailing_trivia: + - start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Whitespace + characters: " " + generics: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Whitespace + characters: " " + declare_as: + Table: + braces: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: "{" + trailing_trivia: + - start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: "\n" + - leading_trivia: [] + token: + start_position: + bytes: 166 + line: 5 + character: 1 + end_position: + bytes: 167 + line: 5 + character: 2 + token_type: + type: Symbol + symbol: "}" + trailing_trivia: [] + fields: + pairs: + - Punctuated: + - key: + Name: + leading_trivia: + - start_position: + bytes: 16 + line: 2 + character: 1 + end_position: + bytes: 20 + line: 2 + character: 5 + token_type: + type: Whitespace + characters: " " + token: + start_position: + bytes: 20 + line: 2 + character: 5 + end_position: + bytes: 27 + line: 2 + character: 12 + token_type: + type: Identifier + identifier: option1 + trailing_trivia: [] + colon: + leading_trivia: [] + token: + start_position: + bytes: 27 + line: 2 + character: 12 + end_position: + bytes: 28 + line: 2 + character: 13 + token_type: + type: Symbol + symbol: ":" + trailing_trivia: + - start_position: + bytes: 28 + line: 2 + character: 13 + end_position: + bytes: 29 + line: 2 + character: 14 + token_type: + type: Whitespace + characters: " " + value: + Optional: + base: + Optional: + base: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 29 + line: 2 + character: 14 + end_position: + bytes: 35 + line: 2 + character: 20 + token_type: + type: Identifier + identifier: string + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 35 + line: 2 + character: 20 + end_position: + bytes: 36 + line: 2 + character: 21 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 36 + line: 2 + character: 21 + end_position: + bytes: 37 + line: 2 + character: 22 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 37 + line: 2 + character: 22 + end_position: + bytes: 38 + line: 2 + character: 23 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 38 + line: 2 + character: 23 + end_position: + bytes: 39 + line: 2 + character: 24 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 39 + line: 2 + character: 24 + end_position: + bytes: 78 + line: 2 + character: 63 + token_type: + type: SingleLineComment + comment: " you probably need it once in a while" + - start_position: + bytes: 78 + line: 2 + character: 63 + end_position: + bytes: 79 + line: 2 + character: 63 + token_type: + type: Whitespace + characters: "\n" + - Punctuated: + - key: + Name: + leading_trivia: + - start_position: + bytes: 79 + line: 3 + character: 1 + end_position: + bytes: 83 + line: 3 + character: 5 + token_type: + type: Whitespace + characters: " " + token: + start_position: + bytes: 83 + line: 3 + character: 5 + end_position: + bytes: 90 + line: 3 + character: 12 + token_type: + type: Identifier + identifier: option2 + trailing_trivia: [] + colon: + leading_trivia: [] + token: + start_position: + bytes: 90 + line: 3 + character: 12 + end_position: + bytes: 91 + line: 3 + character: 13 + token_type: + type: Symbol + symbol: ":" + trailing_trivia: + - start_position: + bytes: 91 + line: 3 + character: 13 + end_position: + bytes: 92 + line: 3 + character: 14 + token_type: + type: Whitespace + characters: " " + value: + Optional: + base: + Optional: + base: + Optional: + base: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 92 + line: 3 + character: 14 + end_position: + bytes: 98 + line: 3 + character: 20 + token_type: + type: Identifier + identifier: string + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 98 + line: 3 + character: 20 + end_position: + bytes: 99 + line: 3 + character: 21 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 99 + line: 3 + character: 21 + end_position: + bytes: 100 + line: 3 + character: 22 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 100 + line: 3 + character: 22 + end_position: + bytes: 101 + line: 3 + character: 23 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 101 + line: 3 + character: 23 + end_position: + bytes: 102 + line: 3 + character: 24 + token_type: + type: Symbol + symbol: "," + trailing_trivia: + - start_position: + bytes: 102 + line: 3 + character: 24 + end_position: + bytes: 103 + line: 3 + character: 25 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 103 + line: 3 + character: 25 + end_position: + bytes: 117 + line: 3 + character: 39 + token_type: + type: SingleLineComment + comment: " once a year" + - start_position: + bytes: 117 + line: 3 + character: 39 + end_position: + bytes: 118 + line: 3 + character: 39 + token_type: + type: Whitespace + characters: "\n" + - End: + key: + Name: + leading_trivia: + - start_position: + bytes: 118 + line: 4 + character: 1 + end_position: + bytes: 122 + line: 4 + character: 5 + token_type: + type: Whitespace + characters: " " + token: + start_position: + bytes: 122 + line: 4 + character: 5 + end_position: + bytes: 129 + line: 4 + character: 12 + token_type: + type: Identifier + identifier: option3 + trailing_trivia: [] + colon: + leading_trivia: [] + token: + start_position: + bytes: 129 + line: 4 + character: 12 + end_position: + bytes: 130 + line: 4 + character: 13 + token_type: + type: Symbol + symbol: ":" + trailing_trivia: + - start_position: + bytes: 130 + line: 4 + character: 13 + end_position: + bytes: 131 + line: 4 + character: 14 + token_type: + type: Whitespace + characters: " " + value: + Optional: + base: + Optional: + base: + Optional: + base: + Optional: + base: + Optional: + base: + Optional: + base: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 131 + line: 4 + character: 14 + end_position: + bytes: 137 + line: 4 + character: 20 + token_type: + type: Identifier + identifier: string + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 137 + line: 4 + character: 20 + end_position: + bytes: 138 + line: 4 + character: 21 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 138 + line: 4 + character: 21 + end_position: + bytes: 139 + line: 4 + character: 22 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 139 + line: 4 + character: 22 + end_position: + bytes: 140 + line: 4 + character: 23 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 140 + line: 4 + character: 23 + end_position: + bytes: 141 + line: 4 + character: 24 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 141 + line: 4 + character: 24 + end_position: + bytes: 142 + line: 4 + character: 25 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 142 + line: 4 + character: 25 + end_position: + bytes: 143 + line: 4 + character: 26 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: + - start_position: + bytes: 143 + line: 4 + character: 26 + end_position: + bytes: 144 + line: 4 + character: 27 + token_type: + type: Whitespace + characters: " " + - start_position: + bytes: 144 + line: 4 + character: 27 + end_position: + bytes: 165 + line: 4 + character: 48 + token_type: + type: SingleLineComment + comment: " once in your life!" + - start_position: + bytes: 165 + line: 4 + character: 48 + end_position: + bytes: 166 + line: 4 + character: 48 + token_type: + type: Whitespace + characters: "\n" + - ~ + diff --git a/full-moon/tests/roblox_cases/pass/types_chained_optionals/source.lua b/full-moon/tests/roblox_cases/pass/types_chained_optionals/source.lua new file mode 100644 index 00000000..0809eac6 --- /dev/null +++ b/full-moon/tests/roblox_cases/pass/types_chained_optionals/source.lua @@ -0,0 +1,5 @@ +type Config = { + option1: string??, -- you probably need it once in a while + option2: string???, -- once a year + option3: string?????? -- once in your life! +} \ No newline at end of file diff --git a/full-moon/tests/roblox_cases/pass/types_chained_optionals/tokens.snap b/full-moon/tests/roblox_cases/pass/types_chained_optionals/tokens.snap new file mode 100644 index 00000000..30a57817 --- /dev/null +++ b/full-moon/tests/roblox_cases/pass/types_chained_optionals/tokens.snap @@ -0,0 +1,521 @@ +--- +source: full-moon/tests/pass_cases.rs +expression: tokens +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 4 + line: 1 + character: 5 + token_type: + type: Identifier + identifier: type +- start_position: + bytes: 4 + line: 1 + character: 5 + end_position: + bytes: 5 + line: 1 + character: 6 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 5 + line: 1 + character: 6 + end_position: + bytes: 11 + line: 1 + character: 12 + token_type: + type: Identifier + identifier: Config +- start_position: + bytes: 11 + line: 1 + character: 12 + end_position: + bytes: 12 + line: 1 + character: 13 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 12 + line: 1 + character: 13 + end_position: + bytes: 13 + line: 1 + character: 14 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 13 + line: 1 + character: 14 + end_position: + bytes: 14 + line: 1 + character: 15 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 14 + line: 1 + character: 15 + end_position: + bytes: 15 + line: 1 + character: 16 + token_type: + type: Symbol + symbol: "{" +- start_position: + bytes: 15 + line: 1 + character: 16 + end_position: + bytes: 16 + line: 1 + character: 16 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 16 + line: 2 + character: 1 + end_position: + bytes: 20 + line: 2 + character: 5 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 20 + line: 2 + character: 5 + end_position: + bytes: 27 + line: 2 + character: 12 + token_type: + type: Identifier + identifier: option1 +- start_position: + bytes: 27 + line: 2 + character: 12 + end_position: + bytes: 28 + line: 2 + character: 13 + token_type: + type: Symbol + symbol: ":" +- start_position: + bytes: 28 + line: 2 + character: 13 + end_position: + bytes: 29 + line: 2 + character: 14 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 29 + line: 2 + character: 14 + end_position: + bytes: 35 + line: 2 + character: 20 + token_type: + type: Identifier + identifier: string +- start_position: + bytes: 35 + line: 2 + character: 20 + end_position: + bytes: 36 + line: 2 + character: 21 + token_type: + type: Symbol + symbol: "?" +- start_position: + bytes: 36 + line: 2 + character: 21 + end_position: + bytes: 37 + line: 2 + character: 22 + token_type: + type: Symbol + symbol: "?" +- start_position: + bytes: 37 + line: 2 + character: 22 + end_position: + bytes: 38 + line: 2 + character: 23 + token_type: + type: Symbol + symbol: "," +- start_position: + bytes: 38 + line: 2 + character: 23 + end_position: + bytes: 39 + line: 2 + character: 24 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 39 + line: 2 + character: 24 + end_position: + bytes: 78 + line: 2 + character: 63 + token_type: + type: SingleLineComment + comment: " you probably need it once in a while" +- start_position: + bytes: 78 + line: 2 + character: 63 + end_position: + bytes: 79 + line: 2 + character: 63 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 79 + line: 3 + character: 1 + end_position: + bytes: 83 + line: 3 + character: 5 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 83 + line: 3 + character: 5 + end_position: + bytes: 90 + line: 3 + character: 12 + token_type: + type: Identifier + identifier: option2 +- start_position: + bytes: 90 + line: 3 + character: 12 + end_position: + bytes: 91 + line: 3 + character: 13 + token_type: + type: Symbol + symbol: ":" +- start_position: + bytes: 91 + line: 3 + character: 13 + end_position: + bytes: 92 + line: 3 + character: 14 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 92 + line: 3 + character: 14 + end_position: + bytes: 98 + line: 3 + character: 20 + token_type: + type: Identifier + identifier: string +- start_position: + bytes: 98 + line: 3 + character: 20 + end_position: + bytes: 99 + line: 3 + character: 21 + token_type: + type: Symbol + symbol: "?" +- start_position: + bytes: 99 + line: 3 + character: 21 + end_position: + bytes: 100 + line: 3 + character: 22 + token_type: + type: Symbol + symbol: "?" +- start_position: + bytes: 100 + line: 3 + character: 22 + end_position: + bytes: 101 + line: 3 + character: 23 + token_type: + type: Symbol + symbol: "?" +- start_position: + bytes: 101 + line: 3 + character: 23 + end_position: + bytes: 102 + line: 3 + character: 24 + token_type: + type: Symbol + symbol: "," +- start_position: + bytes: 102 + line: 3 + character: 24 + end_position: + bytes: 103 + line: 3 + character: 25 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 103 + line: 3 + character: 25 + end_position: + bytes: 117 + line: 3 + character: 39 + token_type: + type: SingleLineComment + comment: " once a year" +- start_position: + bytes: 117 + line: 3 + character: 39 + end_position: + bytes: 118 + line: 3 + character: 39 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 118 + line: 4 + character: 1 + end_position: + bytes: 122 + line: 4 + character: 5 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 122 + line: 4 + character: 5 + end_position: + bytes: 129 + line: 4 + character: 12 + token_type: + type: Identifier + identifier: option3 +- start_position: + bytes: 129 + line: 4 + character: 12 + end_position: + bytes: 130 + line: 4 + character: 13 + token_type: + type: Symbol + symbol: ":" +- start_position: + bytes: 130 + line: 4 + character: 13 + end_position: + bytes: 131 + line: 4 + character: 14 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 131 + line: 4 + character: 14 + end_position: + bytes: 137 + line: 4 + character: 20 + token_type: + type: Identifier + identifier: string +- start_position: + bytes: 137 + line: 4 + character: 20 + end_position: + bytes: 138 + line: 4 + character: 21 + token_type: + type: Symbol + symbol: "?" +- start_position: + bytes: 138 + line: 4 + character: 21 + end_position: + bytes: 139 + line: 4 + character: 22 + token_type: + type: Symbol + symbol: "?" +- start_position: + bytes: 139 + line: 4 + character: 22 + end_position: + bytes: 140 + line: 4 + character: 23 + token_type: + type: Symbol + symbol: "?" +- start_position: + bytes: 140 + line: 4 + character: 23 + end_position: + bytes: 141 + line: 4 + character: 24 + token_type: + type: Symbol + symbol: "?" +- start_position: + bytes: 141 + line: 4 + character: 24 + end_position: + bytes: 142 + line: 4 + character: 25 + token_type: + type: Symbol + symbol: "?" +- start_position: + bytes: 142 + line: 4 + character: 25 + end_position: + bytes: 143 + line: 4 + character: 26 + token_type: + type: Symbol + symbol: "?" +- start_position: + bytes: 143 + line: 4 + character: 26 + end_position: + bytes: 144 + line: 4 + character: 27 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 144 + line: 4 + character: 27 + end_position: + bytes: 165 + line: 4 + character: 48 + token_type: + type: SingleLineComment + comment: " once in your life!" +- start_position: + bytes: 165 + line: 4 + character: 48 + end_position: + bytes: 166 + line: 4 + character: 48 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 166 + line: 5 + character: 1 + end_position: + bytes: 167 + line: 5 + character: 2 + token_type: + type: Symbol + symbol: "}" +- start_position: + bytes: 167 + line: 5 + character: 2 + end_position: + bytes: 167 + line: 5 + character: 2 + token_type: + type: Eof + diff --git a/full-moon/tests/roblox_cases/pass/types_compound_precedence/ast.snap b/full-moon/tests/roblox_cases/pass/types_compound_precedence/ast.snap new file mode 100644 index 00000000..6f886a08 --- /dev/null +++ b/full-moon/tests/roblox_cases/pass/types_compound_precedence/ast.snap @@ -0,0 +1,663 @@ +--- +source: full-moon/tests/pass_cases.rs +expression: ast.nodes() +--- +stmts: + - - TypeDeclaration: + type_token: + leading_trivia: + - start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 54 + line: 1 + character: 55 + token_type: + type: SingleLineComment + comment: " https://github.com/Kampfkarren/full-moon/issues/286" + - start_position: + bytes: 54 + line: 1 + character: 55 + end_position: + bytes: 55 + line: 1 + character: 55 + token_type: + type: Whitespace + characters: "\n" + - start_position: + bytes: 55 + line: 2 + character: 1 + end_position: + bytes: 56 + line: 2 + character: 1 + token_type: + type: Whitespace + characters: "\n" + - start_position: + bytes: 56 + line: 3 + character: 1 + end_position: + bytes: 148 + line: 3 + character: 93 + token_type: + type: SingleLineComment + comment: " should be parsed as a function returning a variable amount of values of type \"string & T\"" + - start_position: + bytes: 148 + line: 3 + character: 93 + end_position: + bytes: 149 + line: 3 + character: 93 + token_type: + type: Whitespace + characters: "\n" + token: + start_position: + bytes: 149 + line: 4 + character: 1 + end_position: + bytes: 153 + line: 4 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 153 + line: 4 + character: 5 + end_position: + bytes: 154 + line: 4 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 154 + line: 4 + character: 6 + end_position: + bytes: 157 + line: 4 + character: 9 + token_type: + type: Identifier + identifier: FnA + trailing_trivia: + - start_position: + bytes: 157 + line: 4 + character: 9 + end_position: + bytes: 158 + line: 4 + character: 10 + token_type: + type: Whitespace + characters: " " + generics: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 158 + line: 4 + character: 10 + end_position: + bytes: 159 + line: 4 + character: 11 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 159 + line: 4 + character: 11 + end_position: + bytes: 160 + line: 4 + character: 12 + token_type: + type: Whitespace + characters: " " + declare_as: + Callback: + generics: ~ + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 160 + line: 4 + character: 12 + end_position: + bytes: 161 + line: 4 + character: 13 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 161 + line: 4 + character: 13 + end_position: + bytes: 162 + line: 4 + character: 14 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 162 + line: 4 + character: 14 + end_position: + bytes: 163 + line: 4 + character: 15 + token_type: + type: Whitespace + characters: " " + arguments: + pairs: [] + arrow: + leading_trivia: [] + token: + start_position: + bytes: 163 + line: 4 + character: 15 + end_position: + bytes: 165 + line: 4 + character: 17 + token_type: + type: Symbol + symbol: "->" + trailing_trivia: + - start_position: + bytes: 165 + line: 4 + character: 17 + end_position: + bytes: 166 + line: 4 + character: 18 + token_type: + type: Whitespace + characters: " " + return_type: + Variadic: + ellipse: + leading_trivia: [] + token: + start_position: + bytes: 166 + line: 4 + character: 18 + end_position: + bytes: 169 + line: 4 + character: 21 + token_type: + type: Symbol + symbol: "..." + trailing_trivia: [] + type_info: + Intersection: + left: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 169 + line: 4 + character: 21 + end_position: + bytes: 175 + line: 4 + character: 27 + token_type: + type: Identifier + identifier: string + trailing_trivia: + - start_position: + bytes: 175 + line: 4 + character: 27 + end_position: + bytes: 176 + line: 4 + character: 28 + token_type: + type: Whitespace + characters: " " + ampersand: + leading_trivia: [] + token: + start_position: + bytes: 176 + line: 4 + character: 28 + end_position: + bytes: 177 + line: 4 + character: 29 + token_type: + type: Symbol + symbol: "&" + trailing_trivia: + - start_position: + bytes: 177 + line: 4 + character: 29 + end_position: + bytes: 178 + line: 4 + character: 30 + token_type: + type: Whitespace + characters: " " + right: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 178 + line: 4 + character: 30 + end_position: + bytes: 179 + line: 4 + character: 31 + token_type: + type: Identifier + identifier: T + trailing_trivia: + - start_position: + bytes: 179 + line: 4 + character: 31 + end_position: + bytes: 180 + line: 4 + character: 31 + token_type: + type: Whitespace + characters: "\n" + - ~ + - - TypeDeclaration: + type_token: + leading_trivia: + - start_position: + bytes: 180 + line: 5 + character: 1 + end_position: + bytes: 181 + line: 5 + character: 1 + token_type: + type: Whitespace + characters: "\n" + - start_position: + bytes: 181 + line: 6 + character: 1 + end_position: + bytes: 278 + line: 6 + character: 98 + token_type: + type: SingleLineComment + comment: " should be parsed as an intersection of a function returning U... values, and a value of type T" + - start_position: + bytes: 278 + line: 6 + character: 98 + end_position: + bytes: 279 + line: 6 + character: 98 + token_type: + type: Whitespace + characters: "\n" + token: + start_position: + bytes: 279 + line: 7 + character: 1 + end_position: + bytes: 283 + line: 7 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 283 + line: 7 + character: 5 + end_position: + bytes: 284 + line: 7 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 284 + line: 7 + character: 6 + end_position: + bytes: 287 + line: 7 + character: 9 + token_type: + type: Identifier + identifier: FnB + trailing_trivia: [] + generics: + arrows: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 287 + line: 7 + character: 9 + end_position: + bytes: 288 + line: 7 + character: 10 + token_type: + type: Symbol + symbol: "<" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 292 + line: 7 + character: 14 + end_position: + bytes: 293 + line: 7 + character: 15 + token_type: + type: Symbol + symbol: ">" + trailing_trivia: + - start_position: + bytes: 293 + line: 7 + character: 15 + end_position: + bytes: 294 + line: 7 + character: 16 + token_type: + type: Whitespace + characters: " " + generics: + pairs: + - End: + parameter: + Variadic: + name: + leading_trivia: [] + token: + start_position: + bytes: 288 + line: 7 + character: 10 + end_position: + bytes: 289 + line: 7 + character: 11 + token_type: + type: Identifier + identifier: U + trailing_trivia: [] + ellipse: + leading_trivia: [] + token: + start_position: + bytes: 289 + line: 7 + character: 11 + end_position: + bytes: 292 + line: 7 + character: 14 + token_type: + type: Symbol + symbol: "..." + trailing_trivia: [] + default: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 294 + line: 7 + character: 16 + end_position: + bytes: 295 + line: 7 + character: 17 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 295 + line: 7 + character: 17 + end_position: + bytes: 296 + line: 7 + character: 18 + token_type: + type: Whitespace + characters: " " + declare_as: + Intersection: + left: + Callback: + generics: ~ + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 296 + line: 7 + character: 18 + end_position: + bytes: 297 + line: 7 + character: 19 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 297 + line: 7 + character: 19 + end_position: + bytes: 298 + line: 7 + character: 20 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 298 + line: 7 + character: 20 + end_position: + bytes: 299 + line: 7 + character: 21 + token_type: + type: Whitespace + characters: " " + arguments: + pairs: [] + arrow: + leading_trivia: [] + token: + start_position: + bytes: 299 + line: 7 + character: 21 + end_position: + bytes: 301 + line: 7 + character: 23 + token_type: + type: Symbol + symbol: "->" + trailing_trivia: + - start_position: + bytes: 301 + line: 7 + character: 23 + end_position: + bytes: 302 + line: 7 + character: 24 + token_type: + type: Whitespace + characters: " " + return_type: + GenericPack: + name: + leading_trivia: [] + token: + start_position: + bytes: 302 + line: 7 + character: 24 + end_position: + bytes: 303 + line: 7 + character: 25 + token_type: + type: Identifier + identifier: U + trailing_trivia: [] + ellipse: + leading_trivia: [] + token: + start_position: + bytes: 303 + line: 7 + character: 25 + end_position: + bytes: 306 + line: 7 + character: 28 + token_type: + type: Symbol + symbol: "..." + trailing_trivia: + - start_position: + bytes: 306 + line: 7 + character: 28 + end_position: + bytes: 307 + line: 7 + character: 29 + token_type: + type: Whitespace + characters: " " + ampersand: + leading_trivia: [] + token: + start_position: + bytes: 307 + line: 7 + character: 29 + end_position: + bytes: 308 + line: 7 + character: 30 + token_type: + type: Symbol + symbol: "&" + trailing_trivia: + - start_position: + bytes: 308 + line: 7 + character: 30 + end_position: + bytes: 309 + line: 7 + character: 31 + token_type: + type: Whitespace + characters: " " + right: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 309 + line: 7 + character: 31 + end_position: + bytes: 310 + line: 7 + character: 32 + token_type: + type: Identifier + identifier: T + trailing_trivia: + - start_position: + bytes: 310 + line: 7 + character: 32 + end_position: + bytes: 311 + line: 7 + character: 32 + token_type: + type: Whitespace + characters: "\n" + - ~ + diff --git a/full-moon/tests/roblox_cases/pass/types_compound_precedence/source.lua b/full-moon/tests/roblox_cases/pass/types_compound_precedence/source.lua new file mode 100644 index 00000000..5950d4d2 --- /dev/null +++ b/full-moon/tests/roblox_cases/pass/types_compound_precedence/source.lua @@ -0,0 +1,7 @@ +-- https://github.com/Kampfkarren/full-moon/issues/286 + +-- should be parsed as a function returning a variable amount of values of type "string & T" +type FnA = () -> ...string & T + +-- should be parsed as an intersection of a function returning U... values, and a value of type T +type FnB = () -> U... & T diff --git a/full-moon/tests/roblox_cases/pass/types_compound_precedence/tokens.snap b/full-moon/tests/roblox_cases/pass/types_compound_precedence/tokens.snap new file mode 100644 index 00000000..b24d4cef --- /dev/null +++ b/full-moon/tests/roblox_cases/pass/types_compound_precedence/tokens.snap @@ -0,0 +1,543 @@ +--- +source: full-moon/tests/pass_cases.rs +expression: tokens +--- +- start_position: + bytes: 0 + line: 1 + character: 1 + end_position: + bytes: 54 + line: 1 + character: 55 + token_type: + type: SingleLineComment + comment: " https://github.com/Kampfkarren/full-moon/issues/286" +- start_position: + bytes: 54 + line: 1 + character: 55 + end_position: + bytes: 55 + line: 1 + character: 55 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 55 + line: 2 + character: 1 + end_position: + bytes: 56 + line: 2 + character: 1 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 56 + line: 3 + character: 1 + end_position: + bytes: 148 + line: 3 + character: 93 + token_type: + type: SingleLineComment + comment: " should be parsed as a function returning a variable amount of values of type \"string & T\"" +- start_position: + bytes: 148 + line: 3 + character: 93 + end_position: + bytes: 149 + line: 3 + character: 93 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 149 + line: 4 + character: 1 + end_position: + bytes: 153 + line: 4 + character: 5 + token_type: + type: Identifier + identifier: type +- start_position: + bytes: 153 + line: 4 + character: 5 + end_position: + bytes: 154 + line: 4 + character: 6 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 154 + line: 4 + character: 6 + end_position: + bytes: 157 + line: 4 + character: 9 + token_type: + type: Identifier + identifier: FnA +- start_position: + bytes: 157 + line: 4 + character: 9 + end_position: + bytes: 158 + line: 4 + character: 10 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 158 + line: 4 + character: 10 + end_position: + bytes: 159 + line: 4 + character: 11 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 159 + line: 4 + character: 11 + end_position: + bytes: 160 + line: 4 + character: 12 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 160 + line: 4 + character: 12 + end_position: + bytes: 161 + line: 4 + character: 13 + token_type: + type: Symbol + symbol: ( +- start_position: + bytes: 161 + line: 4 + character: 13 + end_position: + bytes: 162 + line: 4 + character: 14 + token_type: + type: Symbol + symbol: ) +- start_position: + bytes: 162 + line: 4 + character: 14 + end_position: + bytes: 163 + line: 4 + character: 15 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 163 + line: 4 + character: 15 + end_position: + bytes: 165 + line: 4 + character: 17 + token_type: + type: Symbol + symbol: "->" +- start_position: + bytes: 165 + line: 4 + character: 17 + end_position: + bytes: 166 + line: 4 + character: 18 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 166 + line: 4 + character: 18 + end_position: + bytes: 169 + line: 4 + character: 21 + token_type: + type: Symbol + symbol: "..." +- start_position: + bytes: 169 + line: 4 + character: 21 + end_position: + bytes: 175 + line: 4 + character: 27 + token_type: + type: Identifier + identifier: string +- start_position: + bytes: 175 + line: 4 + character: 27 + end_position: + bytes: 176 + line: 4 + character: 28 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 176 + line: 4 + character: 28 + end_position: + bytes: 177 + line: 4 + character: 29 + token_type: + type: Symbol + symbol: "&" +- start_position: + bytes: 177 + line: 4 + character: 29 + end_position: + bytes: 178 + line: 4 + character: 30 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 178 + line: 4 + character: 30 + end_position: + bytes: 179 + line: 4 + character: 31 + token_type: + type: Identifier + identifier: T +- start_position: + bytes: 179 + line: 4 + character: 31 + end_position: + bytes: 180 + line: 4 + character: 31 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 180 + line: 5 + character: 1 + end_position: + bytes: 181 + line: 5 + character: 1 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 181 + line: 6 + character: 1 + end_position: + bytes: 278 + line: 6 + character: 98 + token_type: + type: SingleLineComment + comment: " should be parsed as an intersection of a function returning U... values, and a value of type T" +- start_position: + bytes: 278 + line: 6 + character: 98 + end_position: + bytes: 279 + line: 6 + character: 98 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 279 + line: 7 + character: 1 + end_position: + bytes: 283 + line: 7 + character: 5 + token_type: + type: Identifier + identifier: type +- start_position: + bytes: 283 + line: 7 + character: 5 + end_position: + bytes: 284 + line: 7 + character: 6 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 284 + line: 7 + character: 6 + end_position: + bytes: 287 + line: 7 + character: 9 + token_type: + type: Identifier + identifier: FnB +- start_position: + bytes: 287 + line: 7 + character: 9 + end_position: + bytes: 288 + line: 7 + character: 10 + token_type: + type: Symbol + symbol: "<" +- start_position: + bytes: 288 + line: 7 + character: 10 + end_position: + bytes: 289 + line: 7 + character: 11 + token_type: + type: Identifier + identifier: U +- start_position: + bytes: 289 + line: 7 + character: 11 + end_position: + bytes: 292 + line: 7 + character: 14 + token_type: + type: Symbol + symbol: "..." +- start_position: + bytes: 292 + line: 7 + character: 14 + end_position: + bytes: 293 + line: 7 + character: 15 + token_type: + type: Symbol + symbol: ">" +- start_position: + bytes: 293 + line: 7 + character: 15 + end_position: + bytes: 294 + line: 7 + character: 16 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 294 + line: 7 + character: 16 + end_position: + bytes: 295 + line: 7 + character: 17 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 295 + line: 7 + character: 17 + end_position: + bytes: 296 + line: 7 + character: 18 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 296 + line: 7 + character: 18 + end_position: + bytes: 297 + line: 7 + character: 19 + token_type: + type: Symbol + symbol: ( +- start_position: + bytes: 297 + line: 7 + character: 19 + end_position: + bytes: 298 + line: 7 + character: 20 + token_type: + type: Symbol + symbol: ) +- start_position: + bytes: 298 + line: 7 + character: 20 + end_position: + bytes: 299 + line: 7 + character: 21 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 299 + line: 7 + character: 21 + end_position: + bytes: 301 + line: 7 + character: 23 + token_type: + type: Symbol + symbol: "->" +- start_position: + bytes: 301 + line: 7 + character: 23 + end_position: + bytes: 302 + line: 7 + character: 24 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 302 + line: 7 + character: 24 + end_position: + bytes: 303 + line: 7 + character: 25 + token_type: + type: Identifier + identifier: U +- start_position: + bytes: 303 + line: 7 + character: 25 + end_position: + bytes: 306 + line: 7 + character: 28 + token_type: + type: Symbol + symbol: "..." +- start_position: + bytes: 306 + line: 7 + character: 28 + end_position: + bytes: 307 + line: 7 + character: 29 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 307 + line: 7 + character: 29 + end_position: + bytes: 308 + line: 7 + character: 30 + token_type: + type: Symbol + symbol: "&" +- start_position: + bytes: 308 + line: 7 + character: 30 + end_position: + bytes: 309 + line: 7 + character: 31 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 309 + line: 7 + character: 31 + end_position: + bytes: 310 + line: 7 + character: 32 + token_type: + type: Identifier + identifier: T +- start_position: + bytes: 310 + line: 7 + character: 32 + end_position: + bytes: 311 + line: 7 + character: 32 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 311 + line: 8 + character: 1 + end_position: + bytes: 311 + line: 8 + character: 1 + token_type: + type: Eof + diff --git a/full-moon/tests/roblox_cases/pass/types_generic_declaration/ast.snap b/full-moon/tests/roblox_cases/pass/types_generic_declaration/ast.snap index 454d9078..5e4af5a1 100644 --- a/full-moon/tests/roblox_cases/pass/types_generic_declaration/ast.snap +++ b/full-moon/tests/roblox_cases/pass/types_generic_declaration/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() - --- stmts: - - TypeDeclaration: @@ -755,7 +753,7 @@ stmts: token_type: type: Whitespace characters: " " - - VariadicPack: + - Variadic: ellipse: leading_trivia: [] token: @@ -771,21 +769,22 @@ stmts: type: Symbol symbol: "..." trailing_trivia: [] - name: - leading_trivia: [] - token: - start_position: - bytes: 99 - line: 4 - character: 28 - end_position: - bytes: 102 - line: 4 - character: 31 - token_type: - type: Identifier - identifier: any - trailing_trivia: [] + type_info: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 99 + line: 4 + character: 28 + end_position: + bytes: 102 + line: 4 + character: 31 + token_type: + type: Identifier + identifier: any + trailing_trivia: [] - leading_trivia: [] token: start_position: diff --git a/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/ast.snap b/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/ast.snap index 6b418b52..325628a4 100644 --- a/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/ast.snap +++ b/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/ast.snap @@ -129,8 +129,181 @@ stmts: token_type: type: Symbol symbol: ">" - trailing_trivia: [] + trailing_trivia: + - start_position: + bytes: 16 + line: 1 + character: 17 + end_position: + bytes: 17 + line: 1 + character: 17 + token_type: + type: Whitespace + characters: "\n" generics: pairs: [] - ~ + - - TypeDeclaration: + type_token: + leading_trivia: [] + token: + start_position: + bytes: 17 + line: 2 + character: 1 + end_position: + bytes: 21 + line: 2 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 21 + line: 2 + character: 5 + end_position: + bytes: 22 + line: 2 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 22 + line: 2 + character: 6 + end_position: + bytes: 25 + line: 2 + character: 9 + token_type: + type: Identifier + identifier: Baz + trailing_trivia: + - start_position: + bytes: 25 + line: 2 + character: 9 + end_position: + bytes: 26 + line: 2 + character: 10 + token_type: + type: Whitespace + characters: " " + generics: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 26 + line: 2 + character: 10 + end_position: + bytes: 27 + line: 2 + character: 11 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 27 + line: 2 + character: 11 + end_position: + bytes: 28 + line: 2 + character: 12 + token_type: + type: Whitespace + characters: " " + declare_as: + Module: + module: + leading_trivia: [] + token: + start_position: + bytes: 28 + line: 2 + character: 12 + end_position: + bytes: 34 + line: 2 + character: 18 + token_type: + type: Identifier + identifier: module + trailing_trivia: [] + punctuation: + leading_trivia: [] + token: + start_position: + bytes: 34 + line: 2 + character: 18 + end_position: + bytes: 35 + line: 2 + character: 19 + token_type: + type: Symbol + symbol: "." + trailing_trivia: [] + type_info: + Generic: + base: + leading_trivia: [] + token: + start_position: + bytes: 35 + line: 2 + character: 19 + end_position: + bytes: 38 + line: 2 + character: 22 + token_type: + type: Identifier + identifier: Foo + trailing_trivia: [] + arrows: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 38 + line: 2 + character: 22 + end_position: + bytes: 39 + line: 2 + character: 23 + token_type: + type: Symbol + symbol: "<" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 39 + line: 2 + character: 23 + end_position: + bytes: 40 + line: 2 + character: 24 + token_type: + type: Symbol + symbol: ">" + trailing_trivia: [] + generics: + pairs: [] + - ~ diff --git a/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/source.lua b/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/source.lua index 09b69300..85bc070d 100644 --- a/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/source.lua +++ b/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/source.lua @@ -1 +1,2 @@ -type Bar = Foo<> \ No newline at end of file +type Bar = Foo<> +type Baz = module.Foo<> \ No newline at end of file diff --git a/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/tokens.snap b/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/tokens.snap index b26dc941..df908aa0 100644 --- a/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/tokens.snap +++ b/full-moon/tests/roblox_cases/pass/types_generic_no_parameters/tokens.snap @@ -1,6 +1,5 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 38 expression: tokens --- - start_position: @@ -107,9 +106,141 @@ expression: tokens line: 1 character: 17 end_position: - bytes: 16 + bytes: 17 line: 1 character: 17 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 17 + line: 2 + character: 1 + end_position: + bytes: 21 + line: 2 + character: 5 + token_type: + type: Identifier + identifier: type +- start_position: + bytes: 21 + line: 2 + character: 5 + end_position: + bytes: 22 + line: 2 + character: 6 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 22 + line: 2 + character: 6 + end_position: + bytes: 25 + line: 2 + character: 9 + token_type: + type: Identifier + identifier: Baz +- start_position: + bytes: 25 + line: 2 + character: 9 + end_position: + bytes: 26 + line: 2 + character: 10 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 26 + line: 2 + character: 10 + end_position: + bytes: 27 + line: 2 + character: 11 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 27 + line: 2 + character: 11 + end_position: + bytes: 28 + line: 2 + character: 12 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 28 + line: 2 + character: 12 + end_position: + bytes: 34 + line: 2 + character: 18 + token_type: + type: Identifier + identifier: module +- start_position: + bytes: 34 + line: 2 + character: 18 + end_position: + bytes: 35 + line: 2 + character: 19 + token_type: + type: Symbol + symbol: "." +- start_position: + bytes: 35 + line: 2 + character: 19 + end_position: + bytes: 38 + line: 2 + character: 22 + token_type: + type: Identifier + identifier: Foo +- start_position: + bytes: 38 + line: 2 + character: 22 + end_position: + bytes: 39 + line: 2 + character: 23 + token_type: + type: Symbol + symbol: "<" +- start_position: + bytes: 39 + line: 2 + character: 23 + end_position: + bytes: 40 + line: 2 + character: 24 + token_type: + type: Symbol + symbol: ">" +- start_position: + bytes: 40 + line: 2 + character: 24 + end_position: + bytes: 40 + line: 2 + character: 24 token_type: type: Eof diff --git a/full-moon/tests/roblox_cases/pass/types_indexable/ast.snap b/full-moon/tests/roblox_cases/pass/types_indexable/ast.snap index 65892f71..2af4a04b 100644 --- a/full-moon/tests/roblox_cases/pass/types_indexable/ast.snap +++ b/full-moon/tests/roblox_cases/pass/types_indexable/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/roblox_cases/pass/types_indexable --- stmts: - - LocalAssignment: @@ -1076,7 +1074,7 @@ stmts: generics: pairs: - End: - VariadicPack: + Variadic: ellipse: leading_trivia: [] token: @@ -1092,21 +1090,22 @@ stmts: type: Symbol symbol: "..." trailing_trivia: [] - name: - leading_trivia: [] - token: - start_position: - bytes: 155 - line: 5 - character: 24 - end_position: - bytes: 161 - line: 5 - character: 30 - token_type: - type: Identifier - identifier: string - trailing_trivia: [] + type_info: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 155 + line: 5 + character: 24 + end_position: + bytes: 161 + line: 5 + character: 30 + token_type: + type: Identifier + identifier: string + trailing_trivia: [] name_list: pairs: - End: diff --git a/full-moon/tests/roblox_cases/pass/types_packs/ast.snap b/full-moon/tests/roblox_cases/pass/types_packs/ast.snap index e31350ee..2cea2450 100644 --- a/full-moon/tests/roblox_cases/pass/types_packs/ast.snap +++ b/full-moon/tests/roblox_cases/pass/types_packs/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/roblox_cases/pass/types_packs --- stmts: - - FunctionDeclaration: @@ -1657,7 +1655,7 @@ stmts: type: Whitespace characters: " " - End: - VariadicPack: + Variadic: ellipse: leading_trivia: [] token: @@ -1673,21 +1671,22 @@ stmts: type: Symbol symbol: "..." trailing_trivia: [] - name: - leading_trivia: [] - token: - start_position: - bytes: 221 - line: 12 - character: 23 - end_position: - bytes: 227 - line: 12 - character: 29 - token_type: - type: Identifier - identifier: string - trailing_trivia: [] + type_info: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 221 + line: 12 + character: 23 + end_position: + bytes: 227 + line: 12 + character: 29 + token_type: + type: Identifier + identifier: string + trailing_trivia: [] - ~ - - TypeDeclaration: type_token: @@ -2445,7 +2444,7 @@ stmts: generics: pairs: - Punctuated: - - VariadicPack: + - Variadic: ellipse: leading_trivia: [] token: @@ -2461,21 +2460,22 @@ stmts: type: Symbol symbol: "..." trailing_trivia: [] - name: - leading_trivia: [] - token: - start_position: - bytes: 400 - line: 17 - character: 32 - end_position: - bytes: 403 - line: 17 - character: 35 - token_type: - type: Identifier - identifier: any - trailing_trivia: [] + type_info: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 400 + line: 17 + character: 32 + end_position: + bytes: 403 + line: 17 + character: 35 + token_type: + type: Identifier + identifier: any + trailing_trivia: [] - leading_trivia: [] token: start_position: @@ -2502,7 +2502,7 @@ stmts: type: Whitespace characters: " " - End: - VariadicPack: + Variadic: ellipse: leading_trivia: [] token: @@ -2518,21 +2518,22 @@ stmts: type: Symbol symbol: "..." trailing_trivia: [] - name: - leading_trivia: [] - token: - start_position: - bytes: 408 - line: 17 - character: 40 - end_position: - bytes: 411 - line: 17 - character: 43 - token_type: - type: Identifier - identifier: any - trailing_trivia: [] + type_info: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 408 + line: 17 + character: 40 + end_position: + bytes: 411 + line: 17 + character: 43 + token_type: + type: Identifier + identifier: any + trailing_trivia: [] - ~ - - LocalAssignment: local_token: diff --git a/full-moon/tests/roblox_cases/pass/types_parentheses/ast.snap b/full-moon/tests/roblox_cases/pass/types_parentheses/ast.snap index b9ca5d05..8c5a36cd 100644 --- a/full-moon/tests/roblox_cases/pass/types_parentheses/ast.snap +++ b/full-moon/tests/roblox_cases/pass/types_parentheses/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/roblox_cases/pass/types_parentheses --- stmts: - - TypeDeclaration: @@ -1552,215 +1550,215 @@ stmts: - Punctuated: - name: ~ type_info: - Union: - left: - Optional: - base: - Tuple: - parentheses: - tokens: - - leading_trivia: - - start_position: - bytes: 223 - line: 13 - character: 1 - end_position: - bytes: 239 - line: 13 - character: 17 - token_type: - type: Whitespace - characters: " " - token: - start_position: - bytes: 239 - line: 13 - character: 17 - end_position: - bytes: 240 - line: 13 - character: 18 - token_type: - type: Symbol - symbol: ( - trailing_trivia: [] - - leading_trivia: [] - token: - start_position: - bytes: 248 - line: 13 - character: 26 - end_position: - bytes: 249 - line: 13 - character: 27 - token_type: - type: Symbol - symbol: ) - trailing_trivia: [] - types: - pairs: - - End: - Callback: - generics: ~ - parentheses: - tokens: - - leading_trivia: [] - token: - start_position: - bytes: 240 - line: 13 - character: 18 - end_position: - bytes: 241 - line: 13 - character: 19 - token_type: - type: Symbol - symbol: ( - trailing_trivia: [] - - leading_trivia: [] + Optional: + base: + Union: + left: + Optional: + base: + Tuple: + parentheses: + tokens: + - leading_trivia: + - start_position: + bytes: 223 + line: 13 + character: 1 + end_position: + bytes: 239 + line: 13 + character: 17 + token_type: + type: Whitespace + characters: " " + token: + start_position: + bytes: 239 + line: 13 + character: 17 + end_position: + bytes: 240 + line: 13 + character: 18 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 248 + line: 13 + character: 26 + end_position: + bytes: 249 + line: 13 + character: 27 + token_type: + type: Symbol + symbol: ) + trailing_trivia: [] + types: + pairs: + - End: + Callback: + generics: ~ + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 240 + line: 13 + character: 18 + end_position: + bytes: 241 + line: 13 + character: 19 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 242 + line: 13 + character: 20 + end_position: + bytes: 243 + line: 13 + character: 21 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 243 + line: 13 + character: 21 + end_position: + bytes: 244 + line: 13 + character: 22 + token_type: + type: Whitespace + characters: " " + arguments: + pairs: + - End: + name: ~ + type_info: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 241 + line: 13 + character: 19 + end_position: + bytes: 242 + line: 13 + character: 20 + token_type: + type: Identifier + identifier: T + trailing_trivia: [] + arrow: + leading_trivia: [] token: start_position: - bytes: 242 + bytes: 244 line: 13 - character: 20 + character: 22 end_position: - bytes: 243 + bytes: 246 line: 13 - character: 21 + character: 24 token_type: type: Symbol - symbol: ) + symbol: "->" trailing_trivia: - start_position: - bytes: 243 + bytes: 246 line: 13 - character: 21 + character: 24 end_position: - bytes: 244 + bytes: 247 line: 13 - character: 22 + character: 25 token_type: type: Whitespace characters: " " - arguments: - pairs: - - End: - name: ~ - type_info: - Basic: - leading_trivia: [] - token: - start_position: - bytes: 241 - line: 13 - character: 19 - end_position: - bytes: 242 - line: 13 - character: 20 - token_type: - type: Identifier - identifier: T - trailing_trivia: [] - arrow: - leading_trivia: [] - token: - start_position: - bytes: 244 - line: 13 - character: 22 - end_position: - bytes: 246 - line: 13 - character: 24 - token_type: - type: Symbol - symbol: "->" - trailing_trivia: - - start_position: - bytes: 246 - line: 13 - character: 24 - end_position: - bytes: 247 - line: 13 - character: 25 - token_type: - type: Whitespace - characters: " " - return_type: - Basic: - leading_trivia: [] - token: - start_position: - bytes: 247 - line: 13 - character: 25 - end_position: - bytes: 248 - line: 13 - character: 26 - token_type: - type: Identifier - identifier: T - trailing_trivia: [] - question_mark: + return_type: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 247 + line: 13 + character: 25 + end_position: + bytes: 248 + line: 13 + character: 26 + token_type: + type: Identifier + identifier: T + trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 249 + line: 13 + character: 27 + end_position: + bytes: 250 + line: 13 + character: 28 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: + - start_position: + bytes: 250 + line: 13 + character: 28 + end_position: + bytes: 251 + line: 13 + character: 29 + token_type: + type: Whitespace + characters: " " + pipe: leading_trivia: [] token: start_position: - bytes: 249 + bytes: 251 line: 13 - character: 27 + character: 29 end_position: - bytes: 250 + bytes: 252 line: 13 - character: 28 + character: 30 token_type: type: Symbol - symbol: "?" + symbol: "|" trailing_trivia: - start_position: - bytes: 250 + bytes: 252 line: 13 - character: 28 + character: 30 end_position: - bytes: 251 + bytes: 253 line: 13 - character: 29 + character: 31 token_type: type: Whitespace characters: " " - pipe: - leading_trivia: [] - token: - start_position: - bytes: 251 - line: 13 - character: 29 - end_position: - bytes: 252 - line: 13 - character: 30 - token_type: - type: Symbol - symbol: "|" - trailing_trivia: - - start_position: - bytes: 252 - line: 13 - character: 30 - end_position: - bytes: 253 - line: 13 - character: 31 - token_type: - type: Whitespace - characters: " " - right: - Optional: - base: + right: Tuple: parentheses: tokens: @@ -1859,21 +1857,21 @@ stmts: type: Identifier identifier: T trailing_trivia: [] - question_mark: - leading_trivia: [] - token: - start_position: - bytes: 269 - line: 13 - character: 47 - end_position: - bytes: 270 - line: 13 - character: 48 - token_type: - type: Symbol - symbol: "?" - trailing_trivia: [] + question_mark: + leading_trivia: [] + token: + start_position: + bytes: 269 + line: 13 + character: 47 + end_position: + bytes: 270 + line: 13 + character: 48 + token_type: + type: Symbol + symbol: "?" + trailing_trivia: [] - leading_trivia: [] token: start_position: @@ -1971,98 +1969,98 @@ stmts: types: pairs: - End: - Callback: - generics: ~ - parentheses: - tokens: - - leading_trivia: [] - token: - start_position: - bytes: 300 - line: 14 - character: 18 - end_position: - bytes: 301 - line: 14 - character: 19 - token_type: - type: Symbol - symbol: ( - trailing_trivia: [] - - leading_trivia: [] + Union: + left: + Callback: + generics: ~ + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 300 + line: 14 + character: 18 + end_position: + bytes: 301 + line: 14 + character: 19 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 304 + line: 14 + character: 22 + end_position: + bytes: 305 + line: 14 + character: 23 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 305 + line: 14 + character: 23 + end_position: + bytes: 306 + line: 14 + character: 24 + token_type: + type: Whitespace + characters: " " + arguments: + pairs: + - End: + name: ~ + type_info: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 301 + line: 14 + character: 19 + end_position: + bytes: 304 + line: 14 + character: 22 + token_type: + type: Identifier + identifier: any + trailing_trivia: [] + arrow: + leading_trivia: [] token: start_position: - bytes: 304 + bytes: 306 line: 14 - character: 22 + character: 24 end_position: - bytes: 305 + bytes: 308 line: 14 - character: 23 + character: 26 token_type: type: Symbol - symbol: ) + symbol: "->" trailing_trivia: - start_position: - bytes: 305 + bytes: 308 line: 14 - character: 23 + character: 26 end_position: - bytes: 306 + bytes: 309 line: 14 - character: 24 + character: 27 token_type: type: Whitespace characters: " " - arguments: - pairs: - - End: - name: ~ - type_info: - Basic: - leading_trivia: [] - token: - start_position: - bytes: 301 - line: 14 - character: 19 - end_position: - bytes: 304 - line: 14 - character: 22 - token_type: - type: Identifier - identifier: any - trailing_trivia: [] - arrow: - leading_trivia: [] - token: - start_position: - bytes: 306 - line: 14 - character: 24 - end_position: - bytes: 308 - line: 14 - character: 26 - token_type: - type: Symbol - symbol: "->" - trailing_trivia: - - start_position: - bytes: 308 - line: 14 - character: 26 - end_position: - bytes: 309 - line: 14 - character: 27 - token_type: - type: Whitespace - characters: " " - return_type: - Union: - left: + return_type: Tuple: parentheses: tokens: @@ -2107,97 +2105,97 @@ stmts: characters: " " types: pairs: [] - pipe: + pipe: + leading_trivia: [] + token: + start_position: + bytes: 312 + line: 14 + character: 30 + end_position: + bytes: 313 + line: 14 + character: 31 + token_type: + type: Symbol + symbol: "|" + trailing_trivia: + - start_position: + bytes: 313 + line: 14 + character: 31 + end_position: + bytes: 314 + line: 14 + character: 32 + token_type: + type: Whitespace + characters: " " + right: + Generic: + base: leading_trivia: [] token: start_position: - bytes: 312 + bytes: 314 line: 14 - character: 30 + character: 32 end_position: - bytes: 313 + bytes: 325 line: 14 - character: 31 + character: 43 token_type: - type: Symbol - symbol: "|" - trailing_trivia: - - start_position: - bytes: 313 - line: 14 - character: 31 - end_position: - bytes: 314 - line: 14 - character: 32 - token_type: - type: Whitespace - characters: " " - right: - Generic: - base: - leading_trivia: [] + type: Identifier + identifier: PromiseLike + trailing_trivia: [] + arrows: + tokens: + - leading_trivia: [] token: start_position: - bytes: 314 - line: 14 - character: 32 - end_position: bytes: 325 line: 14 character: 43 + end_position: + bytes: 326 + line: 14 + character: 44 token_type: - type: Identifier - identifier: PromiseLike + type: Symbol + symbol: "<" trailing_trivia: [] - arrows: - tokens: - - leading_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 327 + line: 14 + character: 45 + end_position: + bytes: 328 + line: 14 + character: 46 + token_type: + type: Symbol + symbol: ">" + trailing_trivia: [] + generics: + pairs: + - End: + Basic: + leading_trivia: [] token: start_position: - bytes: 325 - line: 14 - character: 43 - end_position: bytes: 326 line: 14 character: 44 - token_type: - type: Symbol - symbol: "<" - trailing_trivia: [] - - leading_trivia: [] - token: - start_position: + end_position: bytes: 327 line: 14 character: 45 - end_position: - bytes: 328 - line: 14 - character: 46 token_type: - type: Symbol - symbol: ">" + type: Identifier + identifier: T trailing_trivia: [] - generics: - pairs: - - End: - Basic: - leading_trivia: [] - token: - start_position: - bytes: 326 - line: 14 - character: 44 - end_position: - bytes: 327 - line: 14 - character: 45 - token_type: - type: Identifier - identifier: T - trailing_trivia: [] question_mark: leading_trivia: [] token: diff --git a/full-moon/tests/roblox_cases/pass/types_variadic/ast.snap b/full-moon/tests/roblox_cases/pass/types_variadic/ast.snap index 3b29e064..a494d784 100644 --- a/full-moon/tests/roblox_cases/pass/types_variadic/ast.snap +++ b/full-moon/tests/roblox_cases/pass/types_variadic/ast.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs -assertion_line: 52 expression: ast.nodes() -input_file: full-moon/tests/roblox_cases/pass/types_variadic --- stmts: - - TypeDeclaration: @@ -1046,25 +1044,25 @@ stmts: - End: name: ~ type_info: - Union: - left: - Variadic: - ellipse: - leading_trivia: [] - token: - start_position: - bytes: 146 - line: 5 - character: 14 - end_position: - bytes: 149 - line: 5 - character: 17 - token_type: - type: Symbol - symbol: "..." - trailing_trivia: [] - type_info: + Variadic: + ellipse: + leading_trivia: [] + token: + start_position: + bytes: 146 + line: 5 + character: 14 + end_position: + bytes: 149 + line: 5 + character: 17 + token_type: + type: Symbol + symbol: "..." + trailing_trivia: [] + type_info: + Union: + left: String: leading_trivia: [] token: @@ -1092,49 +1090,49 @@ stmts: token_type: type: Whitespace characters: " " - pipe: - leading_trivia: [] - token: - start_position: - bytes: 155 - line: 5 - character: 23 - end_position: - bytes: 156 - line: 5 - character: 24 - token_type: - type: Symbol - symbol: "|" - trailing_trivia: - - start_position: - bytes: 156 - line: 5 - character: 24 - end_position: - bytes: 157 - line: 5 - character: 25 - token_type: - type: Whitespace - characters: " " - right: - String: - leading_trivia: [] - token: - start_position: - bytes: 157 - line: 5 - character: 25 - end_position: - bytes: 163 - line: 5 - character: 31 - token_type: - type: StringLiteral - literal: miss - quote_type: Double - trailing_trivia: [] + pipe: + leading_trivia: [] + token: + start_position: + bytes: 155 + line: 5 + character: 23 + end_position: + bytes: 156 + line: 5 + character: 24 + token_type: + type: Symbol + symbol: "|" + trailing_trivia: + - start_position: + bytes: 156 + line: 5 + character: 24 + end_position: + bytes: 157 + line: 5 + character: 25 + token_type: + type: Whitespace + characters: " " + right: + String: + leading_trivia: [] + token: + start_position: + bytes: 157 + line: 5 + character: 25 + end_position: + bytes: 163 + line: 5 + character: 31 + token_type: + type: StringLiteral + literal: miss + quote_type: Double + trailing_trivia: [] arrow: leading_trivia: [] token: @@ -1306,86 +1304,32 @@ stmts: - End: Union: left: - String: - leading_trivia: [] - token: - start_position: - bytes: 181 - line: 5 - character: 49 - end_position: - bytes: 191 - line: 5 - character: 59 - token_type: - type: StringLiteral - literal: critical - quote_type: Double - trailing_trivia: - - start_position: - bytes: 191 - line: 5 - character: 59 - end_position: - bytes: 192 - line: 5 - character: 60 - token_type: - type: Whitespace - characters: " " - pipe: - leading_trivia: [] - token: - start_position: - bytes: 192 - line: 5 - character: 60 - end_position: - bytes: 193 - line: 5 - character: 61 - token_type: - type: Symbol - symbol: "|" - trailing_trivia: - - start_position: - bytes: 193 - line: 5 - character: 61 - end_position: - bytes: 194 - line: 5 - character: 62 - token_type: - type: Whitespace - characters: " " - right: Union: left: String: leading_trivia: [] token: start_position: - bytes: 194 + bytes: 181 line: 5 - character: 62 + character: 49 end_position: - bytes: 200 + bytes: 191 line: 5 - character: 68 + character: 59 token_type: type: StringLiteral - literal: weak + literal: critical quote_type: Double trailing_trivia: - start_position: - bytes: 200 + bytes: 191 line: 5 - character: 68 + character: 59 end_position: - bytes: 201 + bytes: 192 line: 5 - character: 69 + character: 60 token_type: type: Whitespace characters: " " @@ -1393,25 +1337,25 @@ stmts: leading_trivia: [] token: start_position: - bytes: 201 + bytes: 192 line: 5 - character: 69 + character: 60 end_position: - bytes: 202 + bytes: 193 line: 5 - character: 70 + character: 61 token_type: type: Symbol symbol: "|" trailing_trivia: - start_position: - bytes: 202 + bytes: 193 line: 5 - character: 70 + character: 61 end_position: - bytes: 203 + bytes: 194 line: 5 - character: 71 + character: 62 token_type: type: Whitespace characters: " " @@ -1420,18 +1364,72 @@ stmts: leading_trivia: [] token: start_position: - bytes: 203 + bytes: 194 line: 5 - character: 71 + character: 62 end_position: - bytes: 211 + bytes: 200 line: 5 - character: 79 + character: 68 token_type: type: StringLiteral - literal: normal + literal: weak quote_type: Double - trailing_trivia: [] + trailing_trivia: + - start_position: + bytes: 200 + line: 5 + character: 68 + end_position: + bytes: 201 + line: 5 + character: 69 + token_type: + type: Whitespace + characters: " " + pipe: + leading_trivia: [] + token: + start_position: + bytes: 201 + line: 5 + character: 69 + end_position: + bytes: 202 + line: 5 + character: 70 + token_type: + type: Symbol + symbol: "|" + trailing_trivia: + - start_position: + bytes: 202 + line: 5 + character: 70 + end_position: + bytes: 203 + line: 5 + character: 71 + token_type: + type: Whitespace + characters: " " + right: + String: + leading_trivia: [] + token: + start_position: + bytes: 203 + line: 5 + character: 71 + end_position: + bytes: 211 + line: 5 + character: 79 + token_type: + type: StringLiteral + literal: normal + quote_type: Double + trailing_trivia: [] arrow: leading_trivia: [] token: @@ -1772,25 +1770,25 @@ stmts: type: Whitespace characters: " " type_info: - Union: - left: - Variadic: - ellipse: - leading_trivia: [] - token: - start_position: - bytes: 268 - line: 7 - character: 29 - end_position: - bytes: 271 - line: 7 - character: 32 - token_type: - type: Symbol - symbol: "..." - trailing_trivia: [] - type_info: + Variadic: + ellipse: + leading_trivia: [] + token: + start_position: + bytes: 268 + line: 7 + character: 29 + end_position: + bytes: 271 + line: 7 + character: 32 + token_type: + type: Symbol + symbol: "..." + trailing_trivia: [] + type_info: + Union: + left: Basic: leading_trivia: [] token: @@ -1817,59 +1815,59 @@ stmts: token_type: type: Whitespace characters: " " - pipe: - leading_trivia: [] - token: - start_position: - bytes: 278 - line: 7 - character: 39 - end_position: - bytes: 279 - line: 7 - character: 40 - token_type: - type: Symbol - symbol: "|" - trailing_trivia: - - start_position: - bytes: 279 - line: 7 - character: 40 - end_position: - bytes: 280 - line: 7 - character: 41 - token_type: - type: Whitespace - characters: " " - right: - Basic: - leading_trivia: [] - token: - start_position: - bytes: 280 - line: 7 - character: 41 - end_position: - bytes: 286 - line: 7 - character: 47 - token_type: - type: Identifier - identifier: string - trailing_trivia: - - start_position: - bytes: 286 + pipe: + leading_trivia: [] + token: + start_position: + bytes: 278 line: 7 - character: 47 + character: 39 end_position: - bytes: 287 + bytes: 279 line: 7 - character: 48 + character: 40 token_type: - type: Whitespace - characters: " " + type: Symbol + symbol: "|" + trailing_trivia: + - start_position: + bytes: 279 + line: 7 + character: 40 + end_position: + bytes: 280 + line: 7 + character: 41 + token_type: + type: Whitespace + characters: " " + right: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 280 + line: 7 + character: 41 + end_position: + bytes: 286 + line: 7 + character: 47 + token_type: + type: Identifier + identifier: string + trailing_trivia: + - start_position: + bytes: 286 + line: 7 + character: 47 + end_position: + bytes: 287 + line: 7 + character: 48 + token_type: + type: Whitespace + characters: " " block: stmts: [] end_token: @@ -3676,4 +3674,353 @@ stmts: type: Whitespace characters: "\n" - ~ + - - TypeDeclaration: + type_token: + leading_trivia: + - start_position: + bytes: 551 + line: 23 + character: 1 + end_position: + bytes: 552 + line: 23 + character: 1 + token_type: + type: Whitespace + characters: "\n" + token: + start_position: + bytes: 552 + line: 24 + character: 1 + end_position: + bytes: 556 + line: 24 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 556 + line: 24 + character: 5 + end_position: + bytes: 557 + line: 24 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 557 + line: 24 + character: 6 + end_position: + bytes: 559 + line: 24 + character: 8 + token_type: + type: Identifier + identifier: Fn + trailing_trivia: [] + generics: + arrows: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 559 + line: 24 + character: 8 + end_position: + bytes: 560 + line: 24 + character: 9 + token_type: + type: Symbol + symbol: "<" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 564 + line: 24 + character: 13 + end_position: + bytes: 565 + line: 24 + character: 14 + token_type: + type: Symbol + symbol: ">" + trailing_trivia: + - start_position: + bytes: 565 + line: 24 + character: 14 + end_position: + bytes: 566 + line: 24 + character: 15 + token_type: + type: Whitespace + characters: " " + generics: + pairs: + - End: + parameter: + Variadic: + name: + leading_trivia: [] + token: + start_position: + bytes: 560 + line: 24 + character: 9 + end_position: + bytes: 561 + line: 24 + character: 10 + token_type: + type: Identifier + identifier: U + trailing_trivia: [] + ellipse: + leading_trivia: [] + token: + start_position: + bytes: 561 + line: 24 + character: 10 + end_position: + bytes: 564 + line: 24 + character: 13 + token_type: + type: Symbol + symbol: "..." + trailing_trivia: [] + default: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 566 + line: 24 + character: 15 + end_position: + bytes: 567 + line: 24 + character: 16 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 567 + line: 24 + character: 16 + end_position: + bytes: 568 + line: 24 + character: 17 + token_type: + type: Whitespace + characters: " " + declare_as: + Basic: + leading_trivia: [] + token: + start_position: + bytes: 568 + line: 24 + character: 17 + end_position: + bytes: 571 + line: 24 + character: 20 + token_type: + type: Identifier + identifier: any + trailing_trivia: + - start_position: + bytes: 571 + line: 24 + character: 20 + end_position: + bytes: 572 + line: 24 + character: 20 + token_type: + type: Whitespace + characters: "\n" + - ~ + - - TypeDeclaration: + type_token: + leading_trivia: [] + token: + start_position: + bytes: 572 + line: 25 + character: 1 + end_position: + bytes: 576 + line: 25 + character: 5 + token_type: + type: Identifier + identifier: type + trailing_trivia: + - start_position: + bytes: 576 + line: 25 + character: 5 + end_position: + bytes: 577 + line: 25 + character: 6 + token_type: + type: Whitespace + characters: " " + base: + leading_trivia: [] + token: + start_position: + bytes: 577 + line: 25 + character: 6 + end_position: + bytes: 578 + line: 25 + character: 7 + token_type: + type: Identifier + identifier: T + trailing_trivia: + - start_position: + bytes: 578 + line: 25 + character: 7 + end_position: + bytes: 579 + line: 25 + character: 8 + token_type: + type: Whitespace + characters: " " + generics: ~ + equal_token: + leading_trivia: [] + token: + start_position: + bytes: 579 + line: 25 + character: 8 + end_position: + bytes: 580 + line: 25 + character: 9 + token_type: + type: Symbol + symbol: "=" + trailing_trivia: + - start_position: + bytes: 580 + line: 25 + character: 9 + end_position: + bytes: 581 + line: 25 + character: 10 + token_type: + type: Whitespace + characters: " " + declare_as: + Generic: + base: + leading_trivia: [] + token: + start_position: + bytes: 581 + line: 25 + character: 10 + end_position: + bytes: 583 + line: 25 + character: 12 + token_type: + type: Identifier + identifier: Fn + trailing_trivia: [] + arrows: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 583 + line: 25 + character: 12 + end_position: + bytes: 584 + line: 25 + character: 13 + token_type: + type: Symbol + symbol: "<" + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 591 + line: 25 + character: 20 + end_position: + bytes: 592 + line: 25 + character: 21 + token_type: + type: Symbol + symbol: ">" + trailing_trivia: [] + generics: + pairs: + - End: + Variadic: + ellipse: + leading_trivia: [] + token: + start_position: + bytes: 584 + line: 25 + character: 13 + end_position: + bytes: 587 + line: 25 + character: 16 + token_type: + type: Symbol + symbol: "..." + trailing_trivia: [] + type_info: + String: + leading_trivia: [] + token: + start_position: + bytes: 587 + line: 25 + character: 16 + end_position: + bytes: 591 + line: 25 + character: 20 + token_type: + type: StringLiteral + literal: ok + quote_type: Single + trailing_trivia: [] + - ~ diff --git a/full-moon/tests/roblox_cases/pass/types_variadic/source.lua b/full-moon/tests/roblox_cases/pass/types_variadic/source.lua index 7eb991df..45669424 100644 --- a/full-moon/tests/roblox_cases/pass/types_variadic/source.lua +++ b/full-moon/tests/roblox_cases/pass/types_variadic/source.lua @@ -20,3 +20,6 @@ function Boo:f(name: string, ...: number): () -> (string, ...Foo) -> () return function(_x: string, ...: Foo) end end end + +type Fn = any +type T = Fn<...'ok'> \ No newline at end of file diff --git a/full-moon/tests/roblox_cases/pass/types_variadic/tokens.snap b/full-moon/tests/roblox_cases/pass/types_variadic/tokens.snap index 12d18a7d..acb9fdf3 100644 --- a/full-moon/tests/roblox_cases/pass/types_variadic/tokens.snap +++ b/full-moon/tests/roblox_cases/pass/types_variadic/tokens.snap @@ -1,8 +1,6 @@ --- source: full-moon/tests/pass_cases.rs expression: tokens -input_file: full-moon/tests/roblox_cases/pass/types_variadic - --- - start_position: bytes: 0 @@ -2802,9 +2800,274 @@ input_file: full-moon/tests/roblox_cases/pass/types_variadic line: 23 character: 1 end_position: - bytes: 551 + bytes: 552 line: 23 character: 1 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 552 + line: 24 + character: 1 + end_position: + bytes: 556 + line: 24 + character: 5 + token_type: + type: Identifier + identifier: type +- start_position: + bytes: 556 + line: 24 + character: 5 + end_position: + bytes: 557 + line: 24 + character: 6 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 557 + line: 24 + character: 6 + end_position: + bytes: 559 + line: 24 + character: 8 + token_type: + type: Identifier + identifier: Fn +- start_position: + bytes: 559 + line: 24 + character: 8 + end_position: + bytes: 560 + line: 24 + character: 9 + token_type: + type: Symbol + symbol: "<" +- start_position: + bytes: 560 + line: 24 + character: 9 + end_position: + bytes: 561 + line: 24 + character: 10 + token_type: + type: Identifier + identifier: U +- start_position: + bytes: 561 + line: 24 + character: 10 + end_position: + bytes: 564 + line: 24 + character: 13 + token_type: + type: Symbol + symbol: "..." +- start_position: + bytes: 564 + line: 24 + character: 13 + end_position: + bytes: 565 + line: 24 + character: 14 + token_type: + type: Symbol + symbol: ">" +- start_position: + bytes: 565 + line: 24 + character: 14 + end_position: + bytes: 566 + line: 24 + character: 15 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 566 + line: 24 + character: 15 + end_position: + bytes: 567 + line: 24 + character: 16 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 567 + line: 24 + character: 16 + end_position: + bytes: 568 + line: 24 + character: 17 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 568 + line: 24 + character: 17 + end_position: + bytes: 571 + line: 24 + character: 20 + token_type: + type: Identifier + identifier: any +- start_position: + bytes: 571 + line: 24 + character: 20 + end_position: + bytes: 572 + line: 24 + character: 20 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 572 + line: 25 + character: 1 + end_position: + bytes: 576 + line: 25 + character: 5 + token_type: + type: Identifier + identifier: type +- start_position: + bytes: 576 + line: 25 + character: 5 + end_position: + bytes: 577 + line: 25 + character: 6 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 577 + line: 25 + character: 6 + end_position: + bytes: 578 + line: 25 + character: 7 + token_type: + type: Identifier + identifier: T +- start_position: + bytes: 578 + line: 25 + character: 7 + end_position: + bytes: 579 + line: 25 + character: 8 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 579 + line: 25 + character: 8 + end_position: + bytes: 580 + line: 25 + character: 9 + token_type: + type: Symbol + symbol: "=" +- start_position: + bytes: 580 + line: 25 + character: 9 + end_position: + bytes: 581 + line: 25 + character: 10 + token_type: + type: Whitespace + characters: " " +- start_position: + bytes: 581 + line: 25 + character: 10 + end_position: + bytes: 583 + line: 25 + character: 12 + token_type: + type: Identifier + identifier: Fn +- start_position: + bytes: 583 + line: 25 + character: 12 + end_position: + bytes: 584 + line: 25 + character: 13 + token_type: + type: Symbol + symbol: "<" +- start_position: + bytes: 584 + line: 25 + character: 13 + end_position: + bytes: 587 + line: 25 + character: 16 + token_type: + type: Symbol + symbol: "..." +- start_position: + bytes: 587 + line: 25 + character: 16 + end_position: + bytes: 591 + line: 25 + character: 20 + token_type: + type: StringLiteral + literal: ok + quote_type: Single +- start_position: + bytes: 591 + line: 25 + character: 20 + end_position: + bytes: 592 + line: 25 + character: 21 + token_type: + type: Symbol + symbol: ">" +- start_position: + bytes: 592 + line: 25 + character: 21 + end_position: + bytes: 592 + line: 25 + character: 21 token_type: type: Eof diff --git a/full-moon/tests/roblox_cases/pass/z-escape-string/ast.snap b/full-moon/tests/roblox_cases/pass/z-escape-string/ast.snap index 714faee2..6f787e5d 100644 --- a/full-moon/tests/roblox_cases/pass/z-escape-string/ast.snap +++ b/full-moon/tests/roblox_cases/pass/z-escape-string/ast.snap @@ -53,7 +53,18 @@ stmts: token_type: type: Symbol symbol: ) - trailing_trivia: [] + trailing_trivia: + - start_position: + bytes: 30 + line: 2 + character: 13 + end_position: + bytes: 31 + line: 2 + character: 13 + token_type: + type: Whitespace + characters: "\n" arguments: pairs: - End: @@ -74,4 +85,97 @@ stmts: quote_type: Double trailing_trivia: [] - ~ + - - FunctionCall: + prefix: + Name: + leading_trivia: + - start_position: + bytes: 31 + line: 3 + character: 1 + end_position: + bytes: 32 + line: 3 + character: 1 + token_type: + type: Whitespace + characters: "\n" + token: + start_position: + bytes: 32 + line: 4 + character: 1 + end_position: + bytes: 37 + line: 4 + character: 6 + token_type: + type: Identifier + identifier: print + trailing_trivia: [] + suffixes: + - Call: + AnonymousCall: + Parentheses: + parentheses: + tokens: + - leading_trivia: [] + token: + start_position: + bytes: 37 + line: 4 + character: 6 + end_position: + bytes: 38 + line: 4 + character: 7 + token_type: + type: Symbol + symbol: ( + trailing_trivia: [] + - leading_trivia: [] + token: + start_position: + bytes: 54 + line: 5 + character: 8 + end_position: + bytes: 55 + line: 5 + character: 9 + token_type: + type: Symbol + symbol: ) + trailing_trivia: + - start_position: + bytes: 55 + line: 5 + character: 9 + end_position: + bytes: 56 + line: 5 + character: 9 + token_type: + type: Whitespace + characters: "\n" + arguments: + pairs: + - End: + String: + leading_trivia: [] + token: + start_position: + bytes: 38 + line: 4 + character: 7 + end_position: + bytes: 54 + line: 5 + character: 8 + token_type: + type: StringLiteral + literal: "Hello \\\n\tWorld" + quote_type: Double + trailing_trivia: [] + - ~ diff --git a/full-moon/tests/roblox_cases/pass/z-escape-string/source.lua b/full-moon/tests/roblox_cases/pass/z-escape-string/source.lua index 230a2b44..3167d6c9 100644 --- a/full-moon/tests/roblox_cases/pass/z-escape-string/source.lua +++ b/full-moon/tests/roblox_cases/pass/z-escape-string/source.lua @@ -1,2 +1,5 @@ print("testing \z - twelve") \ No newline at end of file + twelve") + +print("Hello \ + World") diff --git a/full-moon/tests/roblox_cases/pass/z-escape-string/tokens.snap b/full-moon/tests/roblox_cases/pass/z-escape-string/tokens.snap index 3193aac1..42a20cf6 100644 --- a/full-moon/tests/roblox_cases/pass/z-escape-string/tokens.snap +++ b/full-moon/tests/roblox_cases/pass/z-escape-string/tokens.snap @@ -52,9 +52,87 @@ expression: tokens line: 2 character: 13 end_position: - bytes: 30 + bytes: 31 line: 2 character: 13 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 31 + line: 3 + character: 1 + end_position: + bytes: 32 + line: 3 + character: 1 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 32 + line: 4 + character: 1 + end_position: + bytes: 37 + line: 4 + character: 6 + token_type: + type: Identifier + identifier: print +- start_position: + bytes: 37 + line: 4 + character: 6 + end_position: + bytes: 38 + line: 4 + character: 7 + token_type: + type: Symbol + symbol: ( +- start_position: + bytes: 38 + line: 4 + character: 7 + end_position: + bytes: 54 + line: 5 + character: 8 + token_type: + type: StringLiteral + literal: "Hello \\\n\tWorld" + quote_type: Double +- start_position: + bytes: 54 + line: 5 + character: 8 + end_position: + bytes: 55 + line: 5 + character: 9 + token_type: + type: Symbol + symbol: ) +- start_position: + bytes: 55 + line: 5 + character: 9 + end_position: + bytes: 56 + line: 5 + character: 9 + token_type: + type: Whitespace + characters: "\n" +- start_position: + bytes: 56 + line: 6 + character: 1 + end_position: + bytes: 56 + line: 6 + character: 1 token_type: type: Eof