diff --git a/.gitignore b/.gitignore
index 7e8ea38a87c731336f4c99a9052fd38adba02cbe..68ec47295083dab2e361efe792ce6d6e857bdb0d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,7 +19,6 @@ build.clang/*
 # Local configurations
 .vim/*
 .vscode/*
-
-# CCLS styff
+.idea/
 .ccls*/
 .ccls
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 08e07772c361dad38867ddc85996bf2d591190e9..e9493eb8aa2a25c9baa81a04137228e37fdfbf95 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,45 +11,46 @@ endif()
 message(STATUS "The installation prefix is ${CMAKE_INSTALL_PREFIX}")
 message(STATUS "The build type is ${CMAKE_BUILD_TYPE}")
 
-# Don't forget for specific things
-if(WIN32)
-    message(STATUS "You are building on windows, pay attenion to the dependencies")
-endif()
-if(MSVC OR MSYS OR MINGW)
-    message(STATUS "You are building with a windows compiler")
-elseif(APPLE)
-    message(STATUS "You are building on MacOS X")
-elseif(UNIX AND NOT APPLE)
-    message(STATUS "You are building on Linux, FreeBSD or any other toaster OS")
-else()
-    message(FATAL_ERROR "The OS is not recognized")
-endif()
-
 set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Pass -fPIC
 set(CMAKE_COLOR_MAKEFILE            ON)
 set(CMAKE_COLOR_DIAGNOSTICS         ON)
-set(CMAKE_EXPORT_COMPILE_COMMANDS   ON)
+set(CMAKE_EXPORT_COMPILE_COMMANDS   ON) # Always to that...
 set(THREADS_PREFER_PTHREAD_FLAG     ON) # Pthread ftw
+set(CMAKE_AUTOUIC                   ON)
+set(CMAKE_AUTOMOC                   ON)
+set(CMAKE_AUTORCC                   ON)
+
+# Do the thing with UPX to try to reduce the size of large executables
+option(USE_UPX "Use upx to reduce executable size [OFF,ON,AUTO]" AUTO)
+find_program(UPX upx DOC "Use upx to compress executables, optional")
+if(UPX STREQUAL "UPX-NOTFOUND")
+    if(USE_UPX STREQUAL "ON")
+        message(ERROR "The upx executable was not found (USE_UPX=ON)")
+    else()
+        message(STATUS "The upx executable was not found, don't compress executable (USE_UPX=${USE_UPX})")
+        macro(upx_pack TARGET EXEC)
+        endmacro()
+    endif()
+elseif((USE_UPX STREQUAL "ON") OR (USE_UPX STREQUAL "AUTO"))
+    message(STATUS "The ${UPX} program will be used to compress the built binaries (USE_UPX=${USE_UPX})")
+    macro(upx_pack TARGET EXEC)
+        add_custom_command(TARGET "${TARGET}" POST_BUILD USES_TERMINAL
+            COMMAND ${UPX} -qt "${EXEC}" || ${UPX} --best --lzma "${EXEC}"
+        )
+    endmacro()
+else()
+    message(STATUS "The upx executable was found, but we won't use it (USE_UPX=OFF)")
+    macro(upx_pack TARGET EXEC)
+    endmacro()
+endif()
 
-# For Qt
-set(CMAKE_AUTOUIC ON)
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-
-# Find Qt dependencies
-find_package(Qt6 REQUIRED COMPONENTS
-    Widgets
-    OpenGL
-    OpenGLWidgets
-)
-
-# Find others dependencies
-find_library(AVCODEC_LIBRARY    avcodec     4.0 REQUIRED)
-find_library(AVUTIL_LIBRARY     avutil      4.0 REQUIRED)
-find_library(SWRESAMPLE_LIBRARY swresample      REQUIRED)
-find_library(AVFORMAT_LIBRARY   avformat        REQUIRED)
-find_library(MPV_LIBRARY        mpv             REQUIRED)
-find_package(                   OpenMP          REQUIRED)
+# Dependencies
+find_package(Qt6 COMPONENTS Widgets OpenGL OpenGLWidgets REQUIRED)
+find_library(AVCODEC_LIBRARY    avcodec    4.0 REQUIRED)
+find_library(AVUTIL_LIBRARY     avutil     4.0 REQUIRED)
+find_library(SWRESAMPLE_LIBRARY swresample     REQUIRED)
+find_library(AVFORMAT_LIBRARY   avformat       REQUIRED)
+find_library(MPV_LIBRARY        mpv            REQUIRED)
 
 # Grab all files
 file(GLOB_RECURSE Vivy_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc")
@@ -59,6 +60,18 @@ if(APPLE)
 endif()
 set(PROJECT_SOURCES ${Vivy_SRC} ${Vivy_INC} ${Vivy_APPLE_SRC})
 
+# The Rust lib
+add_custom_target(libvivy
+    COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/utils/scripts/build-libvivy.bash"
+        "${CMAKE_CURRENT_BINARY_DIR}" ${CARGO_RELEASE_BUILD}
+    BYPRODUCTS  vvcc libvivy.a
+    COMMENT     "Rust library to embed into Vivy"
+    USES_TERMINAL
+)
+upx_pack(libvivy "${CMAKE_CURRENT_BINARY_DIR}/vvcc")
+set_property(TARGET libvivy PROPERTY ADDITIONAL_CLEAN_FILES "vvcc;libvivy.a")
+install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/vvcc" DESTINATION bin)
+
 # Add the Vivy executable
 qt_add_executable(Vivy
     MANUAL_FINALIZATION
@@ -66,6 +79,9 @@ qt_add_executable(Vivy
     rsc/VivyRessources.qrc
 )
 qt_set_finalizer_mode(Vivy ENABLE MODES static_plugins)
+add_dependencies(Vivy libvivy)
+upx_pack(Vivy "${CMAKE_CURRENT_BINARY_DIR}/Vivy")
+install(TARGETS Vivy RUNTIME DESTINATION bin)
 
 set(Vivy_PRECOMPILED_INC PRIVATE src/PreCompiledHeaders.hh)
 
@@ -83,7 +99,7 @@ target_link_libraries(Vivy PRIVATE ${AVUTIL_LIBRARY})
 target_link_libraries(Vivy PRIVATE ${SWRESAMPLE_LIBRARY})
 target_link_libraries(Vivy PRIVATE ${AVFORMAT_LIBRARY})
 target_link_libraries(Vivy PRIVATE ${MPV_LIBRARY})
-target_link_libraries(Vivy PRIVATE OpenMP::OpenMP_CXX)
+target_link_libraries(Vivy PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/libvivy.a)
 
 # Headers related things
 target_include_directories(Vivy PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
@@ -145,10 +161,12 @@ if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
         -Wno-c++98-compat-pedantic
         -Wno-c++98-c++11-c++14-c++17-compat-pedantic
         -Wno-c++20-compat
+        -Wno-unsafe-buffer-usage
 
         # Different versions of MPV...
         -Wno-switch-enum
 
+        -Wno-unknown-warning-option
         -Wno-reserved-identifier
         -Wno-extra-semi-stmt
         -Wno-redundant-parens
diff --git a/README.md b/README.md
index 4e99f86760827e6f64af02a89c57357f1996eaf1..ac7fa9edb6cb8133b4870cb8db227297f2696b45 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,14 @@
 
 ## Prerequisites
 
-- [rust](https://www.rust-lang.org) compiler with version >= 1.70
+- [rust](https://www.rust-lang.org) compiler with version >= 1.77
 - [cmake](https://cmake.org/) at least the version 3.18
 - C++ compiler with [C++17 support](https://en.cppreference.com/w/cpp/17)
 - [mpv](https://mpv.io/) development library
 - [Qt6](https://www.qt.io/) development library: QtCore, QtWidgets, QtOpenGL, QtOpenGLWidgets.
-- The AV libraries: libavutil libavcodec libavformat
+- The AV libraries in e recent version: libavutil libavcodec libavformat
 - [cbindgen](https://github.com/mozilla/cbindgen): `cargo install --force cbindgen`
+- [cargo-insta](https://insta.rs/docs/cli/): `cargo install --force cargo-insta`
 - Some unix utils, the `jq` binary, the `bash` shell.
 
 ## Build
@@ -16,22 +17,41 @@
 Simply use cmake to build in another folder of the source folder:
 
 ```bash
+# Prepare, compile and install
 cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_INSTALL_PREFIX=$HOME/.local -GNinja
 ninja -Cbuild
 ninja -Cbuild install
 ```
 
-To do a debug build, use the debug switch with cmake: `-DCMAKE_BUILD_TYPE=Debug`. Note that the last
-option is here to generate the `compile_commands.json`, you should copy it at the root of the
-project.
+To do a debug build, use the debug switch with cmake: `-DCMAKE_BUILD_TYPE=Debug`.
 
-## Licence
+To only build and use vvcc, you may use the following commands:
+
+```bash
+cd src/Rust
+
+# Build and install, if vvcc is too big, you can use upx
+cargo install --path vvs_cli
 
-The C++ part of this software is licenced under the LGPL v3.0 or latter. The Rust part is under the
-MIT license.
+# Man pages
+mkdir -p $HOME/.local/share/man/man1/
+vvcc --manpage > $HOME/.local/share/man/man1/vvcc.1
 
----
+# Shell completion scripts
+mkdir -p $HOME/.local/share/completion/
+vvcc --shell bash > $HOME/.local/share/bash-completion/completions/vvcc
+vvcc --shell zsh  > $HOME/.local/share/zsh/site-functions/_vvcc
+
+# View the dependencies
+cargo install cargo-depgraph
+cargo depgraph --build-deps --dedup-transitive-deps | dot -Tpdf | zathura -
+```
+
+## Licence
 
-# TODO!
+- The C++ part of this software is licenced under [the LGPL v3.0 or latter](/LICENSE)
+- The Rust part (Vivy Script) is under the [MIT license](/src/Rust/LICENSE.txt)
+- The NotoSans fonts are distributed using the [OFL licence](/rsc/licence/OFL-1.1)
+- Some parts of the Rust folder (vvs_parser, vvs_parser_derive) are under the
+  [MPL-2.0](/src/Rust/full_moon/LICENSE.txt)
 
-- Use the rust things for the ASS instead of the C++ thing.
diff --git a/TOFIX.md b/TOFIX.md
index b98321dd639ed0b461da4269617be0fc1fc1e942..dd353838043c7c88b4247f349335d0a529fe9ab9 100644
--- a/TOFIX.md
+++ b/TOFIX.md
@@ -1,6 +1,14 @@
+# MISC
+
 - [ ] Save file: do not error on save = name
 - [ ] Load Ass: do not fail on Default style not defined
 - [ ] Save file: add .vivy extension by default
-- [ ] Save/Load file: use the rust thing, also find a way to populate the properties with that thing
 - [ ] Problems with the mouse with video/ass/audio sub-documents
 - [ ] Some videos won't embed with the OpenGL thing...
+
+# Script Specific
+
+- [ ] We can't have recursive types for containers, for example we can't have a table that contains
+      tables, or a sequence that contains sequences. We must enforce that
+- [ ] Enforce variant declaration correctness (ints or floats, maybe only one string that is always
+      that last thing)
diff --git a/rsc/VivyRessources.qrc b/rsc/VivyRessources.qrc
index 8f32cedb7cdd095af365c96baba55e470eeacaeb..53700b1d440c6e383b871431f710d3a6e44e6579 100644
--- a/rsc/VivyRessources.qrc
+++ b/rsc/VivyRessources.qrc
@@ -9,10 +9,7 @@
     <!-- Fonts, FiraCode is OFL-1.1, NotoSans is APACHE-2.0 -->
     <file>fonts/FiraCode-Regular.ttf</file>
     <file>fonts/FiraCode-Bold.ttf</file>
-    <file>fonts/NotoSans-Bold.ttf</file>
-    <file>fonts/NotoSans-Italic.ttf</file>
     <file>fonts/NotoSans-Regular.ttf</file>
-    <file>fonts/NotoSans-BoldItalic.ttf</file>
 
     <!-- Licences -->
     <file>licence/LGPL-V2.0</file>
diff --git a/rsc/fonts/NotoSans-Bold.ttf b/rsc/fonts/NotoSans-Bold.ttf
deleted file mode 100644
index 54ad879b41b5db8b21dca1aa00a2d474697e7bf0..0000000000000000000000000000000000000000
Binary files a/rsc/fonts/NotoSans-Bold.ttf and /dev/null differ
diff --git a/rsc/fonts/NotoSans-BoldItalic.ttf b/rsc/fonts/NotoSans-BoldItalic.ttf
deleted file mode 100644
index 530a82835d3b0b07d4b56cfae9ebfa5e02a9129e..0000000000000000000000000000000000000000
Binary files a/rsc/fonts/NotoSans-BoldItalic.ttf and /dev/null differ
diff --git a/rsc/fonts/NotoSans-Italic.ttf b/rsc/fonts/NotoSans-Italic.ttf
deleted file mode 100644
index 27ff1ed60a9afc0e6a4d7604abf6d9ad307ef7fd..0000000000000000000000000000000000000000
Binary files a/rsc/fonts/NotoSans-Italic.ttf and /dev/null differ
diff --git a/src/Rust/Cargo.lock b/src/Rust/Cargo.lock
index 438b9cce5e2c3acb9b7aecd42b68361435637657..724c516d66202c5a162160f278bac90c7d2ebc7d 100644
--- a/src/Rust/Cargo.lock
+++ b/src/Rust/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "ab_glyph"
-version = "0.2.22"
+version = "0.2.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1061f3ff92c2f65800df1f12fc7b4ff44ee14783104187dd04dfee6f11b0fd2"
+checksum = "79faae4620f45232f599d9bc7b290f88247a0834162c4495ab2f02d60004adfb"
 dependencies = [
  "ab_glyph_rasterizer",
  "owned_ttf_parser",
@@ -20,9 +20,9 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
 
 [[package]]
 name = "ahash"
-version = "0.8.6"
+version = "0.8.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
 dependencies = [
  "cfg-if",
  "once_cell",
@@ -32,42 +32,118 @@ dependencies = [
 
 [[package]]
 name = "aho-corasick"
-version = "1.1.2"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "allocator-api2"
-version = "0.2.16"
+version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
+checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
+
+[[package]]
+name = "anes"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
 
 [[package]]
 name = "anstyle"
-version = "1.0.4"
+version = "1.0.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
+checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
 
 [[package]]
 name = "anyhow"
-version = "1.0.75"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi 0.1.19",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
 
 [[package]]
 name = "bitflags"
-version = "2.4.1"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "bstr"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
 name = "bytecount"
-version = "0.6.7"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
+
+[[package]]
+name = "cast"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205"
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+
+[[package]]
+name = "cbindgen"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49"
+dependencies = [
+ "clap 3.2.25",
+ "heck 0.4.1",
+ "indexmap 1.9.3",
+ "log",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "syn 1.0.109",
+ "tempfile",
+ "toml 0.5.11",
+]
+
+[[package]]
+name = "cc"
+version = "1.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549"
 
 [[package]]
 name = "cfg-if"
@@ -75,11 +151,53 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
+[[package]]
+name = "ciborium"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
+dependencies = [
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
+]
+
+[[package]]
+name = "ciborium-io"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
+
+[[package]]
+name = "ciborium-ll"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
+dependencies = [
+ "ciborium-io",
+ "half",
+]
+
+[[package]]
+name = "clap"
+version = "3.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
+dependencies = [
+ "atty",
+ "bitflags 1.3.2",
+ "clap_lex 0.2.4",
+ "indexmap 1.9.3",
+ "strsim 0.10.0",
+ "termcolor",
+ "textwrap",
+]
+
 [[package]]
 name = "clap"
-version = "4.4.7"
+version = "4.5.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
+checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -87,53 +205,203 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.4.7"
+version = "4.5.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
+checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99"
 dependencies = [
  "anstyle",
- "clap_lex",
- "strsim",
+ "clap_lex 0.7.2",
+ "strsim 0.11.1",
  "terminal_size",
 ]
 
 [[package]]
 name = "clap_complete"
-version = "4.4.4"
+version = "4.5.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae"
+checksum = "a8670053e87c316345e384ca1f3eba3006fc6355ed8b8a1140d104e109e3df34"
 dependencies = [
- "clap",
+ "clap 4.5.13",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.4.7"
+version = "4.5.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
+checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
 dependencies = [
- "heck",
+ "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.72",
 ]
 
 [[package]]
 name = "clap_lex"
-version = "0.6.0"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+dependencies = [
+ "os_str_bytes",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
+checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
 
 [[package]]
 name = "clap_mangen"
-version = "0.2.15"
+version = "0.2.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3be86020147691e1d2ef58f75346a3d4d94807bfc473e377d52f09f0f7d77f7"
+checksum = "f17415fd4dfbea46e3274fcd8d368284519b358654772afb700dc2e8d2b24eeb"
 dependencies = [
- "clap",
+ "clap 4.5.13",
  "roff",
 ]
 
+[[package]]
+name = "codespan"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3362992a0d9f1dd7c3d0e89e0ab2bb540b7a95fea8cd798090e758fda2899b5e"
+dependencies = [
+ "codespan-reporting",
+]
+
+[[package]]
+name = "codespan-reporting"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
+dependencies = [
+ "termcolor",
+ "unicode-width",
+]
+
+[[package]]
+name = "console"
+version = "0.15.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
+dependencies = [
+ "encode_unicode",
+ "lazy_static",
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "convert_case"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "criterion"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
+dependencies = [
+ "anes",
+ "cast",
+ "ciborium",
+ "clap 4.5.13",
+ "criterion-plot",
+ "is-terminal",
+ "itertools",
+ "num-traits",
+ "once_cell",
+ "oorandom",
+ "plotters",
+ "rayon",
+ "regex",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "tinytemplate",
+ "walkdir",
+]
+
+[[package]]
+name = "criterion-plot"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
+dependencies = [
+ "cast",
+ "itertools",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "derive_more"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
+dependencies = [
+ "derive_more-impl",
+]
+
+[[package]]
+name = "derive_more-impl"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+ "unicode-xid",
+]
+
+[[package]]
+name = "either"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+
+[[package]]
+name = "encode_unicode"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+
 [[package]]
 name = "equivalent"
 version = "1.0.1"
@@ -142,19 +410,54 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "errno"
-version = "0.3.5"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
 dependencies = [
  "libc",
- "windows-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
+
+[[package]]
+name = "globset"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
+dependencies = [
+ "aho-corasick",
+ "bstr",
+ "log",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "half"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
+dependencies = [
+ "cfg-if",
+ "crunchy",
 ]
 
 [[package]]
 name = "hashbrown"
-version = "0.14.2"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 dependencies = [
  "ahash",
  "allocator-api2",
@@ -166,105 +469,260 @@ version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
 [[package]]
 name = "indexmap"
-version = "2.0.2"
+version = "1.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0"
 dependencies = [
  "equivalent",
- "hashbrown",
+ "hashbrown 0.14.5",
 ]
 
+[[package]]
+name = "insta"
+version = "1.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "810ae6042d48e2c9e9215043563a58a80b877bc863228a74cf10c49d4620a6f5"
+dependencies = [
+ "console",
+ "globset",
+ "lazy_static",
+ "linked-hash-map",
+ "serde",
+ "similar",
+ "walkdir",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
+dependencies = [
+ "hermit-abi 0.3.9",
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
+name = "js-sys"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
 [[package]]
 name = "libc"
-version = "0.2.149"
+version = "0.2.155"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.10"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
+name = "llvm-sys"
+version = "181.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d255b36907416971229095a8465c0b69f5f1c6fb8421b6dcdbb64eb47e1be90"
+dependencies = [
+ "anyhow",
+ "cc",
+ "lazy_static",
+ "libc",
+ "regex-lite",
+ "semver",
+]
 
 [[package]]
 name = "log"
-version = "0.4.20"
+version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
 [[package]]
 name = "memchr"
-version = "2.6.4"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[package]]
-name = "minimal-lexical"
-version = "0.2.1"
+name = "oorandom"
+version = "11.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
 
 [[package]]
-name = "nom"
-version = "7.1.3"
+name = "os_str_bytes"
+version = "6.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
+
+[[package]]
+name = "owned_ttf_parser"
+version = "0.24.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "490d3a563d3122bf7c911a59b0add9389e5ec0f5f0c3ac6b91ff235a0e6a7f90"
 dependencies = [
- "memchr",
- "minimal-lexical",
+ "ttf-parser",
 ]
 
 [[package]]
-name = "nom_locate"
-version = "4.2.0"
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "plotters"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e3c83c053b0713da60c5b8de47fe8e494fe3ece5267b2f23090a07a053ba8f3"
+checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3"
 dependencies = [
- "bytecount",
- "memchr",
- "nom",
+ "num-traits",
+ "plotters-backend",
+ "plotters-svg",
+ "wasm-bindgen",
+ "web-sys",
 ]
 
 [[package]]
-name = "once_cell"
-version = "1.18.0"
+name = "plotters-backend"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7"
 
 [[package]]
-name = "owned_ttf_parser"
-version = "0.19.0"
+name = "plotters-svg"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "706de7e2214113d63a8238d1910463cfce781129a6f263d13fdb09ff64355ba4"
+checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705"
 dependencies = [
- "ttf-parser",
+ "plotters-backend",
 ]
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.69"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.33"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
 dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "rayon"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
 [[package]]
 name = "regex"
-version = "1.10.2"
+version = "1.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -274,65 +732,120 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.3"
+version = "0.4.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
 dependencies = [
  "aho-corasick",
  "memchr",
  "regex-syntax",
 ]
 
+[[package]]
+name = "regex-lite"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
+
 [[package]]
 name = "regex-syntax"
-version = "0.8.2"
+version = "0.8.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
 
 [[package]]
 name = "roff"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
+checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
 
 [[package]]
 name = "rustix"
-version = "0.38.21"
+version = "0.38.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
+checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
 dependencies = [
- "bitflags",
+ "bitflags 2.6.0",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
 ]
 
+[[package]]
+name = "semver"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+
 [[package]]
 name = "serde"
-version = "1.0.190"
+version = "1.0.205"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
+checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.190"
+version = "1.0.205"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
+checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.72",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.122"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
+dependencies = [
+ "indexmap 2.3.0",
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
 ]
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.4"
+version = "0.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "similar"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e"
+
+[[package]]
+name = "smol_str"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80"
+checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead"
 dependencies = [
  "serde",
 ]
@@ -343,17 +856,56 @@ version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
 [[package]]
 name = "syn"
-version = "2.0.38"
+version = "2.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
+checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-ident",
 ]
 
+[[package]]
+name = "tempfile"
+version = "3.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
 [[package]]
 name = "terminal_size"
 version = "0.3.0"
@@ -361,34 +913,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
 dependencies = [
  "rustix",
- "windows-sys",
+ "windows-sys 0.48.0",
 ]
 
+[[package]]
+name = "textwrap"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
+
 [[package]]
 name = "thiserror"
-version = "1.0.50"
+version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
+checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.50"
+version = "1.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
+checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.72",
+]
+
+[[package]]
+name = "tinytemplate"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
+dependencies = [
+ "serde",
+ "serde_json",
 ]
 
 [[package]]
 name = "toml"
-version = "0.8.5"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3efaf127c78d5339cc547cce4e4d973bd5e4f56e949a06d091c082ebeef2f800"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -398,20 +975,20 @@ dependencies = [
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.5"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "toml_edit"
-version = "0.20.5"
+version = "0.22.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "782bf6c2ddf761c1e7855405e8975472acf76f7f36d0d4328bd3b7a2fae12a85"
+checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
 dependencies = [
- "indexmap",
+ "indexmap 2.3.0",
  "serde",
  "serde_spanned",
  "toml_datetime",
@@ -420,9 +997,9 @@ dependencies = [
 
 [[package]]
 name = "ttf-parser"
-version = "0.19.2"
+version = "0.24.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49d64318d8311fc2668e48b63969f4343e0a85c4a109aa8460d6672e364b8bd1"
+checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a"
 
 [[package]]
 name = "unicode-ident"
@@ -432,15 +1009,27 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "unicode-segmentation"
-version = "1.10.1"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
+checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
 
 [[package]]
 name = "version_check"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
 
 [[package]]
 name = "vvs_ass"
@@ -461,14 +1050,34 @@ name = "vvs_cli"
 version = "0.5.0"
 dependencies = [
  "anyhow",
- "clap",
+ "clap 4.5.13",
  "clap_complete",
  "clap_mangen",
  "log",
  "serde",
  "thiserror",
- "toml",
+ "toml 0.8.19",
+ "vvs_ass",
+ "vvs_codegen",
  "vvs_font",
+ "vvs_llvm",
+ "vvs_parser",
+ "vvs_runtime",
+ "vvs_utils",
+]
+
+[[package]]
+name = "vvs_codegen"
+version = "0.5.0"
+dependencies = [
+ "anyhow",
+ "hashbrown 0.14.5",
+ "log",
+ "serde",
+ "serde_json",
+ "vvs_lang",
+ "vvs_llvm",
+ "vvs_runtime_types",
  "vvs_utils",
 ]
 
@@ -487,41 +1096,250 @@ name = "vvs_lang"
 version = "0.5.0"
 dependencies = [
  "anyhow",
- "hashbrown",
+ "derive_more",
+ "hashbrown 0.14.5",
  "log",
- "nom",
- "nom_locate",
+ "paste",
  "regex",
  "serde",
  "thiserror",
+ "toml 0.8.19",
+ "vvs_parser",
  "vvs_utils",
 ]
 
+[[package]]
+name = "vvs_lib"
+version = "0.5.0"
+dependencies = [
+ "cbindgen",
+ "hashbrown 0.14.5",
+ "log",
+ "serde",
+ "serde_json",
+ "vvs_ass",
+]
+
+[[package]]
+name = "vvs_llvm"
+version = "0.5.0"
+dependencies = [
+ "anyhow",
+ "llvm-sys",
+ "log",
+]
+
+[[package]]
+name = "vvs_parser"
+version = "0.5.0"
+dependencies = [
+ "anyhow",
+ "bytecount",
+ "cfg-if",
+ "codespan",
+ "codespan-reporting",
+ "criterion",
+ "derive_more",
+ "hashbrown 0.14.5",
+ "insta",
+ "log",
+ "paste",
+ "serde",
+ "smol_str",
+ "termcolor",
+ "vvs_parser_derive",
+]
+
+[[package]]
+name = "vvs_parser_derive"
+version = "0.5.0"
+dependencies = [
+ "indexmap 2.3.0",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "vvs_procmacro"
 version = "0.5.0"
 dependencies = [
+ "anyhow",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.72",
+]
+
+[[package]]
+name = "vvs_runtime"
+version = "0.5.0"
+dependencies = [
+ "anyhow",
+ "log",
+ "serde",
+ "serde_json",
+ "vvs_llvm",
+ "vvs_runtime_types",
+ "vvs_utils",
+]
+
+[[package]]
+name = "vvs_runtime_types"
+version = "0.5.0"
+dependencies = [
+ "anyhow",
+ "hashbrown 0.14.5",
+ "log",
+ "serde",
+ "serde_json",
+ "unicode-segmentation",
+ "vvs_ass",
+ "vvs_lang",
+ "vvs_llvm",
+ "vvs_procmacro",
+ "vvs_utils",
 ]
 
 [[package]]
 name = "vvs_utils"
 version = "0.5.0"
 dependencies = [
+ "anyhow",
  "log",
  "serde",
  "thiserror",
 ]
 
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
+
+[[package]]
+name = "web-sys"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -530,13 +1348,29 @@ version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
 ]
 
 [[package]]
@@ -545,67 +1379,115 @@ version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
 
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
 [[package]]
 name = "windows_aarch64_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
 
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
 [[package]]
 name = "windows_i686_gnu"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
 
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
 [[package]]
 name = "windows_i686_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
 
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
 [[package]]
 name = "windows_x86_64_gnu"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
 
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
 [[package]]
 name = "windows_x86_64_gnullvm"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
 
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
 [[package]]
 name = "windows_x86_64_msvc"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
 
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
 [[package]]
 name = "winnow"
-version = "0.5.17"
+version = "0.6.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c"
+checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "zerocopy"
-version = "0.7.15"
+version = "0.7.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81ba595b9f2772fbee2312de30eeb80ec773b4cb2f1e8098db024afadda6c06f"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
 dependencies = [
  "zerocopy-derive",
 ]
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.7.15"
+version = "0.7.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "772666c41fb6dceaf520b564b962d738a8e1a83b41bd48945f50837aed78bb1d"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.72",
 ]
diff --git a/src/Rust/Cargo.toml b/src/Rust/Cargo.toml
index aeba7e5ad0f4da0a66977cef64410c516894ec9d..840c7a05919cca5327972a63b104b142afae2e09 100644
--- a/src/Rust/Cargo.toml
+++ b/src/Rust/Cargo.toml
@@ -1,54 +1,105 @@
 [workspace]
 resolver = "2"
-members = [
-    "vvs_cli",
-    "vvs_ass",
-    "vvs_font",
-    "vvs_lang",
-    "vvs_utils",
-    "vvs_procmacro",
-]
+members = ["vvs_*"]
+
 
 [workspace.package]
 version = "0.5.0"
-authors = ["Maël MARTIN"]
-description = "The V5 of the Vivy Script utility to manipulate in an easy way ASS files"
-edition = "2021"
-license = "MIT"
+authors = [
+    "Maëlle Martin <maelle.martin@proton.me>",
+    "Kampfkarren <kampfkarren@gmail.com>",
+]
+description  = "The V5 of the Vivy Script utility to manipulate in an easy way ASS files"
+edition      = "2021"
+license      = "MIT"
+rust-version = "1.76"
+
+
+[profile.release]
+debug         = false
+opt-level     = 3
+panic         = "abort"
+strip         = true
+codegen-units = 1
+lto           = true
+
+
+[profile.dev]
+debug     = true
+opt-level = "s"
+
 
 [workspace.dependencies]
+# Local dependencies
+vvs_parser_derive = { path = "vvs_parser_derive" }
+vvs_parser        = { path = "vvs_parser"        }
+vvs_procmacro     = { path = "vvs_procmacro"     }
+vvs_utils         = { path = "vvs_utils"         }
+vvs_font          = { path = "vvs_font"          }
+vvs_ass           = { path = "vvs_ass"           }
+vvs_lang          = { path = "vvs_lang"          }
+vvs_runtime       = { path = "vvs_runtime"       }
+vvs_codegen       = { path = "vvs_codegen"       }
+vvs_llvm          = { path = "vvs_llvm"          }
+vvs_runtime_types = { path = "vvs_runtime_types" }
+
 # Utils
-thiserror = "1"
-anyhow = "1"
-paste = "1"
-log = "0.4"
-bitflags = { version = "2", default-features = false }
-unicode-segmentation = "1"
-hashbrown = "0.14"
+bytecount   = "*"
+cfg-if      = "*"
+paste       = "*"
+indexmap    = "*"
+thiserror   = "*"
+anyhow      = "*"
+log         = "*"
+hashbrown   = "*"
+cbindgen    = "*"
+termcolor   = "*"
+derive_more = { version = "*", features = ["full"] }
+smol_str    = { version = "*", features = ["serde"] }
+bitflags    = { version = "*", default-features = false }
 
 # Parsing
-regex = { version = "1", default-features = false, features = ["std"] }
-nom = { version = "7", default-features = false, features = ["std"] }
-nom_locate = { version = "4", default-features = false, features = ["std"] }
+unicode-segmentation = "*"
+regex = { version = "*", default-features = false, features = ["std"] }
 
 # SerDe
-toml = { version = "0.8", default-features = false, features = [
+serde_json = { version = "*", default-features = false, features = [
+    "std",
+    "preserve_order",
+] }
+serde = { version = "*", default-features = false, features = [
+    "std",
+    "rc",
+    "derive",
+] }
+toml = { version = "*", default-features = false, features = [
     "parse",
     "display",
 ] }
-serde = { version = "1", default-features = false, features = [
+
+# ProcMacros
+quote       = "*"
+proc-macro2 = "*"
+
+# FONTS
+ttf-parser = { version = "*" }
+ab_glyph   = { version = "*" }
+
+# CLI
+clap_mangen   = "*" # Could be replace by something crafter by hand…
+clap_complete = "*"
+clap = { version = "*", default-features = false, features = [
+    "usage",
+    "help",
     "std",
+    "suggestions",
+    "error-context",
     "derive",
+    "wrap_help",
 ] }
 
-[profile.release]
-strip = true
-debug = false
-lto = true
-opt-level = "z"
-codegen-units = 1
-panic = "abort"
-
-[profile.dev]
-debug = true
-opt-level = "s"
+# FOR FULL-MOON TESTS
+codespan           = "*"
+codespan-reporting = "*"
+criterion          = "*"
+insta = { version = "*", features = ["glob", "yaml"] }
diff --git a/src/Rust/README.md b/src/Rust/README.md
deleted file mode 100644
index 3337f0bd3339cfea7d9f35318bf790457238cdd6..0000000000000000000000000000000000000000
--- a/src/Rust/README.md
+++ /dev/null
@@ -1,57 +0,0 @@
-# Vivy Script
-The V4 of the Vivy Script utility to manipulate in an easy way ASS files.
-
-# How to build and install
-Like any rust project, simply run:
-
-    cargo build --release
-    cargo install --path vvs_cli
-    vvcc --help
-
-If you want to test it, from the root of the project you may replace any call
-to `vvcc` by `cargo run --bin vvcc --`.
-
-# Misc
-## Manpage
-To get the `vvcc` manpage, just run:
-
-    vvcc --manpage | man -l -
-
-To install it, you may run the following commands:
-
-    mkdir -p $HOME/.local/share/man/man1/
-    vvcc --manpage > $HOME/.local/share/man/man1/vvcc.1
-    man vvcc
-
-## Shell completion
-To get the completion scripts to source you can use the following commands. You
-can then source those files to get the completion working with your shell.
-
-    mkdir -p $HOME/.local/share/completion/
-    vvcc --shell bash > $HOME/.local/share/bash-completion/completions/vvcc
-    vvcc --shell zsh  > $HOME/.local/share/zsh/site-functions/_vvcc
-
-To get the completion working with the system, you can use the following commands:
-
-    vvcc --shell bash > /usr/local/share/bash-completion/completions/vvcc
-    vvcc --shell zsh  > /usr/local/share/zsh/site-functions/_vvcc
-
-To visualize the dependency graph of VivyScript, use the command:
-
-    cargo install cargo-depgraph
-    cargo depgraph --build-deps --dedup-transitive-deps | dot -Tpdf | zathura -
-
-## To test the project
-The unit-tests can be ran on the project by running `cargo test`. The
-integration tests and the unit-tests can be run together by using pcvs in the
-[tests](tests) folder:
-
-    pip install pcvs        -- Install PCVS
-    (cd tests && pcvs run)  -- Run in the correct folder
-
-You can also install PCVS by cloning the project and running `pip install .`
-from its root.
-
-# Licence
-- The VVS project is under the MIT licence
-- The NotoSans fonts are distributed using the [OFL licence](vvs_font/fonts/NotoSans-LICENCE-OFL.txt)
diff --git a/src/Rust/VVLib.h b/src/Rust/VVLib.h
new file mode 100644
index 0000000000000000000000000000000000000000..7dcc900cb3ab67f9bb9d1ea35716c60692000f9a
--- /dev/null
+++ b/src/Rust/VVLib.h
@@ -0,0 +1,187 @@
+/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
+
+#pragma once
+
+/* Generated with cbindgen:0.26.0 */
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+namespace VVLib {
+namespace C {
+#endif // __cplusplus
+
+/**
+ * Wraps the container that holds all the content of the ASS file / Vivy file.
+ */
+typedef struct ASSContainer ASSContainer;
+
+/**
+ * Wraps a line in an ASS file.
+ */
+typedef struct ASSLine ASSLine;
+
+/**
+ * Type used to describe an ASS style.
+ */
+typedef struct ASSStyle ASSStyle;
+
+/**
+ * Wraps syllabes, contained in lines in ASS files.
+ */
+typedef struct ASSSyllabe ASSSyllabe;
+
+/**
+ * Represents a string slice, the user may not modify this slice, never! Note that the string is
+ * not null terminated and may contains null bytes in it, use the len attribute to get the length
+ * of this string and convert it to your linking.
+ *
+ * # Safety
+ * Note that you must always put unicode inside a string slice!
+ */
+typedef struct StringSlice
+{
+    uintptr_t len;
+    const char *str;
+} StringSlice;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * Get the number of lines in the container.
+ */
+int32_t ASSContainerGetLinesCount(const struct ASSContainer *this_);
+
+/**
+ * Get the number of syllabes in the line.
+ */
+int32_t ASSLineGetSyllabesCount(const struct ASSLine *this_);
+
+/**
+ * Get a line by its number in the container.
+ */
+struct ASSLine *ASSContainerGetLineAt(struct ASSContainer *this_, int32_t idx);
+
+/**
+ * Get a syllabe in a line by its index.
+ */
+struct ASSSyllabe *ASSLineGetSyllabeAt(struct ASSLine *this_, int32_t idx);
+
+/**
+ * Tells whever a line is commented or not.
+ */
+bool ASSLineIsCommented(const struct ASSLine *this_);
+
+/**
+ * Gets the style of the line, or 'Default' if it was not found/specified.
+ */
+struct StringSlice ASSLineGetStyle(const struct ASSLine *this_);
+
+/**
+ * Get the content of a syllabe.
+ */
+struct StringSlice ASSSyllabeGetContent(const struct ASSSyllabe *this_);
+
+/**
+ * Get the duration of a syllabe.
+ */
+int32_t ASSSyllabeGetDuration(const struct ASSSyllabe *this_);
+
+/**
+ * Get the start of a syllabe.
+ */
+int32_t ASSSyllabeGetStartTime(const struct ASSSyllabe *this_);
+
+/**
+ * Get the end time of a syllabe.
+ */
+int32_t ASSSyllabeGetFiniTime(const struct ASSSyllabe *this_);
+
+/**
+ * Set the duration of a syllabe.
+ */
+void ASSSyllabeSetDuration(struct ASSSyllabe *this_, int32_t duration);
+
+/**
+ * Set the start of a syllabe.
+ */
+void ASSSyllabeSetStartTime(struct ASSSyllabe *this_, int32_t time);
+
+/**
+ * Set the end of a syllabe.
+ */
+void ASSSyllabeSetFiniTime(struct ASSSyllabe *this_, int32_t time);
+
+/**
+ * Load the ASS from a file, returns nullptr if an error was encountred.
+ */
+struct ASSContainer *ASSContainerFromFile(char *path);
+
+/**
+ * Get a style out of the container by its name.
+ */
+struct ASSStyle *ASSContainerGetStyleByName(struct ASSContainer *this_, struct StringSlice name);
+
+/**
+ * Get the name of a style by its position.
+ */
+struct StringSlice ASSContainerGetStyleNameAt(const struct ASSContainer *this_, int32_t idx);
+
+/**
+ * Get the number of styles in the container.
+ */
+int32_t ASSContainerGetStylesCount(const struct ASSContainer *this_);
+
+/**
+ * Set the start time of the line.
+ */
+void ASSLineSetStartTime(struct ASSLine *this_, int32_t time);
+
+/**
+ * Set the end time of a line.
+ */
+void ASSLineSetFiniTime(struct ASSLine *this_, int32_t time);
+
+/**
+ * Get the duration of a line.
+ */
+int32_t ASSLineGetDuration(const struct ASSLine *this_);
+
+/**
+ * Set the duration of a line.
+ */
+void ASSLineSetDuration(struct ASSLine *this_, int32_t duration);
+
+/**
+ * Get the start time of a line.
+ */
+int32_t ASSLineGetStartTime(const struct ASSLine *this_);
+
+/**
+ * Get the end time of a line.
+ */
+int32_t ASSLineGetFiniTime(const struct ASSLine *this_);
+
+/**
+ * Drop the container. It is file to pass a null pointer to this function.
+ */
+void ASSContainerDrop(struct ASSContainer *this_);
+
+/**
+ * Get the name of the style.
+ *
+ * # Safety
+ * It is up to the user to ensure that the style is not dropped before the returned pointer.
+ */
+struct StringSlice ASSStyleGetName(const struct ASSStyle *this_);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+#ifdef __cplusplus
+} // namespace C
+} // namespace VVLib
+#endif // __cplusplus
diff --git a/src/Rust/VVLib.hh b/src/Rust/VVLib.hh
new file mode 100644
index 0000000000000000000000000000000000000000..93ab3c44189bfa2856d0060bdcd998d6dff73177
--- /dev/null
+++ b/src/Rust/VVLib.hh
@@ -0,0 +1,123 @@
+/// This file was hand-written to wrap the generated C ABI into a C++ wrapper.
+
+#include "VVLib.h"
+
+#include <algorithm>
+#include <string>
+#include <string_view>
+
+namespace VVLib
+{
+class ASSContainer;
+class ASSLine;
+class ASSSyllabe;
+
+/// ASSSyllabe modelize each syllabe of each line in the ASS file.
+class ASSSyllabe {
+    C::ASSSyllabe *const self;
+    friend ASSLine;
+
+    ASSSyllabe(C::ASSSyllabe *const zelf) noexcept
+        : self(zelf)
+    {
+    }
+
+public:
+    const std::string_view content() const noexcept
+    {
+        const C::StringSlice slice = C::ASSSyllabeGetContent(self);
+        return std::string_view(slice.str, slice.len);
+    }
+    char operator[](int i) noexcept { return content()[static_cast<size_t>(i)]; }
+    char operator[](int i) const noexcept { return content()[static_cast<size_t>(i)]; }
+
+    void set_duration(int dur) noexcept { C::ASSSyllabeSetDuration(self, dur); }
+    void set_start(int start) noexcept { C::ASSSyllabeSetStartTime(self, start); }
+    void set_fini(int fini) noexcept { C::ASSSyllabeSetFiniTime(self, fini); }
+    int duration() const noexcept { return C::ASSSyllabeGetDuration(self); }
+    int start() const noexcept { return C::ASSSyllabeGetStartTime(self); }
+    int fini() const noexcept { return C::ASSSyllabeGetFiniTime(self); }
+};
+
+/// ASSLine modelize each line of an ASS file.
+class ASSLine {
+    C::ASSLine *const self;
+    friend ASSContainer;
+
+    ASSLine(C::ASSLine *const zelf) noexcept
+        : self(zelf)
+    {
+    }
+
+public:
+    int syllabes_count() const noexcept { return C::ASSLineGetSyllabesCount(self); }
+    ASSSyllabe operator[](int i) noexcept { return syllabe_at(i); }
+    const ASSSyllabe operator[](int i) const noexcept { return syllabe_at(i); }
+    const ASSSyllabe syllabe_at(int i) const noexcept
+    {
+        return const_cast<ASSLine *>(this)->syllabe_at(i);
+    }
+    ASSSyllabe syllabe_at(int i) noexcept
+    {
+        return ASSSyllabe(C::ASSLineGetSyllabeAt(self, std::clamp(i, 0, this->syllabes_count())));
+    }
+
+    bool is_commented() const noexcept { return C::ASSLineIsCommented(self); }
+    const std::string_view style() const
+    {
+        const C::StringSlice slice = C::ASSLineGetStyle(self);
+        return std::string_view(slice.str, slice.len);
+    }
+
+    void set_start(int start) noexcept { C::ASSLineSetStartTime(self, start); }
+    void set_fini(int fini) noexcept { C::ASSLineSetFiniTime(self, fini); }
+    void set_duration(int dur) noexcept { C::ASSLineSetDuration(self, dur); }
+    int start() const noexcept { return C::ASSLineGetStartTime(self); }
+    int fini() const noexcept { return C::ASSLineGetFiniTime(self); }
+    int duration() const noexcept { return C::ASSLineGetDuration(self); }
+};
+
+/// The container wraps everything around an ASS file.
+class ASSContainer {
+    C::ASSContainer *const self;
+
+    ASSContainer(const char *path) noexcept
+        : self(C::ASSContainerFromFile(const_cast<char *>(path)))
+    {
+    }
+
+public:
+    ~ASSContainer() noexcept { C::ASSContainerDrop(self); }
+
+    static ASSContainer from_file(const char *path) noexcept { return ASSContainer(path); }
+    static ASSContainer from_file(std::string path) noexcept { return from_file(path.c_str()); }
+    static ASSContainer from_file(std::string_view path) noexcept
+    {
+        return from_file(std::string(path));
+    }
+
+    int styles_count() const noexcept { return C::ASSContainerGetStylesCount(self); }
+    C::ASSStyle *style(std::string_view name) const noexcept
+    {
+        C::StringSlice style{ .len = name.length(), .str = name.data() };
+        return C::ASSContainerGetStyleByName(self, style);
+    }
+    std::string_view style(int idx) const noexcept
+    {
+        const C::StringSlice slice = C::ASSContainerGetStyleNameAt(self, idx);
+        return std::string_view(slice.str, slice.len);
+    }
+
+    int lines_count() const noexcept { return C::ASSContainerGetLinesCount(self); }
+    ASSLine operator[](int i) noexcept { return line_at(i); }
+    const ASSLine operator[](int i) const noexcept { return line_at(i); }
+    const ASSLine line_at(int i) const noexcept
+    {
+        return const_cast<ASSContainer *>(this)->line_at(i);
+    }
+    ASSLine line_at(int i) noexcept
+    {
+        return ASSLine(C::ASSContainerGetLineAt(self, std::clamp(i, 0, this->lines_count())));
+    }
+};
+}
diff --git a/src/Rust/benches/date.lua b/src/Rust/benches/date.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f8f6bcecd8e8fbd9b97579db348d72fb209db035
--- /dev/null
+++ b/src/Rust/benches/date.lua
@@ -0,0 +1,730 @@
+---------------------------------------------------------------------------------------
+-- Module for date and time calculations
+--
+-- Version 2.1.1
+-- Copyright (C) 2006, by Jas Latrix (jastejada@yahoo.com)
+-- Copyright (C) 2013-2014, by Thijs Schreijer
+-- Licensed under MIT, http://opensource.org/licenses/MIT
+
+--[[ CONSTANTS ]]--
+local HOURPERDAY  = 24
+local MINPERHOUR  = 60
+local MINPERDAY    = 1440  -- 24*60
+local SECPERMIN   = 60
+local SECPERHOUR  = 3600  -- 60*60
+local SECPERDAY   = 86400 -- 24*60*60
+local TICKSPERSEC = 1000000
+local TICKSPERDAY = 86400000000
+local TICKSPERHOUR = 3600000000
+local TICKSPERMIN = 60000000
+local DAYNUM_MAX =  365242500 -- Sat Jan 01 1000000 00:00:00
+local DAYNUM_MIN = -365242500 -- Mon Jan 01 1000000 BCE 00:00:00
+local DAYNUM_DEF =  0 -- Mon Jan 01 0001 00:00:00
+local _;
+--[[ LOCAL ARE FASTER ]]--
+local type     = type
+local pairs    = pairs
+local error    = error
+local assert   = assert
+local tonumber = tonumber
+local tostring = tostring
+local string   = string
+local math     = math
+local os       = os
+local unpack   = unpack or table.unpack
+local setmetatable = setmetatable
+local getmetatable = getmetatable
+--[[ EXTRA FUNCTIONS ]]--
+local fmt  = string.format
+local lwr  = string.lower
+local rep  = string.rep
+local len  = string.len  -- luacheck: ignore
+local sub  = string.sub
+local gsub = string.gsub
+local gmatch = string.gmatch or string.gfind
+local find = string.find
+local ostime = os.time
+local osdate = os.date
+local floor = math.floor
+local ceil  = math.ceil
+local abs   = math.abs
+-- removes the decimal part of a number
+local function fix(n) n = tonumber(n) return n and ((n > 0 and floor or ceil)(n)) end
+-- returns the modulo n % d;
+local function mod(n,d) return n - d*floor(n/d) end
+-- is `str` in string list `tbl`, `ml` is the minimun len
+local function inlist(str, tbl, ml, tn)
+  local sl = len(str)
+  if sl < (ml or 0) then return nil end
+  str = lwr(str)
+  for k, v in pairs(tbl) do
+	if str == lwr(sub(v, 1, sl)) then
+	  if tn then tn[0] = k end
+	  return k
+	end
+  end
+end
+local function fnil() end
+--[[ DATE FUNCTIONS ]]--
+local DATE_EPOCH -- to be set later
+local sl_weekdays = {
+  [0]="Sunday",[1]="Monday",[2]="Tuesday",[3]="Wednesday",[4]="Thursday",[5]="Friday",[6]="Saturday",
+  [7]="Sun",[8]="Mon",[9]="Tue",[10]="Wed",[11]="Thu",[12]="Fri",[13]="Sat",
+}
+local sl_meridian = {[-1]="AM", [1]="PM"}
+local sl_months = {
+  [00]="January", [01]="February", [02]="March",
+  [03]="April",   [04]="May",      [05]="June",
+  [06]="July",    [07]="August",   [08]="September",
+  [09]="October", [10]="November", [11]="December",
+  [12]="Jan", [13]="Feb", [14]="Mar",
+  [15]="Apr", [16]="May", [17]="Jun",
+  [18]="Jul", [19]="Aug", [20]="Sep",
+  [21]="Oct", [22]="Nov", [23]="Dec",
+}
+-- added the '.2'  to avoid collision, use `fix` to remove
+local sl_timezone = {
+  [000]="utc",    [0.2]="gmt",
+  [300]="est",    [240]="edt",
+  [360]="cst",  [300.2]="cdt",
+  [420]="mst",  [360.2]="mdt",
+  [480]="pst",  [420.2]="pdt",
+}
+-- set the day fraction resolution
+local function setticks(t)
+  TICKSPERSEC = t;
+  TICKSPERDAY = SECPERDAY*TICKSPERSEC
+  TICKSPERHOUR= SECPERHOUR*TICKSPERSEC
+  TICKSPERMIN = SECPERMIN*TICKSPERSEC
+end
+-- is year y leap year?
+local function isleapyear(y) -- y must be int!
+  return (mod(y, 4) == 0 and (mod(y, 100) ~= 0 or mod(y, 400) == 0))
+end
+-- day since year 0
+local function dayfromyear(y) -- y must be int!
+  return 365*y + floor(y/4) - floor(y/100) + floor(y/400)
+end
+-- day number from date, month is zero base
+local function makedaynum(y, m, d)
+  local mm = mod(mod(m,12) + 10, 12)
+  return dayfromyear(y + floor(m/12) - floor(mm/10)) + floor((mm*306 + 5)/10) + d - 307
+  --local yy = y + floor(m/12) - floor(mm/10)
+  --return dayfromyear(yy) + floor((mm*306 + 5)/10) + (d - 1)
+end
+-- date from day number, month is zero base
+local function breakdaynum(g)
+  local g = g + 306
+  local y = floor((10000*g + 14780)/3652425)
+  local d = g - dayfromyear(y)
+  if d < 0 then y = y - 1; d = g - dayfromyear(y) end
+  local mi = floor((100*d + 52)/3060)
+  return (floor((mi + 2)/12) + y), mod(mi + 2,12), (d - floor((mi*306 + 5)/10) + 1)
+end
+--[[ for floats or int32 Lua Number data type
+local function breakdaynum2(g)
+  local g, n = g + 306;
+  local n400 = floor(g/DI400Y);n = mod(g,DI400Y);
+  local n100 = floor(n/DI100Y);n = mod(n,DI100Y);
+  local n004 = floor(n/DI4Y);   n = mod(n,DI4Y);
+  local n001 = floor(n/365);   n = mod(n,365);
+  local y = (n400*400) + (n100*100) + (n004*4) + n001  - ((n001 == 4 or n100 == 4) and 1 or 0)
+  local d = g - dayfromyear(y)
+  local mi = floor((100*d + 52)/3060)
+  return (floor((mi + 2)/12) + y), mod(mi + 2,12), (d - floor((mi*306 + 5)/10) + 1)
+end
+]]
+-- day fraction from time
+local function makedayfrc(h,r,s,t)
+  return ((h*60 + r)*60 + s)*TICKSPERSEC + t
+end
+-- time from day fraction
+local function breakdayfrc(df)
+  return
+	mod(floor(df/TICKSPERHOUR),HOURPERDAY),
+	mod(floor(df/TICKSPERMIN ),MINPERHOUR),
+	mod(floor(df/TICKSPERSEC ),SECPERMIN),
+	mod(df,TICKSPERSEC)
+end
+-- weekday sunday = 0, monday = 1 ...
+local function weekday(dn) return mod(dn + 1, 7) end
+-- yearday 0 based ...
+local function yearday(dn)
+   return dn - dayfromyear((breakdaynum(dn))-1)
+end
+-- parse v as a month
+local function getmontharg(v)
+  local m = tonumber(v);
+  return (m and fix(m - 1)) or inlist(tostring(v) or "", sl_months, 2)
+end
+-- get daynum of isoweek one of year y
+local function isow1(y)
+  local f = makedaynum(y, 0, 4) -- get the date for the 4-Jan of year `y`
+  local d = weekday(f)
+  d = d == 0 and 7 or d -- get the ISO day number, 1 == Monday, 7 == Sunday
+  return f + (1 - d)
+end
+local function isowy(dn)
+  local w1;
+  local y = (breakdaynum(dn))
+  if dn >= makedaynum(y, 11, 29) then
+	w1 = isow1(y + 1);
+	if dn < w1 then
+	  w1 = isow1(y);
+	else
+		y = y + 1;
+	end
+  else
+	w1 = isow1(y);
+	if dn < w1 then
+	  w1 = isow1(y-1)
+	  y = y - 1
+	end
+  end
+  return floor((dn-w1)/7)+1, y
+end
+local function isoy(dn)
+  local y = (breakdaynum(dn))
+  return y + (((dn >= makedaynum(y, 11, 29)) and (dn >= isow1(y + 1))) and 1 or (dn < isow1(y) and -1 or 0))
+end
+local function makedaynum_isoywd(y,w,d)
+  return isow1(y) + 7*w + d - 8 -- simplified: isow1(y) + ((w-1)*7) + (d-1)
+end
+--[[ THE DATE MODULE ]]--
+local fmtstr  = "%x %X";
+--#if not DATE_OBJECT_AFX then
+local date = {}
+setmetatable(date, date)
+-- Version:  VMMMRRRR; V-Major, M-Minor, R-Revision;  e.g. 5.45.321 == 50450321
+date.version = 20010001 -- 2.1.1
+--#end -- not DATE_OBJECT_AFX
+--[[ THE DATE OBJECT ]]--
+local dobj = {}
+dobj.__index = dobj
+dobj.__metatable = dobj
+-- shout invalid arg
+local function date_error_arg() return error("invalid argument(s)",0) end
+-- create new date object
+local function date_new(dn, df)
+  return setmetatable({daynum=dn, dayfrc=df}, dobj)
+end
+
+--#if not NO_LOCAL_TIME_SUPPORT then
+-- magic year table
+local date_epoch, yt;
+local function getequivyear(y)
+  assert(not yt)
+  yt = {}
+  local de = date_epoch:copy()
+  local dw, dy
+  for _ = 0, 3000 do
+	de:setyear(de:getyear() + 1, 1, 1)
+	dy = de:getyear()
+	dw = de:getweekday() * (isleapyear(dy) and  -1 or 1)
+	if not yt[dw] then yt[dw] = dy end  --print(de)
+	if yt[1] and yt[2] and yt[3] and yt[4] and yt[5] and yt[6] and yt[7] and yt[-1] and yt[-2] and yt[-3] and yt[-4] and yt[-5] and yt[-6] and yt[-7] then
+	  getequivyear = function(y)  return yt[ (weekday(makedaynum(y, 0, 1)) + 1) * (isleapyear(y) and  -1 or 1) ]  end
+	  return getequivyear(y)
+	end
+  end
+end
+-- TimeValue from date and time
+local function totv(y,m,d,h,r,s)
+  return (makedaynum(y, m, d) - DATE_EPOCH) * SECPERDAY  + ((h*60 + r)*60 + s)
+end
+-- TimeValue from TimeTable
+local function tmtotv(tm)
+  return tm and totv(tm.year, tm.month - 1, tm.day, tm.hour, tm.min, tm.sec)
+end
+-- Returns the bias in seconds of utc time daynum and dayfrc
+local function getbiasutc2(self)
+  local y,m,d = breakdaynum(self.daynum)
+  local h,r,s = breakdayfrc(self.dayfrc)
+  local tvu = totv(y,m,d,h,r,s) -- get the utc TimeValue of date and time
+  local tml = osdate("*t", tvu) -- get the local TimeTable of tvu
+  if (not tml) or (tml.year > (y+1) or tml.year < (y-1)) then -- failed try the magic
+	y = getequivyear(y)
+	tvu = totv(y,m,d,h,r,s)
+	tml = osdate("*t", tvu)
+  end
+  local tvl = tmtotv(tml)
+  if tvu and tvl then
+	return tvu - tvl, tvu, tvl
+  else
+	return error("failed to get bias from utc time")
+  end
+end
+-- Returns the bias in seconds of local time daynum and dayfrc
+local function getbiasloc2(daynum, dayfrc)
+  local tvu
+  -- extract date and time
+  local y,m,d = breakdaynum(daynum)
+  local h,r,s = breakdayfrc(dayfrc)
+  -- get equivalent TimeTable
+  local tml = {year=y, month=m+1, day=d, hour=h, min=r, sec=s}
+  -- get equivalent TimeValue
+  local tvl = tmtotv(tml)
+
+  local function chkutc()
+	tml.isdst =  nil; local tvug = ostime(tml) if tvug and (tvl == tmtotv(osdate("*t", tvug))) then tvu = tvug return end
+	tml.isdst = true; local tvud = ostime(tml) if tvud and (tvl == tmtotv(osdate("*t", tvud))) then tvu = tvud return end
+	tvu = tvud or tvug
+  end
+  chkutc()
+  if not tvu then
+	tml.year = getequivyear(y)
+	tvl = tmtotv(tml)
+	chkutc()
+  end
+  return ((tvu and tvl) and (tvu - tvl)) or error("failed to get bias from local time"), tvu, tvl
+end
+--#end -- not NO_LOCAL_TIME_SUPPORT
+
+--#if not DATE_OBJECT_AFX then
+-- the date parser
+local strwalker = {} -- ^Lua regular expression is not as powerful as Perl$
+strwalker.__index = strwalker
+local function newstrwalker(s)return setmetatable({s=s, i=1, e=1, c=len(s)}, strwalker) end
+function strwalker:aimchr() return "\n" .. self.s .. "\n" .. rep(".",self.e-1) .. "^" end
+function strwalker:finish() return self.i > self.c  end
+function strwalker:back()  self.i = self.e return self  end
+function strwalker:restart() self.i, self.e = 1, 1 return self end
+function strwalker:match(s)  return (find(self.s, s, self.i)) end
+function strwalker:__call(s, f)-- print("strwalker:__call "..s..self:aimchr())
+  local is, ie; is, ie, self[1], self[2], self[3], self[4], self[5] = find(self.s, s, self.i)
+  if is then self.e, self.i = self.i, 1+ie; if f then f(unpack(self)) end return self end
+end
+ local function date_parse(str)
+  local y,m,d, h,r,s,  z,  w,u, j,  e,  x,c,  dn,df
+  local sw = newstrwalker(gsub(gsub(str, "(%b())", ""),"^(%s*)","")) -- remove comment, trim leading space
+  --local function error_out() print(y,m,d,h,r,s) end
+  local function error_dup(q) --[[error_out()]] error("duplicate value: " .. (q or "") .. sw:aimchr()) end
+  local function error_syn(q) --[[error_out()]] error("syntax error: " .. (q or "") .. sw:aimchr()) end
+  local function error_inv(q) --[[error_out()]] error("invalid date: " .. (q or "") .. sw:aimchr()) end
+  local function sety(q) y = y and error_dup() or tonumber(q); end
+  local function setm(q) m = (m or w or j) and error_dup(m or w or j) or tonumber(q) end
+  local function setd(q) d = d and error_dup() or tonumber(q) end
+  local function seth(q) h = h and error_dup() or tonumber(q) end
+  local function setr(q) r = r and error_dup() or tonumber(q) end
+  local function sets(q) s = s and error_dup() or tonumber(q) end
+  local function adds(q) s = s + tonumber(q) end
+  local function setj(q) j = (m or w or j) and error_dup() or tonumber(q); end
+  local function setz(q) z = (z ~= 0 and z) and error_dup() or q end
+  local function setzn(zs,zn) zn = tonumber(zn); setz( ((zn<24) and (zn*60) or (mod(zn,100) + floor(zn/100) * 60))*( zs=='+' and -1 or 1) ) end
+  local function setzc(zs,zh,zm) setz( ((tonumber(zh)*60) + tonumber(zm))*( zs=='+' and -1 or 1) ) end
+
+  if not (sw("^(%d%d%d%d)",sety) and (sw("^(%-?)(%d%d)%1(%d%d)",function(_,a,b) setm(tonumber(a)); setd(tonumber(b)) end) or sw("^(%-?)[Ww](%d%d)%1(%d?)",function(_,a,b) w, u = tonumber(a), tonumber(b or 1) end) or sw("^%-?(%d%d%d)",setj) or sw("^%-?(%d%d)",function(a) setm(a);setd(1) end))
+  and ((sw("^%s*[Tt]?(%d%d):?",seth) and sw("^(%d%d):?",setr) and sw("^(%d%d)",sets) and sw("^(%.%d+)",adds))
+	or sw:finish() or (sw"^%s*$" or sw"^%s*[Zz]%s*$" or sw("^%s-([%+%-])(%d%d):?(%d%d)%s*$",setzc) or sw("^%s*([%+%-])(%d%d)%s*$",setzn))
+	)  )
+  then --print(y,m,d,h,r,s,z,w,u,j)
+  sw:restart(); y,m,d,h,r,s,z,w,u,j = nil,nil,nil,nil,nil,nil,nil,nil,nil,nil
+	repeat -- print(sw:aimchr())
+	  if sw("^[tT:]?%s*(%d%d?):",seth) then --print("$Time")
+		_ = sw("^%s*(%d%d?)",setr) and sw("^%s*:%s*(%d%d?)",sets) and sw("^(%.%d+)",adds)
+	  elseif sw("^(%d+)[/\\%s,-]?%s*") then --print("$Digits")
+		x, c = tonumber(sw[1]), len(sw[1])
+		if (x >= 70) or (m and d and (not y)) or (c > 3) then
+		  sety( x + ((x >= 100 or c>3)and 0 or 1900) )
+		else
+		  if m then setd(x) else m = x end
+		end
+	  elseif sw("^(%a+)[/\\%s,-]?%s*") then --print("$Words")
+		x = sw[1]
+		if inlist(x, sl_months,   2, sw) then
+		  if m and (not d) and (not y) then d, m = m, false end
+		  setm(mod(sw[0],12)+1)
+		elseif inlist(x, sl_timezone, 2, sw) then
+		  c = fix(sw[0]) -- ignore gmt and utc
+		  if c ~= 0 then setz(c, x) end
+		elseif not inlist(x, sl_weekdays, 2, sw) then
+		  sw:back()
+		  -- am pm bce ad ce bc
+		  if sw("^([bB])%s*(%.?)%s*[Cc]%s*(%2)%s*[Ee]%s*(%2)%s*") or sw("^([bB])%s*(%.?)%s*[Cc]%s*(%2)%s*") then
+			e = e and error_dup() or -1
+		  elseif sw("^([aA])%s*(%.?)%s*[Dd]%s*(%2)%s*") or sw("^([cC])%s*(%.?)%s*[Ee]%s*(%2)%s*") then
+			e = e and error_dup() or 1
+		  elseif sw("^([PApa])%s*(%.?)%s*[Mm]?%s*(%2)%s*") then
+			x = lwr(sw[1]) -- there should be hour and it must be correct
+			if (not h) or (h > 12) or (h < 0) then return error_inv() end
+			if x == 'a' and h == 12 then h = 0 end -- am
+			if x == 'p' and h ~= 12 then h = h + 12 end -- pm
+		  else error_syn() end
+		end
+	  elseif not(sw("^([+-])(%d%d?):(%d%d)",setzc) or sw("^([+-])(%d+)",setzn) or sw("^[Zz]%s*$")) then -- sw{"([+-])",{"(%d%d?):(%d%d)","(%d+)"}}
+		error_syn("?")
+	  end
+	sw("^%s*")  until sw:finish()
+  --else print("$Iso(Date|Time|Zone)")
+  end
+  -- if date is given, it must be complete year, month & day
+  if (not y and not h) or ((m and not d) or (d and not m)) or ((m and w) or (m and j) or (j and w)) then return error_inv("!") end
+  -- fix month
+  if m then m = m - 1 end
+  -- fix year if we are on BCE
+  if e and e < 0 and y > 0 then y = 1 - y end
+  --  create date object
+  dn = (y and ((w and makedaynum_isoywd(y,w,u)) or (j and makedaynum(y, 0, j)) or makedaynum(y, m, d))) or DAYNUM_DEF
+  df = makedayfrc(h or 0, r or 0, s or 0, 0) + ((z or 0)*TICKSPERMIN)
+  --print("Zone",h,r,s,z,m,d,y,df)
+  return date_new(dn, df) -- no need to :normalize();
+ end
+local function date_fromtable(v)
+  local y, m, d = fix(v.year), getmontharg(v.month), fix(v.day)
+  local h, r, s, t = tonumber(v.hour), tonumber(v.min), tonumber(v.sec), tonumber(v.ticks)
+  -- atleast there is time or complete date
+  if (y or m or d) and (not(y and m and d)) then return error("incomplete table")  end
+  return (y or h or r or s or t) and date_new(y and makedaynum(y, m, d) or DAYNUM_DEF, makedayfrc(h or 0, r or 0, s or 0, t or 0))
+end
+local tmap = {
+  ['number'] = function(v) return date_epoch:copy():addseconds(v) end,
+  ['string'] = function(v) return date_parse(v) end,
+  ['boolean']= function(v) return date_fromtable(osdate(v and "!*t" or "*t")) end,
+  ['table']  = function(v) local ref = getmetatable(v) == dobj; return ref and v or date_fromtable(v), ref end
+}
+local function date_getdobj(v)
+  local o, r = (tmap[type(v)] or fnil)(v);
+  return (o and o:normalize() or error"invalid date time value"), r -- if r is true then o is a reference to a date obj
+end
+--#end -- not DATE_OBJECT_AFX
+local function date_from(arg1, arg2, arg3, arg4, arg5, arg6, arg7)
+  local y, m, d = fix(arg1), getmontharg(arg2), fix(arg3)
+  local h, r, s, t = tonumber(arg4 or 0), tonumber(arg5 or 0), tonumber(arg6 or 0), tonumber(arg7 or 0)
+  if y and m and d and h and r and s and t then
+	return date_new(makedaynum(y, m, d), makedayfrc(h, r, s, t)):normalize()
+  else
+	return date_error_arg()
+  end
+end
+
+--[[ THE DATE OBJECT METHODS ]]--
+function dobj:normalize()
+  local dn, df = fix(self.daynum), self.dayfrc
+  self.daynum, self.dayfrc = dn + floor(df/TICKSPERDAY), mod(df, TICKSPERDAY)
+  return (dn >= DAYNUM_MIN and dn <= DAYNUM_MAX) and self or error("date beyond imposed limits:"..self)
+end
+
+function dobj:getdate()  local y, m, d = breakdaynum(self.daynum) return y, m+1, d end
+function dobj:gettime()  return breakdayfrc(self.dayfrc) end
+
+function dobj:getclockhour() local h = self:gethours() return h>12 and mod(h,12) or (h==0 and 12 or h) end
+
+function dobj:getyearday() return yearday(self.daynum) + 1 end
+function dobj:getweekday() return weekday(self.daynum) + 1 end   -- in lua weekday is sunday = 1, monday = 2 ...
+
+function dobj:getyear()   local r,_,_ = breakdaynum(self.daynum)  return r end
+function dobj:getmonth() local _,r,_ = breakdaynum(self.daynum)  return r+1 end-- in lua month is 1 base
+function dobj:getday()   local _,_,r = breakdaynum(self.daynum)  return r end
+function dobj:gethours()  return mod(floor(self.dayfrc/TICKSPERHOUR),HOURPERDAY) end
+function dobj:getminutes()  return mod(floor(self.dayfrc/TICKSPERMIN), MINPERHOUR) end
+function dobj:getseconds()  return mod(floor(self.dayfrc/TICKSPERSEC ),SECPERMIN)  end
+function dobj:getfracsec()  return mod(floor(self.dayfrc/TICKSPERSEC ),SECPERMIN)+(mod(self.dayfrc,TICKSPERSEC)/TICKSPERSEC) end
+function dobj:getticks(u)  local x = mod(self.dayfrc,TICKSPERSEC) return u and ((x*u)/TICKSPERSEC) or x  end
+
+function dobj:getweeknumber(wdb)
+  local wd, yd = weekday(self.daynum), yearday(self.daynum)
+  if wdb then
+	wdb = tonumber(wdb)
+	if wdb then
+	  wd = mod(wd-(wdb-1),7)-- shift the week day base
+	else
+	  return date_error_arg()
+	end
+  end
+  return (yd < wd and 0) or (floor(yd/7) + ((mod(yd, 7)>=wd) and 1 or 0))
+end
+
+function dobj:getisoweekday() return mod(weekday(self.daynum)-1,7)+1 end   -- sunday = 7, monday = 1 ...
+function dobj:getisoweeknumber() return (isowy(self.daynum)) end
+function dobj:getisoyear() return isoy(self.daynum)  end
+function dobj:getisodate()
+  local w, y = isowy(self.daynum)
+  return y, w, self:getisoweekday()
+end
+function dobj:setisoyear(y, w, d)
+  local cy, cw, cd = self:getisodate()
+  if y then cy = fix(tonumber(y))end
+  if w then cw = fix(tonumber(w))end
+  if d then cd = fix(tonumber(d))end
+  if cy and cw and cd then
+	self.daynum = makedaynum_isoywd(cy, cw, cd)
+	return self:normalize()
+  else
+	return date_error_arg()
+  end
+end
+
+function dobj:setisoweekday(d)    return self:setisoyear(nil, nil, d) end
+function dobj:setisoweeknumber(w,d)  return self:setisoyear(nil, w, d)  end
+
+function dobj:setyear(y, m, d)
+  local cy, cm, cd = breakdaynum(self.daynum)
+  if y then cy = fix(tonumber(y))end
+  if m then cm = getmontharg(m)  end
+  if d then cd = fix(tonumber(d))end
+  if cy and cm and cd then
+	self.daynum  = makedaynum(cy, cm, cd)
+	return self:normalize()
+  else
+	return date_error_arg()
+  end
+end
+
+function dobj:setmonth(m, d)return self:setyear(nil, m, d) end
+function dobj:setday(d)    return self:setyear(nil, nil, d) end
+
+function dobj:sethours(h, m, s, t)
+  local ch,cm,cs,ck = breakdayfrc(self.dayfrc)
+  ch, cm, cs, ck = tonumber(h or ch), tonumber(m or cm), tonumber(s or cs), tonumber(t or ck)
+  if ch and cm and cs and ck then
+	self.dayfrc = makedayfrc(ch, cm, cs, ck)
+	return self:normalize()
+  else
+	return date_error_arg()
+  end
+end
+
+function dobj:setminutes(m,s,t)  return self:sethours(nil,   m,   s, t) end
+function dobj:setseconds(s, t)  return self:sethours(nil, nil,   s, t) end
+function dobj:setticks(t)    return self:sethours(nil, nil, nil, t) end
+
+function dobj:spanticks()  return (self.daynum*TICKSPERDAY + self.dayfrc) end
+function dobj:spanseconds()  return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERSEC  end
+function dobj:spanminutes()  return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERMIN  end
+function dobj:spanhours()  return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERHOUR end
+function dobj:spandays()  return (self.daynum*TICKSPERDAY + self.dayfrc)/TICKSPERDAY  end
+
+function dobj:addyears(y, m, d)
+  local cy, cm, cd = breakdaynum(self.daynum)
+  if y then y = fix(tonumber(y))else y = 0 end
+  if m then m = fix(tonumber(m))else m = 0 end
+  if d then d = fix(tonumber(d))else d = 0 end
+  if y and m and d then
+	self.daynum  = makedaynum(cy+y, cm+m, cd+d)
+	return self:normalize()
+  else
+	return date_error_arg()
+  end
+end
+
+function dobj:addmonths(m, d)
+  return self:addyears(nil, m, d)
+end
+
+local function dobj_adddayfrc(self,n,pt,pd)
+  n = tonumber(n)
+  if n then
+	local x = floor(n/pd);
+	self.daynum = self.daynum + x;
+	self.dayfrc = self.dayfrc + (n-x*pd)*pt;
+	return self:normalize()
+  else
+	return date_error_arg()
+  end
+end
+function dobj:adddays(n)  return dobj_adddayfrc(self,n,TICKSPERDAY,1) end
+function dobj:addhours(n)  return dobj_adddayfrc(self,n,TICKSPERHOUR,HOURPERDAY) end
+function dobj:addminutes(n)  return dobj_adddayfrc(self,n,TICKSPERMIN,MINPERDAY)  end
+function dobj:addseconds(n)  return dobj_adddayfrc(self,n,TICKSPERSEC,SECPERDAY)  end
+function dobj:addticks(n)  return dobj_adddayfrc(self,n,1,TICKSPERDAY) end
+local tvspec = {
+  -- Abbreviated weekday name (Sun)
+  ['%a']=function(self) return sl_weekdays[weekday(self.daynum) + 7] end,
+  -- Full weekday name (Sunday)
+  ['%A']=function(self) return sl_weekdays[weekday(self.daynum)] end,
+  -- Abbreviated month name (Dec)
+  ['%b']=function(self) return sl_months[self:getmonth() - 1 + 12] end,
+  -- Full month name (December)
+  ['%B']=function(self) return sl_months[self:getmonth() - 1] end,
+  -- Year/100 (19, 20, 30)
+  ['%C']=function(self) return fmt("%.2d", fix(self:getyear()/100)) end,
+  -- The day of the month as a number (range 1 - 31)
+  ['%d']=function(self) return fmt("%.2d", self:getday())  end,
+  -- year for ISO 8601 week, from 00 (79)
+  ['%g']=function(self) return fmt("%.2d", mod(self:getisoyear() ,100)) end,
+  -- year for ISO 8601 week, from 0000 (1979)
+  ['%G']=function(self) return fmt("%.4d", self:getisoyear()) end,
+  -- same as %b
+  ['%h']=function(self) return self:fmt0("%b") end,
+  -- hour of the 24-hour day, from 00 (06)
+  ['%H']=function(self) return fmt("%.2d", self:gethours()) end,
+  -- The  hour as a number using a 12-hour clock (01 - 12)
+  ['%I']=function(self) return fmt("%.2d", self:getclockhour()) end,
+  -- The day of the year as a number (001 - 366)
+  ['%j']=function(self) return fmt("%.3d", self:getyearday())  end,
+  -- Month of the year, from 01 to 12
+  ['%m']=function(self) return fmt("%.2d", self:getmonth())  end,
+  -- Minutes after the hour 55
+  ['%M']=function(self) return fmt("%.2d", self:getminutes())end,
+  -- AM/PM indicator (AM)
+  ['%p']=function(self) return sl_meridian[self:gethours() > 11 and 1 or -1] end, --AM/PM indicator (AM)
+  -- The second as a number (59, 20 , 01)
+  ['%S']=function(self) return fmt("%.2d", self:getseconds())  end,
+  -- ISO 8601 day of the week, to 7 for Sunday (7, 1)
+  ['%u']=function(self) return self:getisoweekday() end,
+  -- Sunday week of the year, from 00 (48)
+  ['%U']=function(self) return fmt("%.2d", self:getweeknumber()) end,
+  -- ISO 8601 week of the year, from 01 (48)
+  ['%V']=function(self) return fmt("%.2d", self:getisoweeknumber()) end,
+  -- The day of the week as a decimal, Sunday being 0
+  ['%w']=function(self) return self:getweekday() - 1 end,
+  -- Monday week of the year, from 00 (48)
+  ['%W']=function(self) return fmt("%.2d", self:getweeknumber(2)) end,
+  -- The year as a number without a century (range 00 to 99)
+  ['%y']=function(self) return fmt("%.2d", mod(self:getyear() ,100)) end,
+  -- Year with century (2000, 1914, 0325, 0001)
+  ['%Y']=function(self) return fmt("%.4d", self:getyear()) end,
+  -- Time zone offset, the date object is assumed local time (+1000, -0230)
+  ['%z']=function(self) local b = -self:getbias(); local x = abs(b); return fmt("%s%.4d", b < 0 and "-" or "+", fix(x/60)*100 + floor(mod(x,60))) end,
+  -- Time zone name, the date object is assumed local time
+  ['%Z']=function(self) return self:gettzname() end,
+  -- Misc --
+  -- Year, if year is in BCE, prints the BCE Year representation, otherwise result is similar to "%Y" (1 BCE, 40 BCE)
+  ['%\b']=function(self) local x = self:getyear() return fmt("%.4d%s", x>0 and x or (-x+1), x>0 and "" or " BCE") end,
+  -- Seconds including fraction (59.998, 01.123)
+  ['%\f']=function(self) local x = self:getfracsec() return fmt("%s%.9f",x >= 10 and "" or "0", x) end,
+  -- percent character %
+  ['%%']=function(self) return "%" end,
+  -- Group Spec --
+  -- 12-hour time, from 01:00:00 AM (06:55:15 AM); same as "%I:%M:%S %p"
+  ['%r']=function(self) return self:fmt0("%I:%M:%S %p") end,
+  -- hour:minute, from 01:00 (06:55); same as "%I:%M"
+  ['%R']=function(self) return self:fmt0("%I:%M")  end,
+  -- 24-hour time, from 00:00:00 (06:55:15); same as "%H:%M:%S"
+  ['%T']=function(self) return self:fmt0("%H:%M:%S") end,
+  -- month/day/year from 01/01/00 (12/02/79); same as "%m/%d/%y"
+  ['%D']=function(self) return self:fmt0("%m/%d/%y") end,
+  -- year-month-day (1979-12-02); same as "%Y-%m-%d"
+  ['%F']=function(self) return self:fmt0("%Y-%m-%d") end,
+  -- The preferred date and time representation;  same as "%x %X"
+  ['%c']=function(self) return self:fmt0("%x %X") end,
+  -- The preferred date representation, same as "%a %b %d %\b"
+  ['%x']=function(self) return self:fmt0("%a %b %d %\b") end,
+  -- The preferred time representation, same as "%H:%M:%\f"
+  ['%X']=function(self) return self:fmt0("%H:%M:%\f") end,
+  -- GroupSpec --
+  -- Iso format, same as "%Y-%m-%dT%T"
+  ['${iso}'] = function(self) return self:fmt0("%Y-%m-%dT%T") end,
+  -- http format, same as "%a, %d %b %Y %T GMT"
+  ['${http}'] = function(self) return self:fmt0("%a, %d %b %Y %T GMT") end,
+  -- ctime format, same as "%a %b %d %T GMT %Y"
+  ['${ctime}'] = function(self) return self:fmt0("%a %b %d %T GMT %Y") end,
+  -- RFC850 format, same as "%A, %d-%b-%y %T GMT"
+  ['${rfc850}'] = function(self) return self:fmt0("%A, %d-%b-%y %T GMT") end,
+  -- RFC1123 format, same as "%a, %d %b %Y %T GMT"
+  ['${rfc1123}'] = function(self) return self:fmt0("%a, %d %b %Y %T GMT") end,
+  -- asctime format, same as "%a %b %d %T %Y"
+  ['${asctime}'] = function(self) return self:fmt0("%a %b %d %T %Y") end,
+}
+function dobj:fmt0(str) return (gsub(str, "%%[%a%%\b\f]", function(x) local f = tvspec[x];return (f and f(self)) or x end)) end
+function dobj:fmt(str)
+  str = str or self.fmtstr or fmtstr
+  return self:fmt0((gmatch(str, "${%w+}")) and (gsub(str, "${%w+}", function(x)local f=tvspec[x];return (f and f(self)) or x end)) or str)
+end
+
+function dobj.__lt(a, b) if (a.daynum == b.daynum) then return (a.dayfrc < b.dayfrc) else return (a.daynum < b.daynum) end end
+function dobj.__le(a, b) if (a.daynum == b.daynum) then return (a.dayfrc <= b.dayfrc) else return (a.daynum <= b.daynum) end end
+function dobj.__eq(a, b)return (a.daynum == b.daynum) and (a.dayfrc == b.dayfrc) end
+function dobj.__sub(a,b)
+  local d1, d2 = date_getdobj(a), date_getdobj(b)
+  local d0 = d1 and d2 and date_new(d1.daynum - d2.daynum, d1.dayfrc - d2.dayfrc)
+  return d0 and d0:normalize()
+end
+function dobj.__add(a,b)
+  local d1, d2 = date_getdobj(a), date_getdobj(b)
+  local d0 = d1 and d2 and date_new(d1.daynum + d2.daynum, d1.dayfrc + d2.dayfrc)
+  return d0 and d0:normalize()
+end
+function dobj.__concat(a, b) return tostring(a) .. tostring(b) end
+function dobj:__tostring() return self:fmt() end
+
+function dobj:copy() return date_new(self.daynum, self.dayfrc) end
+
+--[[ THE LOCAL DATE OBJECT METHODS ]]--
+function dobj:tolocal()
+  local dn,df = self.daynum, self.dayfrc
+  local bias  = getbiasutc2(self)
+  if bias then
+	-- utc = local + bias; local = utc - bias
+	self.daynum = dn
+	self.dayfrc = df - bias*TICKSPERSEC
+	return self:normalize()
+  else
+	return nil
+  end
+end
+
+function dobj:toutc()
+  local dn,df = self.daynum, self.dayfrc
+  local bias  = getbiasloc2(dn, df)
+  if bias then
+	-- utc = local + bias;
+	self.daynum = dn
+	self.dayfrc = df + bias*TICKSPERSEC
+	return self:normalize()
+  else
+	return nil
+  end
+end
+
+function dobj:getbias()  return (getbiasloc2(self.daynum, self.dayfrc))/SECPERMIN end
+
+function dobj:gettzname()
+  local _, tvu, _ = getbiasloc2(self.daynum, self.dayfrc)
+  return tvu and osdate("%Z",tvu) or ""
+end
+
+--#if not DATE_OBJECT_AFX then
+function date.time(h, r, s, t)
+  h, r, s, t = tonumber(h or 0), tonumber(r or 0), tonumber(s or 0), tonumber(t or 0)
+  if h and r and s and t then
+	 return date_new(DAYNUM_DEF, makedayfrc(h, r, s, t))
+  else
+	return date_error_arg()
+  end
+end
+
+function date:__call(arg1, args)
+  local arg_count = select("#", args) + (arg1 == nil and 0 or 1)
+  if arg_count  > 1 then return (date_from(arg1, args))
+  elseif arg_count == 0 then return (date_getdobj(false))
+  else local o, r = date_getdobj(arg1);  return r and o:copy() or o end
+end
+
+date.diff = dobj.__sub
+
+function date.isleapyear(v)
+  local y = fix(v);
+  if not y then
+	y = date_getdobj(v)
+	y = y and y:getyear()
+  end
+  return isleapyear(y+0)
+end
+
+function date.epoch() return date_epoch:copy()  end
+
+function date.isodate(y,w,d) return date_new(makedaynum_isoywd(y + 0, w and (w+0) or 1, d and (d+0) or 1), 0)  end
+
+-- Internal functions
+function date.fmt(str) if str then fmtstr = str end; return fmtstr end
+function date.daynummin(n)  DAYNUM_MIN = (n and n < DAYNUM_MAX) and n or DAYNUM_MIN  return n and DAYNUM_MIN or date_new(DAYNUM_MIN, 0):normalize()end
+function date.daynummax(n)  DAYNUM_MAX = (n and n > DAYNUM_MIN) and n or DAYNUM_MAX return n and DAYNUM_MAX or date_new(DAYNUM_MAX, 0):normalize()end
+function date.ticks(t) if t then setticks(t) end return TICKSPERSEC  end
+--#end -- not DATE_OBJECT_AFX
+
+local tm = osdate("!*t", 0);
+if tm then
+  date_epoch = date_new(makedaynum(tm.year, tm.month - 1, tm.day), makedayfrc(tm.hour, tm.min, tm.sec, 0))
+  -- the distance from our epoch to os epoch in daynum
+  DATE_EPOCH = date_epoch and date_epoch:spandays()
+else -- error will be raise only if called!
+  date_epoch = setmetatable({},{__index = function() error("failed to get the epoch date") end})
+end
+
+--#if not DATE_OBJECT_AFX then
+return date
+--#else
+--$return date_from
+--#end
+
diff --git a/src/Rust/benches/date.rs b/src/Rust/benches/date.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7898cacdea697ec71d681a7c1d87b44db769f999
--- /dev/null
+++ b/src/Rust/benches/date.rs
@@ -0,0 +1,21 @@
+use criterion::{criterion_group, criterion_main, Criterion};
+use vvs_parser::prelude::{ast::*, parser::*};
+
+const DATE_SOURCE: &str = include_str!("./date.lua");
+
+fn parse(criterion: &mut Criterion) {
+    criterion.bench_function("get ast from parsed date", move |b| b.iter(|| parse_lua_tree(DATE_SOURCE)));
+}
+
+fn range(criterion: &mut Criterion) {
+    let ast = parse_lua_tree(DATE_SOURCE).unwrap();
+    criterion.bench_function("get range of ast of date", move |b| b.iter(|| ast.nodes().range()));
+}
+
+criterion_group! {
+    name = benches;
+    config = Criterion::default().sample_size(20);
+    targets = parse, range
+}
+
+criterion_main!(benches);
diff --git a/src/Rust/benches/t.lua b/src/Rust/benches/t.lua
new file mode 100644
index 0000000000000000000000000000000000000000..ced68d9c947a5787cdb4f83eaee81af7ebdd6d7f
--- /dev/null
+++ b/src/Rust/benches/t.lua
@@ -0,0 +1,1135 @@
+-- Sourced from https://github.com/osyrisrblx/t
+
+-- The MPL 2.0 license of Full Moon does not apply to this file.
+-- The license of this file is as follows:
+
+-- MIT License
+
+-- Copyright (c) 2018 Osyris
+--
+-- Permission is hereby granted, free of charge, to any person obtaining a copy
+-- of this software and associated documentation files (the "Software"), to deal
+-- in the Software without restriction, including without limitation the rights
+-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+-- copies of the Software, and to permit persons to whom the Software is
+-- furnished to do so, subject to the following conditions:
+--
+-- The above copyright notice and this permission notice shall be included in all
+-- copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+-- SOFTWARE.
+
+-- t: a runtime typechecker for Roblox
+
+-- regular lua compatibility
+local typeof = typeof or type
+
+local function primitive(typeName)
+	return function(value)
+		local valueType = typeof(value)
+		if valueType == typeName then
+			return true
+		else
+			return false, string.format("%s expected, got %s", typeName, valueType)
+		end
+	end
+end
+
+local t = {}
+
+--[[**
+	matches any type except nil
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+function t.any(value)
+	if value ~= nil then
+		return true
+	else
+		return false, "any expected, got nil"
+	end
+end
+
+--Lua primitives
+
+--[[**
+	ensures Lua primitive boolean type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.boolean = primitive("boolean")
+
+--[[**
+	ensures Lua primitive thread type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.thread = primitive("thread")
+
+--[[**
+	ensures Lua primitive callback type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.callback = primitive("function")
+
+--[[**
+	ensures Lua primitive none type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.none = primitive("nil")
+
+--[[**
+	ensures Lua primitive string type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.string = primitive("string")
+
+--[[**
+	ensures Lua primitive table type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.table = primitive("table")
+
+--[[**
+	ensures Lua primitive userdata type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.userdata = primitive("userdata")
+
+--[[**
+	ensures value is a number and non-NaN
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+function t.number(value)
+	local valueType = typeof(value)
+	if valueType == "number" then
+		if value == value then
+			return true
+		else
+			return false, "unexpected NaN value"
+		end
+	else
+		return false, string.format("number expected, got %s", valueType)
+	end
+end
+
+--[[**
+	ensures value is NaN
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+function t.nan(value)
+	if value ~= value then
+		return true
+	else
+		return false, "unexpected non-NaN value"
+	end
+end
+
+-- roblox types
+
+--[[**
+	ensures Roblox Axes type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Axes = primitive("Axes")
+
+--[[**
+	ensures Roblox BrickColor type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.BrickColor = primitive("BrickColor")
+
+--[[**
+	ensures Roblox CFrame type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.CFrame = primitive("CFrame")
+
+--[[**
+	ensures Roblox Color3 type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Color3 = primitive("Color3")
+
+--[[**
+	ensures Roblox ColorSequence type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.ColorSequence = primitive("ColorSequence")
+
+--[[**
+	ensures Roblox ColorSequenceKeypoint type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.ColorSequenceKeypoint = primitive("ColorSequenceKeypoint")
+
+--[[**
+	ensures Roblox DockWidgetPluginGuiInfo type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.DockWidgetPluginGuiInfo = primitive("DockWidgetPluginGuiInfo")
+
+--[[**
+	ensures Roblox Faces type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Faces = primitive("Faces")
+
+--[[**
+	ensures Roblox Instance type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Instance = primitive("Instance")
+
+--[[**
+	ensures Roblox NumberRange type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.NumberRange = primitive("NumberRange")
+
+--[[**
+	ensures Roblox NumberSequence type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.NumberSequence = primitive("NumberSequence")
+
+--[[**
+	ensures Roblox NumberSequenceKeypoint type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.NumberSequenceKeypoint = primitive("NumberSequenceKeypoint")
+
+--[[**
+	ensures Roblox PathWaypoint type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.PathWaypoint = primitive("PathWaypoint")
+
+--[[**
+	ensures Roblox PhysicalProperties type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.PhysicalProperties = primitive("PhysicalProperties")
+
+--[[**
+	ensures Roblox Random type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Random = primitive("Random")
+
+--[[**
+	ensures Roblox Ray type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Ray = primitive("Ray")
+
+--[[**
+	ensures Roblox Rect type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Rect = primitive("Rect")
+
+--[[**
+	ensures Roblox Region3 type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Region3 = primitive("Region3")
+
+--[[**
+	ensures Roblox Region3int16 type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Region3int16 = primitive("Region3int16")
+
+--[[**
+	ensures Roblox TweenInfo type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.TweenInfo = primitive("TweenInfo")
+
+--[[**
+	ensures Roblox UDim type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.UDim = primitive("UDim")
+
+--[[**
+	ensures Roblox UDim2 type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.UDim2 = primitive("UDim2")
+
+--[[**
+	ensures Roblox Vector2 type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Vector2 = primitive("Vector2")
+
+--[[**
+	ensures Roblox Vector3 type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Vector3 = primitive("Vector3")
+
+--[[**
+	ensures Roblox Vector3int16 type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Vector3int16 = primitive("Vector3int16")
+
+-- roblox enum types
+
+--[[**
+	ensures Roblox Enum type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.Enum = primitive("Enum")
+
+--[[**
+	ensures Roblox EnumItem type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.EnumItem = primitive("EnumItem")
+
+--[[**
+	ensures Roblox RBXScriptSignal type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.RBXScriptSignal = primitive("RBXScriptSignal")
+
+--[[**
+	ensures Roblox RBXScriptConnection type
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+t.RBXScriptConnection = primitive("RBXScriptConnection")
+
+--[[**
+	ensures value is a given literal value
+
+	@param literal The literal to use
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.literal(args)
+	local size = select("#", args)
+	if size == 1 then
+		local literal = args
+		return function(value)
+			if value ~= literal then
+				return false, string.format("expected %s, got %s", tostring(literal), tostring(value))
+			end
+			return true
+		end
+	else
+		local literals = {}
+		for i = 1, size do
+			local value = select(i, args)
+			literals[i] = t.literal(value)
+		end
+		return t.union(unpack(literals))
+	end
+end
+
+--[[**
+	DEPRECATED
+	Please use t.literal
+**--]]
+t.exactly = t.literal
+
+--[[**
+	Returns a t.union of each key in the table as a t.literal
+
+	@param keyTable The table to get keys from
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+function t.keyOf(keyTable)
+	local keys = {}
+	for key in pairs(keyTable) do
+		keys[#keys + 1] = key
+	end
+	return t.literal(unpack(keys))
+end
+
+--[[**
+	Returns a t.union of each value in the table as a t.literal
+
+	@param valueTable The table to get values from
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+function t.valueOf(valueTable)
+	local values = {}
+	for _, value in pairs(valueTable) do
+		values[#values + 1] = value
+	end
+	return t.literal(unpack(values))
+end
+
+--[[**
+	ensures value is an integer
+
+	@param value The value to check against
+
+	@returns True iff the condition is satisfied, false otherwise
+**--]]
+function t.integer(value)
+	local success, errMsg = t.number(value)
+	if not success then
+		return false, errMsg or ""
+	end
+	if value%1 == 0 then
+		return true
+	else
+		return false, string.format("integer expected, got %s", value)
+	end
+end
+
+--[[**
+	ensures value is a number where min <= value
+
+	@param min The minimum to use
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.numberMin(min)
+	return function(value)
+		local success, errMsg = t.number(value)
+		if not success then
+			return false, errMsg or ""
+		end
+		if value >= min then
+			return true
+		else
+			return false, string.format("number >= %s expected, got %s", min, value)
+		end
+	end
+end
+
+--[[**
+	ensures value is a number where value <= max
+
+	@param max The maximum to use
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.numberMax(max)
+	return function(value)
+		local success, errMsg = t.number(value)
+		if not success then
+			return false, errMsg
+		end
+		if value <= max then
+			return true
+		else
+			return false, string.format("number <= %s expected, got %s", max, value)
+		end
+	end
+end
+
+--[[**
+	ensures value is a number where min < value
+
+	@param min The minimum to use
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.numberMinExclusive(min)
+	return function(value)
+		local success, errMsg = t.number(value)
+		if not success then
+			return false, errMsg or ""
+		end
+		if min < value then
+			return true
+		else
+			return false, string.format("number > %s expected, got %s", min, value)
+		end
+	end
+end
+
+--[[**
+	ensures value is a number where value < max
+
+	@param max The maximum to use
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.numberMaxExclusive(max)
+	return function(value)
+		local success, errMsg = t.number(value)
+		if not success then
+			return false, errMsg or ""
+		end
+		if value < max then
+			return true
+		else
+			return false, string.format("number < %s expected, got %s", max, value)
+		end
+	end
+end
+
+--[[**
+	ensures value is a number where value > 0
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+t.numberPositive = t.numberMinExclusive(0)
+
+--[[**
+	ensures value is a number where value < 0
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+t.numberNegative = t.numberMaxExclusive(0)
+
+--[[**
+	ensures value is a number where min <= value <= max
+
+	@param min The minimum to use
+	@param max The maximum to use
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.numberConstrained(min, max)
+	assert(t.number(min) and t.number(max))
+	local minCheck = t.numberMin(min)
+	local maxCheck = t.numberMax(max)
+	return function(value)
+		local minSuccess, minErrMsg = minCheck(value)
+		if not minSuccess then
+			return false, minErrMsg or ""
+		end
+
+		local maxSuccess, maxErrMsg = maxCheck(value)
+		if not maxSuccess then
+			return false, maxErrMsg or ""
+		end
+
+		return true
+	end
+end
+
+--[[**
+	ensures value is a number where min < value < max
+
+	@param min The minimum to use
+	@param max The maximum to use
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.numberConstrainedExclusive(min, max)
+	assert(t.number(min) and t.number(max))
+	local minCheck = t.numberMinExclusive(min)
+	local maxCheck = t.numberMaxExclusive(max)
+	return function(value)
+		local minSuccess, minErrMsg = minCheck(value)
+		if not minSuccess then
+			return false, minErrMsg or ""
+		end
+
+		local maxSuccess, maxErrMsg = maxCheck(value)
+		if not maxSuccess then
+			return false, maxErrMsg or ""
+		end
+
+		return true
+	end
+end
+
+--[[**
+	ensures value matches string pattern
+
+	@param string pattern to check against
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.match(pattern)
+	assert(t.string(pattern))
+	return function(value)
+		local stringSuccess, stringErrMsg = t.string(value)
+		if not stringSuccess then
+			return false, stringErrMsg
+		end
+
+		if string.match(value, pattern) == nil then
+			return false, string.format("\"%s\" failed to match pattern \"%s\"", value, pattern)
+		end
+
+		return true
+	end
+end
+
+--[[**
+	ensures value is either nil or passes check
+
+	@param check The check to use
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.optional(check)
+	assert(t.callback(check))
+	return function(value)
+		if value == nil then
+			return true
+		end
+		local success, errMsg = check(value)
+		if success then
+			return true
+		else
+			return false, string.format("(optional) %s", errMsg or "")
+		end
+	end
+end
+
+--[[**
+	matches given tuple against tuple type definition
+
+	@param ... The type definition for the tuples
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.tuple(args)
+	local checks = args
+	return function(args)
+		for i = 1, #checks do
+			local success, errMsg = checks[i](args[i])
+			if success == false then
+				return false, string.format("Bad tuple index #%s:\n\t%s", i, errMsg or "")
+			end
+		end
+		return true
+	end
+end
+
+--[[**
+	ensures all keys in given table pass check
+
+	@param check The function to use to check the keys
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.keys(check)
+	assert(t.callback(check))
+	return function(value)
+		local tableSuccess, tableErrMsg = t.table(value)
+		if tableSuccess == false then
+			return false, tableErrMsg or ""
+		end
+
+		for key in pairs(value) do
+			local success, errMsg = check(key)
+			if success == false then
+				return false, string.format("bad key %s:\n\t%s", tostring(key), errMsg or "")
+			end
+		end
+
+		return true
+	end
+end
+
+--[[**
+	ensures all values in given table pass check
+
+	@param check The function to use to check the values
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.values(check)
+	assert(t.callback(check))
+	return function(value)
+		local tableSuccess, tableErrMsg = t.table(value)
+		if tableSuccess == false then
+			return false, tableErrMsg or ""
+		end
+
+		for key, val in pairs(value) do
+			local success, errMsg = check(val)
+			if success == false then
+				return false, string.format("bad value for key %s:\n\t%s", tostring(key), errMsg or "")
+			end
+		end
+
+		return true
+	end
+end
+
+--[[**
+	ensures value is a table and all keys pass keyCheck and all values pass valueCheck
+
+	@param keyCheck The function to use to check the keys
+	@param valueCheck The function to use to check the values
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.map(keyCheck, valueCheck)
+	assert(t.callback(keyCheck), t.callback(valueCheck))
+	local keyChecker = t.keys(keyCheck)
+	local valueChecker = t.values(valueCheck)
+	return function(value)
+		local keySuccess, keyErr = keyChecker(value)
+		if not keySuccess then
+			return false, keyErr or ""
+		end
+
+		local valueSuccess, valueErr = valueChecker(value)
+		if not valueSuccess then
+			return false, valueErr or ""
+		end
+
+		return true
+	end
+end
+
+do
+	local arrayKeysCheck = t.keys(t.integer)
+	--[[**
+		ensures value is an array and all values of the array match check
+
+		@param check The check to compare all values with
+
+		@returns A function that will return true iff the condition is passed
+	**--]]
+	function t.array(check)
+		assert(t.callback(check))
+		local valuesCheck = t.values(check)
+		return function(value)
+			local keySuccess, keyErrMsg = arrayKeysCheck(value)
+			if keySuccess == false then
+				return false, string.format("[array] %s", keyErrMsg or "")
+			end
+
+			-- # is unreliable for sparse arrays
+			-- Count upwards using ipairs to avoid false positives from the behavior of #
+			local arraySize = 0
+
+			for _, _ in ipairs(value) do
+				arraySize = arraySize + 1
+			end
+
+			for key in pairs(value) do
+				if key < 1 or key > arraySize then
+					return false, string.format("[array] key %s must be sequential", tostring(key))
+				end
+			end
+
+			local valueSuccess, valueErrMsg = valuesCheck(value)
+			if not valueSuccess then
+				return false, string.format("[array] %s", valueErrMsg or "")
+			end
+
+			return true
+		end
+	end
+end
+
+do
+	local callbackArray = t.array(t.callback)
+	--[[**
+		creates a union type
+
+		@param ... The checks to union
+
+		@returns A function that will return true iff the condition is passed
+	**--]]
+	function t.union(args)
+		local checks = args
+		assert(callbackArray(checks))
+		return function(value)
+			for _, check in pairs(checks) do
+				if check(value) then
+					return true
+				end
+			end
+			return false, "bad type for union"
+		end
+	end
+
+	--[[**
+		Alias for t.union
+	**--]]
+	t.some = t.union
+
+	--[[**
+		creates an intersection type
+
+		@param ... The checks to intersect
+
+		@returns A function that will return true iff the condition is passed
+	**--]]
+	function t.intersection(args)
+		local checks = args
+		assert(callbackArray(checks))
+		return function(value)
+			for _, check in pairs(checks) do
+				local success, errMsg = check(value)
+				if not success then
+					return false, errMsg or ""
+				end
+			end
+			return true
+		end
+	end
+
+	--[[**
+		Alias for t.intersection
+	**--]]
+	t.every = t.intersection
+end
+
+do
+	local checkInterface = t.map(t.any, t.callback)
+	--[[**
+		ensures value matches given interface definition
+
+		@param checkTable The interface definition
+
+		@returns A function that will return true iff the condition is passed
+	**--]]
+	function t.interface(checkTable)
+		assert(checkInterface(checkTable))
+		return function(value)
+			local tableSuccess, tableErrMsg = t.table(value)
+			if tableSuccess == false then
+				return false, tableErrMsg or ""
+			end
+
+			for key, check in pairs(checkTable) do
+				local success, errMsg = check(value[key])
+				if success == false then
+					return false, string.format("[interface] bad value for %s:\n\t%s", tostring(key), errMsg or "")
+				end
+			end
+			return true
+		end
+	end
+
+	--[[**
+		ensures value matches given interface definition strictly
+
+		@param checkTable The interface definition
+
+		@returns A function that will return true iff the condition is passed
+	**--]]
+	function t.strictInterface(checkTable)
+		assert(checkInterface(checkTable))
+		return function(value)
+			local tableSuccess, tableErrMsg = t.table(value)
+			if tableSuccess == false then
+				return false, tableErrMsg or ""
+			end
+
+			for key, check in pairs(checkTable) do
+				local success, errMsg = check(value[key])
+				if success == false then
+					return false, string.format("[interface] bad value for %s:\n\t%s", tostring(key), errMsg or "")
+				end
+			end
+
+			for key in pairs(value) do
+				if not checkTable[key] then
+					return false, string.format("[interface] unexpected field '%s'", tostring(key))
+				end
+			end
+
+			return true
+		end
+	end
+end
+
+--[[**
+	ensure value is an Instance and it's ClassName matches the given ClassName
+
+	@param className The class name to check for
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.instanceOf(className, childTable)
+	assert(t.string(className))
+
+	local childrenCheck
+	if childTable ~= nil then
+		childrenCheck = t.children(childTable)
+	end
+
+	return function(value)
+		local instanceSuccess, instanceErrMsg = t.Instance(value)
+		if not instanceSuccess then
+			return false, instanceErrMsg or ""
+		end
+
+		if value.ClassName ~= className then
+			return false, string.format("%s expected, got %s", className, value.ClassName)
+		end
+
+		if childrenCheck then
+			local childrenSuccess, childrenErrMsg = childrenCheck(value)
+			if not childrenSuccess then
+				return false, childrenErrMsg
+			end
+		end
+
+		return true
+	end
+end
+t.instance = t.instanceOf
+
+--[[**
+	ensure value is an Instance and it's ClassName matches the given ClassName by an IsA comparison
+
+	@param className The class name to check for
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.instanceIsA(className, childTable)
+	assert(t.string(className))
+
+	local childrenCheck
+	if childTable ~= nil then
+		childrenCheck = t.children(childTable)
+	end
+
+	return function(value)
+		local instanceSuccess, instanceErrMsg = t.Instance(value)
+		if not instanceSuccess then
+			return false, instanceErrMsg or ""
+		end
+
+		if not value:IsA(className) then
+			return false, string.format("%s expected, got %s", className, value.ClassName)
+		end
+
+		if childrenCheck then
+			local childrenSuccess, childrenErrMsg = childrenCheck(value)
+			if not childrenSuccess then
+				return false, childrenErrMsg
+			end
+		end
+
+		return true
+	end
+end
+
+--[[**
+	ensures value is an enum of the correct type
+
+	@param enum The enum to check
+
+	@returns A function that will return true iff the condition is passed
+**--]]
+function t.enum(enum)
+	assert(t.Enum(enum))
+	return function(value)
+		local enumItemSuccess, enumItemErrMsg = t.EnumItem(value)
+		if not enumItemSuccess then
+			return false, enumItemErrMsg
+		end
+
+		if value.EnumType == enum then
+			return true
+		else
+			return false, string.format("enum of %s expected, got enum of %s", tostring(enum), tostring(value.EnumType))
+		end
+	end
+end
+
+do
+	local checkWrap = t.tuple(t.callback, t.callback)
+
+	--[[**
+		wraps a callback in an assert with checkArgs
+
+		@param callback The function to wrap
+		@param checkArgs The functon to use to check arguments in the assert
+
+		@returns A function that first asserts using checkArgs and then calls callback
+	**--]]
+	function t.wrap(callback, checkArgs)
+		assert(checkWrap(callback, checkArgs))
+		return function(args)
+			assert(checkArgs(args))
+			return callback(args)
+		end
+	end
+end
+
+--[[**
+	asserts a given check
+
+	@param check The function to wrap with an assert
+
+	@returns A function that simply wraps the given check in an assert
+**--]]
+function t.strict(check)
+	return function(args)
+		assert(check(args))
+	end
+end
+
+do
+	local checkChildren = t.map(t.string, t.callback)
+
+	--[[**
+		Takes a table where keys are child names and values are functions to check the children against.
+		Pass an instance tree into the function.
+		If at least one child passes each check, the overall check passes.
+
+		Warning! If you pass in a tree with more than one child of the same name, this function will always return false
+
+		@param checkTable The table to check against
+
+		@returns A function that checks an instance tree
+	**--]]
+	function t.children(checkTable)
+		assert(checkChildren(checkTable))
+
+		return function(value)
+			local instanceSuccess, instanceErrMsg = t.Instance(value)
+			if not instanceSuccess then
+				return false, instanceErrMsg or ""
+			end
+
+			local childrenByName = {}
+			for _, child in pairs(value:GetChildren()) do
+				local name = child.Name
+				if checkTable[name] then
+					if childrenByName[name] then
+						return false, string.format("Cannot process multiple children with the same name \"%s\"", name)
+					end
+					childrenByName[name] = child
+				end
+			end
+
+			for name, check in pairs(checkTable) do
+				local success, errMsg = check(childrenByName[name])
+				if not success then
+					return false, string.format("[%s.%s] %s", value:GetFullName(), name, errMsg or "")
+				end
+			end
+
+			return true
+		end
+	end
+end
+
+return t
diff --git a/src/Rust/benches/t.rs b/src/Rust/benches/t.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ea31bac1d958c9eae6432cb7ab005d1418cf172a
--- /dev/null
+++ b/src/Rust/benches/t.rs
@@ -0,0 +1,21 @@
+use criterion::{criterion_group, criterion_main, Criterion};
+use vvs_parser::prelude::{ast::*, parser::*};
+
+const T_SOURCE: &str = include_str!("./t.lua");
+
+fn parse(criterion: &mut Criterion) {
+    criterion.bench_function("get ast from parsed t", move |b| b.iter(|| parse_lua_tree(T_SOURCE)));
+}
+
+fn range(criterion: &mut Criterion) {
+    let ast = parse_lua_tree(T_SOURCE).unwrap();
+    criterion.bench_function("get range of ast of t", move |b| b.iter(|| ast.nodes().range()));
+}
+
+criterion_group! {
+    name = benches;
+    config = Criterion::default().sample_size(20);
+    targets = parse, range
+}
+
+criterion_main!(benches);
diff --git a/src/Rust/rustfmt.toml b/src/Rust/rustfmt.toml
index abc68cf273d033f6350083ce7f0a05eedabf2222..9ef09980ff314c41685fc44ddb7990cd7888f160 100644
--- a/src/Rust/rustfmt.toml
+++ b/src/Rust/rustfmt.toml
@@ -1,12 +1,12 @@
 edition = "2021"
-max_width = 120
 newline_style = "Unix"
 
 # Let's use the horizontal space of the screen
-fn_call_width = 70
-single_line_if_else_max_width = 70
-struct_lit_width = 70
-struct_variant_width = 70
+max_width = 120
+fn_call_width = 100
+single_line_if_else_max_width = 100
+struct_lit_width = 100
+struct_variant_width = 100
 
 # Modern rust
 use_try_shorthand = true
diff --git a/src/Rust/vvs_ass/Cargo.toml b/src/Rust/vvs_ass/Cargo.toml
index 2a9a1f6421ec74443e6fa4519b7109258ba28118..7200e2fcdd7a7e85d77688163aaf949033467e20 100644
--- a/src/Rust/vvs_ass/Cargo.toml
+++ b/src/Rust/vvs_ass/Cargo.toml
@@ -1,18 +1,18 @@
 [package]
-name = "vvs_ass"
+name              = "vvs_ass"
+description       = "ASS specification and VVS specificities for VVCC"
 version.workspace = true
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
-description = "ASS specification and VVS specificities for VVCC"
 
 [dependencies]
-vvs_procmacro = { path = "../vvs_procmacro" }
-vvs_utils = { path = "../vvs_utils" }
-vvs_font = { path = "../vvs_font" }
+vvs_procmacro.workspace = true
+vvs_utils.workspace     = true
+vvs_font.workspace      = true
 
 unicode-segmentation.workspace = true
-thiserror.workspace = true
-anyhow.workspace = true
-serde.workspace = true
-log.workspace = true
+thiserror.workspace            = true
+anyhow.workspace               = true
+serde.workspace                = true
+log.workspace                  = true
diff --git a/src/Rust/vvs_ass/src/colors.rs b/src/Rust/vvs_ass/src/colors.rs
index 380a9a1ac0f36cf70dd744f8790460dc7f5af815..d4047bb8a9d9a8da9ac7ac86c4d8d0f772f80306 100644
--- a/src/Rust/vvs_ass/src/colors.rs
+++ b/src/Rust/vvs_ass/src/colors.rs
@@ -36,6 +36,7 @@ impl ASSColor {
     rgb! { FUCHSIA => 255   0 255 }
     rgb! { PURPLE  => 128   0 128 }
 
+    #[inline]
     fn skip_delimiters(str: &str) -> &str {
         str.trim()
             .trim_start_matches('#')
@@ -44,6 +45,7 @@ impl ASSColor {
             .trim_end_matches('&')
     }
 
+    #[inline]
     pub fn try_from_rgba(str: impl AsRef<str>) -> Result<Self, String> {
         let color = Self::skip_delimiters(str.as_ref());
         if !(color.len() == 6 || color.len() == 8) {
@@ -61,6 +63,7 @@ impl ASSColor {
         })
     }
 
+    #[inline]
     pub fn try_from_bgra(str: impl AsRef<str>) -> Result<Self, String> {
         let color = Self::skip_delimiters(str.as_ref());
         if !(color.len() == 6 || color.len() == 8) {
@@ -78,6 +81,7 @@ impl ASSColor {
         })
     }
 
+    #[inline]
     pub fn into_rgba(self) -> Self {
         match self {
             this @ ASSColor::RGBA { .. } => this,
@@ -113,6 +117,7 @@ impl ASSColor {
         }
     }
 
+    #[inline]
     pub fn into_hsla(self) -> Self {
         match self {
             this @ ASSColor::HSLA { .. } => this,
@@ -132,6 +137,7 @@ impl ASSColor {
     }
 
     /// Returns the HUE from the color (the H in HSL/HSV).
+    #[inline]
     fn hue(&self) -> f32 {
         match self {
             ASSColor::HSLA { h, .. } => *h,
diff --git a/src/Rust/vvs_ass/src/definitions.rs b/src/Rust/vvs_ass/src/definitions.rs
index dcd1b2012835759e6ad06fa51d7ab8deef428b8d..bb488d6fb04b66ec2eef0d6b00570857a3330199 100644
--- a/src/Rust/vvs_ass/src/definitions.rs
+++ b/src/Rust/vvs_ass/src/definitions.rs
@@ -17,17 +17,17 @@ pub struct ASSEvent {
 
     /// Subtitles having different layer number will be ignored during the collusion detection.
     /// Higher numbered layers will be drawn over the lower numbered.
-    pub layer: i64,
+    pub layer: i32,
 
     /// Start Time of the Event, in 0:00:00:00 format ie. Hrs:Mins:Secs:hundredths. This is the
     /// time elapsed during script playback at which the text will appear onscreen. Note that there
     /// is a single digit for the hours!
-    pub start: i64,
+    pub start: i32,
 
     /// End Time of the Event, in 0:00:00:00 format ie. Hrs:Mins:Secs:hundredths. This is the time
     /// elapsed during script playback at which the text will disappear offscreen. Note that there
     /// is a single digit for the hours!
-    pub end: i64,
+    pub end: i32,
 
     /// Style name. If it is "Default", then your own *Default style will be subtituted. However,
     /// the Default style used by the script author IS stored in the script even though SSA ignores
@@ -171,6 +171,7 @@ pub enum ScriptInfoKey {
 impl FromStr for ScriptInfoKey {
     type Err = String;
 
+    #[inline]
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         use ScriptInfoKey::*;
         match s.trim() {
@@ -199,6 +200,7 @@ impl FromStr for ScriptInfoKey {
 impl FromStr for ASSFileSection {
     type Err = String;
 
+    #[inline]
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         use ASSFileSection::*;
         const TRIM_PAT: &[char] = &['[', ']', ' ', '\t'];
diff --git a/src/Rust/vvs_ass/src/drawing.rs b/src/Rust/vvs_ass/src/drawing.rs
index c2d2a88260a55919d2179b0a9e5301ce3a3c1053..7e5c7bf8af91919718686de83e4120bc9396310c 100644
--- a/src/Rust/vvs_ass/src/drawing.rs
+++ b/src/Rust/vvs_ass/src/drawing.rs
@@ -21,49 +21,22 @@
 #[derive(Debug, Clone, PartialEq)]
 pub enum ASSDrawingCmd {
     // Moves the cursor to <x>, <y>
-    M {
-        x: i64,
-        y: i64,
-    },
+    M { x: i64, y: i64 },
 
     // Moves the cursor to <x>, <y> (unclosed shapes will be left open)
-    N {
-        x: i64,
-        y: i64,
-    },
+    N { x: i64, y: i64 },
 
     // Draws a line to <x>, <y>
-    L {
-        x: i64,
-        y: i64,
-    },
+    L { x: i64, y: i64 },
 
     // 3rd degree bezier curve to point 3 using point 1 and 2 as the control points
-    B {
-        x1: i64,
-        y1: i64,
-        x2: i64,
-        y2: i64,
-        x3: i64,
-        y3: i64,
-    },
+    B { x1: i64, y1: i64, x2: i64, y2: i64, x3: i64, y3: i64 },
 
     // 3rd degree uniform b-spline to point N, must contain at least 3 coordinates
-    S {
-        x1: i64,
-        y1: i64,
-        x2: i64,
-        y2: i64,
-        x3: i64,
-        y3: i64,
-        others: Vec<(i64, i64)>,
-    },
+    S { x1: i64, y1: i64, x2: i64, y2: i64, x3: i64, y3: i64, others: Vec<(i64, i64)> },
 
     // Extend b-spline to <x>, <y>
-    P {
-        x: i64,
-        y: i64,
-    },
+    P { x: i64, y: i64 },
 
     // close b-spline
     C,
@@ -76,6 +49,7 @@ pub struct ASSDrawing {
 }
 
 impl ASSDrawingCmd {
+    #[inline]
     pub fn is_move_cmd(&self) -> bool {
         use ASSDrawingCmd::*;
         matches!(self, M { .. } | N { .. })
diff --git a/src/Rust/vvs_ass/src/elements/aux_table.rs b/src/Rust/vvs_ass/src/elements/aux_table.rs
new file mode 100644
index 0000000000000000000000000000000000000000..78da4efe8f263e013dbc0d3443f41f4583a06f6c
--- /dev/null
+++ b/src/Rust/vvs_ass/src/elements/aux_table.rs
@@ -0,0 +1,3 @@
+pub trait AuxTable: Default + PartialEq {
+    fn deep_clone(&self) -> Self;
+}
diff --git a/src/Rust/vvs_ass/src/elements/line.rs b/src/Rust/vvs_ass/src/elements/line.rs
index 63df87f09256b591a6ed13421f264e77b0585aff..8e86b8aaac1846185b95937361a6dafb71e0cc62 100644
--- a/src/Rust/vvs_ass/src/elements/line.rs
+++ b/src/Rust/vvs_ass/src/elements/line.rs
@@ -1,78 +1,20 @@
-use crate::{ASSAuxTable, ASSPosition, ASSSyllabePtr};
+use crate::{ASSPosition, ASSSyllabe, AuxTable};
 
-#[derive(Debug, Default, Clone, PartialEq)]
-pub struct ASSLine {
+#[derive(Debug, Default, PartialEq)]
+pub struct ASSLine<T: AuxTable> {
+    pub is_comment: bool,
+    pub start: i32,
+    pub fini: i32,
     pub position: ASSPosition,
-    pub content: Vec<ASSSyllabePtr>,
-    pub aux: ASSAuxTable,
-    pub start: i64,
-    pub fini: i64,
+    pub content: Vec<ASSSyllabe<T>>,
+    pub aux: T,
 }
 
-#[derive(Debug, Default, Clone)]
-#[repr(transparent)]
-pub struct ASSLinePtr(pub crate::Ptr<ASSLine>);
-
-#[derive(Debug, Default, Clone)]
-#[repr(transparent)]
-pub struct ASSLines(pub Vec<ASSLinePtr>);
-
-impl PartialEq for ASSLinePtr {
-    fn eq(&self, other: &Self) -> bool {
-        *self.0.try_read().unwrap() == *other.0.try_read().unwrap()
-    }
-}
-
-impl PartialEq for ASSLines {
-    fn eq(&self, Self(other): &Self) -> bool {
-        let Self(this) = self;
-        (this.len() != other.len()) && {
-            this.iter()
-                .zip(other.iter())
-                .fold(true, |acc, (ASSLinePtr(this), ASSLinePtr(other))| {
-                    acc && (*this.try_read().unwrap() == *other.try_read().unwrap())
-                })
-        }
-    }
-}
-
-impl From<ASSLine> for ASSLinePtr {
-    fn from(value: ASSLine) -> Self {
-        ASSLinePtr(crate::ptr!(value))
-    }
-}
-
-impl ASSLines {
-    pub fn len(&self) -> usize {
-        self.0.len()
-    }
-
-    pub fn is_empty(&self) -> bool {
-        self.0.is_empty()
-    }
-
-    pub fn push(&mut self, value: impl Into<ASSLinePtr>) {
-        self.0.push(value.into())
-    }
-}
-
-impl Extend<ASSLinePtr> for ASSLines {
-    fn extend<T: IntoIterator<Item = ASSLinePtr>>(&mut self, iter: T) {
-        self.0.extend(iter)
-    }
-}
-
-impl Extend<ASSLine> for ASSLines {
-    fn extend<T: IntoIterator<Item = ASSLine>>(&mut self, iter: T) {
-        self.extend(iter.into_iter().map(|line| ASSLinePtr(crate::ptr!(line))))
-    }
-}
-
-impl IntoIterator for ASSLines {
-    type Item = ASSLinePtr;
-    type IntoIter = <Vec<ASSLinePtr> as IntoIterator>::IntoIter;
-
-    fn into_iter(self) -> Self::IntoIter {
-        self.0.into_iter()
+impl<T: AuxTable> Clone for ASSLine<T> {
+    fn clone(&self) -> Self {
+        let Self { is_comment, start, fini, position, .. } = *self;
+        let content = self.content.clone();
+        let aux = self.aux.deep_clone();
+        Self { is_comment, start, fini, position, content, aux }
     }
 }
diff --git a/src/Rust/vvs_ass/src/elements/mod.rs b/src/Rust/vvs_ass/src/elements/mod.rs
index 2de364b6fb53687854afc8678fe8c23baffb5e62..d585f9a29e1fe7d4c714df72890efabf20549acc 100644
--- a/src/Rust/vvs_ass/src/elements/mod.rs
+++ b/src/Rust/vvs_ass/src/elements/mod.rs
@@ -1,39 +1,27 @@
+mod aux_table;
 mod line;
 mod syllabe;
 
-pub use self::{line::*, syllabe::*};
+pub use self::{aux_table::*, line::*, syllabe::*};
 
 use crate::{definitions::ScriptInfoKey, ASSStyle};
 use std::collections::HashMap;
 
 #[derive(Debug, Clone)]
-pub struct ASSContainer {
-    pub lines: ASSLines,
+pub struct ASSContainer<T: AuxTable> {
+    pub lines: Vec<ASSLine<T>>,
     pub script_info: HashMap<ScriptInfoKey, String>,
     pub styles: HashMap<String, ASSStyle>,
 }
 
-#[derive(Debug, Clone)]
-#[repr(transparent)]
-pub struct ASSContainerPtr(pub crate::Ptr<ASSContainer>);
-
-impl ASSContainer {
+impl<T: AuxTable> ASSContainer<T> {
     /// Create an ASS container from its parts, they must be valide!
+    #[inline]
     pub(crate) fn from_parts(
-        lines: impl IntoIterator<Item = ASSLine>,
+        lines: impl IntoIterator<Item = ASSLine<T>>,
         script_info: HashMap<ScriptInfoKey, String>,
         styles: HashMap<String, ASSStyle>,
     ) -> Self {
-        Self {
-            lines: ASSLines(lines.into_iter().map(|line| ASSLinePtr(crate::ptr!(line))).collect()),
-            script_info,
-            styles,
-        }
-    }
-}
-
-impl From<ASSContainer> for ASSContainerPtr {
-    fn from(value: ASSContainer) -> Self {
-        Self(crate::ptr!(value))
+        Self { lines: lines.into_iter().collect(), script_info, styles }
     }
 }
diff --git a/src/Rust/vvs_ass/src/elements/syllabe.rs b/src/Rust/vvs_ass/src/elements/syllabe.rs
index 4c098045cfe2de182e5e9b54e8c20922cec6435e..76898ff35df2cf6e1b924ebd9b66127b055777a3 100644
--- a/src/Rust/vvs_ass/src/elements/syllabe.rs
+++ b/src/Rust/vvs_ass/src/elements/syllabe.rs
@@ -1,78 +1,19 @@
-use crate::{ASSAuxTable, ASSPosition};
+use crate::{ASSPosition, AuxTable};
 
-#[derive(Debug, Default, Clone, PartialEq)]
-pub struct ASSSyllabe {
+#[derive(Debug, Default, PartialEq)]
+pub struct ASSSyllabe<T: AuxTable> {
     pub position: ASSPosition,
     pub content: String,
-    pub aux: ASSAuxTable,
-    pub start: i64,
-    pub fini: i64,
+    pub aux: T,
+    pub start: i32,
+    pub fini: i32,
 }
 
-#[derive(Debug, Default, Clone)]
-#[repr(transparent)]
-pub struct ASSSyllabePtr(pub crate::Ptr<ASSSyllabe>);
-
-#[derive(Debug, Default, Clone)]
-#[repr(transparent)]
-pub struct ASSSyllabes(pub Vec<ASSSyllabePtr>);
-
-impl PartialEq for ASSSyllabePtr {
-    fn eq(&self, other: &Self) -> bool {
-        *self.0.try_read().unwrap() == *other.0.try_read().unwrap()
-    }
-}
-
-impl PartialEq for ASSSyllabes {
-    fn eq(&self, Self(other): &Self) -> bool {
-        let Self(this) = self;
-        (this.len() != other.len()) && {
-            this.iter()
-                .zip(other.iter())
-                .fold(true, |acc, (ASSSyllabePtr(this), ASSSyllabePtr(other))| {
-                    acc && (*this.try_read().unwrap() == *other.try_read().unwrap())
-                })
-        }
-    }
-}
-
-impl From<ASSSyllabe> for ASSSyllabePtr {
-    fn from(value: ASSSyllabe) -> Self {
-        ASSSyllabePtr(crate::ptr!(value))
-    }
-}
-
-impl ASSSyllabes {
-    pub fn len(&self) -> usize {
-        self.0.len()
-    }
-
-    pub fn is_empty(&self) -> bool {
-        self.0.is_empty()
-    }
-
-    pub fn push(&mut self, value: impl Into<ASSSyllabePtr>) {
-        self.0.push(value.into())
-    }
-}
-
-impl Extend<ASSSyllabePtr> for ASSSyllabes {
-    fn extend<T: IntoIterator<Item = ASSSyllabePtr>>(&mut self, iter: T) {
-        self.0.extend(iter)
-    }
-}
-
-impl Extend<ASSSyllabe> for ASSSyllabes {
-    fn extend<T: IntoIterator<Item = ASSSyllabe>>(&mut self, iter: T) {
-        self.extend(iter.into_iter().map(|syllabe| ASSSyllabePtr(crate::ptr!(syllabe))))
-    }
-}
-
-impl IntoIterator for ASSSyllabes {
-    type Item = ASSSyllabePtr;
-    type IntoIter = <Vec<ASSSyllabePtr> as IntoIterator>::IntoIter;
-
-    fn into_iter(self) -> Self::IntoIter {
-        self.0.into_iter()
+impl<T: AuxTable> Clone for ASSSyllabe<T> {
+    fn clone(&self) -> Self {
+        let Self { position, start, fini, .. } = *self;
+        let content = self.content.clone();
+        let aux = self.aux.deep_clone();
+        Self { position, content, aux, start, fini }
     }
 }
diff --git a/src/Rust/vvs_ass/src/lib.rs b/src/Rust/vvs_ass/src/lib.rs
index 59575219123c8918200d5218621b456152507680..ef883672035ccdc5317d3d94cfe8b171291d12f5 100644
--- a/src/Rust/vvs_ass/src/lib.rs
+++ b/src/Rust/vvs_ass/src/lib.rs
@@ -9,23 +9,9 @@ mod position;
 mod reader;
 mod styles;
 mod types;
-mod values;
 
 #[cfg(test)]
 mod tests;
 
-pub use crate::{colors::*, drawing::*, elements::*, position::*, styles::*, types::*, values::*};
+pub use crate::{colors::*, drawing::*, elements::*, position::*, styles::*, types::*};
 pub use reader::{ass_container_from_file, ass_container_from_str, ASSElementReaderError, ContainerFileType};
-
-pub type Ptr<T> = std::sync::Arc<std::sync::RwLock<T>>;
-
-#[macro_export]
-macro_rules! ptr {
-    ($expr: expr) => {
-        std::sync::Arc::new(std::sync::RwLock::new($expr))
-    };
-}
-
-/// A trait to parameterize the ASS element types. It can be a mutable pointer (Arc<RwLock>), a
-/// pointer to a constant thing (Arc) or no pointer at all (just the ASS element).
-pub trait ASSPtr<T>: std::ops::Deref<Target = T> {}
diff --git a/src/Rust/vvs_ass/src/position.rs b/src/Rust/vvs_ass/src/position.rs
index bc335d235b228340a98591e5d0518edee28b60ab..1f9c49868fd8050036c45fb452501163c6eb7817 100644
--- a/src/Rust/vvs_ass/src/position.rs
+++ b/src/Rust/vvs_ass/src/position.rs
@@ -53,6 +53,7 @@ pub type ASSPositionPtr = std::sync::Arc<ASSPosition>;
 impl std::str::FromStr for ASSAlign {
     type Err = String;
 
+    #[inline]
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         match s.trim() {
             "1" => Ok(ASSAlign::BL),
@@ -70,12 +71,14 @@ impl std::str::FromStr for ASSAlign {
 }
 
 impl From<vvs_font::Point> for ASSPosition {
+    #[inline]
     fn from(vvs_font::Point { x, y }: vvs_font::Point) -> Self {
         ASSPosition::Pos { x, y }
     }
 }
 
 impl ASSPosition {
+    #[inline]
     pub fn into_ptr(self) -> ASSPositionPtr {
         std::sync::Arc::new(self)
     }
diff --git a/src/Rust/vvs_ass/src/reader/ass.rs b/src/Rust/vvs_ass/src/reader/ass.rs
index 77c1425508eaa808a62935e72e6d18a2d79fe13a..d3a95ae7a6a7cedb13d0c18b0f7d82439e2d9594 100644
--- a/src/Rust/vvs_ass/src/reader/ass.rs
+++ b/src/Rust/vvs_ass/src/reader/ass.rs
@@ -1,8 +1,4 @@
-use crate::{
-    definitions::{ASSEvent, ASSFileSection, ScriptInfoKey},
-    reader::ASSElementReader,
-    ASSColor, ASSContainer, ASSElementReaderError, ASSLine, ASSStyle,
-};
+use crate::{definitions::*, reader::ASSElementReader, *};
 use std::collections::HashMap;
 use vvs_procmacro::EnumVariantFromStr;
 
@@ -76,9 +72,9 @@ impl<'a, K: Eq + Copy + std::hash::Hash + std::fmt::Debug> UnwrapHashMap<'a, K>
         name: &str,
     ) -> Result<T, ASSElementReaderError> {
         let Self(hashmap) = self;
-        let element = hashmap.get(&key).ok_or(ASSElementReaderError::Custom(format!(
-            "failed to find entry with key {key:?}"
-        )))?;
+        let element = hashmap
+            .get(&key)
+            .ok_or(ASSElementReaderError::Custom(format!("failed to find entry with key {key:?}")))?;
         parser(element, name)
     }
 
@@ -117,9 +113,7 @@ fn parse_boolean(boolean: &str, name: &str) -> Result<bool, ASSElementReaderErro
     match boolean.trim() {
         "-1" | "1" | "+1" => Ok(true),
         "0" => Ok(false),
-        boolean => Err(ASSElementReaderError::Custom(format!(
-            "invalid ass boolean for {name} found: {boolean}"
-        ))),
+        boolean => Err(ASSElementReaderError::Custom(format!("invalid ass boolean for {name} found: {boolean}"))),
     }
 }
 
@@ -129,13 +123,13 @@ fn parse_float(float: &str, name: &str) -> Result<f64, ASSElementReaderError> {
         .map_err(|err| ASSElementReaderError::Custom(format!("invalid float value for {name}: {err}")))
 }
 
-fn parse_int(int: &str, name: &str) -> Result<i64, ASSElementReaderError> {
-    int.parse::<i64>()
+fn parse_int(int: &str, name: &str) -> Result<i32, ASSElementReaderError> {
+    int.parse::<i32>()
         .map_err(|err| ASSElementReaderError::Custom(format!("invalid integer value for {name}: {err}")))
 }
 
 /// Parse dates in the `0:00:00:00` format
-fn parse_date(date: &str, name: &str) -> Result<i64, ASSElementReaderError> {
+fn parse_date(date: &str, name: &str) -> Result<i32, ASSElementReaderError> {
     let std_err = "invalid date for {name}, expected \"h:mm:ss.cc\", got {date:?}".to_string();
     let [h, m, sc] = &date.split(':').collect::<Vec<_>>()[..] else {
         return Err(ASSElementReaderError::Custom(std_err));
@@ -149,7 +143,7 @@ fn parse_date(date: &str, name: &str) -> Result<i64, ASSElementReaderError> {
         } else {
             Ok(str.parse::<u16>().map_err(|err| {
                 ASSElementReaderError::Custom(format!("invalid component {compnent} for date {name}: {err}"))
-            })? as i64)
+            })? as i32)
         }
     };
     let (h, m, s, c) = (
@@ -164,9 +158,7 @@ fn parse_date(date: &str, name: &str) -> Result<i64, ASSElementReaderError> {
 impl ASSReader {
     fn read_script_info(&mut self, line: &str) -> Result<(), ASSElementReaderError> {
         let Some((key, value)) = line.split_once(':') else {
-            return Err(ASSElementReaderError::Custom(format!(
-                "invalid script info line: {line}"
-            )));
+            return Err(ASSElementReaderError::Custom(format!("invalid script info line: {line}")));
         };
         let value = value.trim();
         let key = match key
@@ -187,9 +179,9 @@ impl ASSReader {
             key => key,
         };
         match self.script_info.get(&key) {
-            Some(_) => Err(ASSElementReaderError::Custom(format!(
-                "redefinition of key '{key:?}' in script info section"
-            ))),
+            Some(_) => {
+                Err(ASSElementReaderError::Custom(format!("redefinition of key '{key:?}' in script info section")))
+            }
             None => {
                 self.script_info.insert(key, value.to_string());
                 Ok(())
@@ -198,6 +190,8 @@ impl ASSReader {
     }
 
     fn read_v4_style(&mut self, line: &str) -> Result<(), ASSElementReaderError> {
+        use V4PlusStyleFields::*;
+
         let line = if line.starts_with("Format:") {
             let line = line.split_once(':').unwrap().1.trim();
             self.styles_format = line
@@ -220,57 +214,49 @@ impl ASSReader {
         let fields: UnwrapHashMap<V4PlusStyleFields> =
             UnwrapHashMap(HashMap::from_iter(self.styles_format.iter().copied().zip(fields)));
 
-        let encoding = fields.get(V4PlusStyleFields::Encoding);
+        let encoding = fields.get(Encoding);
         if encoding.ne("1") {
-            return Err(ASSElementReaderError::Custom(format!(
-                "we expected the encoding '1', got: {encoding}"
-            )));
+            return Err(ASSElementReaderError::Custom(format!("we expected the encoding '1', got: {encoding}")));
         }
 
-        let name = fields.get(V4PlusStyleFields::Name);
+        let name = fields.get(Name);
         let style = ASSStyle {
             name: name.to_string(),
-            font_name: fields.get(V4PlusStyleFields::Fontname).to_string(),
-            font_size: fields.parsed(V4PlusStyleFields::Fontsize, parse_int, "font size")?,
-            primary_color: fields.parsed(V4PlusStyleFields::PrimaryColour, parse_color, "primary")?,
-            secondary_color: fields.parsed(V4PlusStyleFields::SecondaryColour, parse_color, "secondary")?,
-            outline_color: fields.parsed(V4PlusStyleFields::OutlineColour, parse_color, "outline")?,
-            back_color: fields.parsed(V4PlusStyleFields::BackColour, parse_color, "back")?,
-            bold: fields.parsed(V4PlusStyleFields::Bold, parse_boolean, "bold")?,
-            italic: fields.parsed(V4PlusStyleFields::Italic, parse_boolean, "italic")?,
-            underline: fields.parsed(V4PlusStyleFields::Underline, parse_boolean, "underline")?,
-            strikeout: fields.parsed(V4PlusStyleFields::StrikeOut, parse_boolean, "strikeout")?,
-            scale_x: fields.parsed(V4PlusStyleFields::ScaleX, parse_float, "scale_x")?,
-            scale_y: fields.parsed(V4PlusStyleFields::ScaleY, parse_float, "scale_y")?,
-            spacing: fields.parsed(V4PlusStyleFields::Spacing, parse_float, "spacing")?,
-            angle: fields.parsed(V4PlusStyleFields::Angle, parse_float, "angle")?,
-            border_style: fields
-                .get(V4PlusStyleFields::BorderStyle)
-                .parse()
-                .map_err(ASSElementReaderError::Custom)?,
-            outline: fields.parsed(V4PlusStyleFields::Outline, parse_float, "outline")?,
-            shadow: fields.parsed(V4PlusStyleFields::Shadow, parse_float, "shadow")?,
-            alignment: fields
-                .get(V4PlusStyleFields::Alignment)
-                .parse()
-                .map_err(ASSElementReaderError::Custom)?,
-            margin_l: fields.parsed(V4PlusStyleFields::MarginL, parse_int, "margin_l")?,
-            margin_r: fields.parsed(V4PlusStyleFields::MarginR, parse_int, "margin_r")?,
-            margin_v: fields.parsed(V4PlusStyleFields::MarginV, parse_int, "margin_v")?,
+            font_name: fields.get(Fontname).to_string(),
+            font_size: fields.parsed(Fontsize, parse_int, "font size")?,
+            primary_color: fields.parsed(PrimaryColour, parse_color, "primary")?,
+            secondary_color: fields.parsed(SecondaryColour, parse_color, "secondary")?,
+            outline_color: fields.parsed(OutlineColour, parse_color, "outline")?,
+            back_color: fields.parsed(BackColour, parse_color, "back")?,
+            bold: fields.parsed(Bold, parse_boolean, "bold")?,
+            italic: fields.parsed(Italic, parse_boolean, "italic")?,
+            underline: fields.parsed(Underline, parse_boolean, "underline")?,
+            strikeout: fields.parsed(StrikeOut, parse_boolean, "strikeout")?,
+            scale_x: fields.parsed(ScaleX, parse_float, "scale_x")?,
+            scale_y: fields.parsed(ScaleY, parse_float, "scale_y")?,
+            spacing: fields.parsed(Spacing, parse_float, "spacing")?,
+            angle: fields.parsed(Angle, parse_float, "angle")?,
+            border_style: fields.get(BorderStyle).parse().map_err(ASSElementReaderError::Custom)?,
+            outline: fields.parsed(Outline, parse_float, "outline")?,
+            shadow: fields.parsed(Shadow, parse_float, "shadow")?,
+            alignment: fields.get(Alignment).parse().map_err(ASSElementReaderError::Custom)?,
+            margin_l: fields.parsed(MarginL, parse_int, "margin_l")?,
+            margin_r: fields.parsed(MarginR, parse_int, "margin_r")?,
+            margin_v: fields.parsed(MarginV, parse_int, "margin_v")?,
         };
 
         match self.styles.insert(name.to_string(), style) {
             None => Ok(()),
             Some(old) => {
                 log::error!(target: "ass", "redefine style '{name}', previous style was: {old:#?}");
-                Err(ASSElementReaderError::Custom(format!(
-                    "redefinition of style '{name}'"
-                )))
+                Err(ASSElementReaderError::Custom(format!("redefinition of style '{name}'")))
             }
         }
     }
 
     fn read_event(&mut self, line: &str) -> Result<(), ASSElementReaderError> {
+        use EventFields::*;
+
         let line = if line.starts_with("Format:") {
             let line = line.split_once(':').unwrap().1.trim();
             self.events_format = line
@@ -278,11 +264,8 @@ impl ASSReader {
                 .flat_map(|str| str.trim().parse::<EventFields>())
                 .collect();
             return match self.events_format.last() {
-                Some(EventFields::Text) => Ok(()),
-                _ => Err(ASSElementReaderError::Custom(format!(
-                    "invalid format line: {:?}",
-                    self.events_format
-                ))),
+                Some(Text) => Ok(()),
+                _ => Err(ASSElementReaderError::Custom(format!("invalid format line: {:?}", self.events_format))),
             };
         } else {
             line.split_once(':').unwrap().1.trim()
@@ -302,21 +285,23 @@ impl ASSReader {
                 .zip(fields.into_iter().map(|s| s.trim())),
         ));
         self.events.push(ASSEvent {
-            marked: fields.parsed_or(EventFields::Marked, parse_boolean, "marked", false),
-            layer: fields.parsed_or(EventFields::Layer, parse_int, "layer", 0),
-            start: fields.parsed(EventFields::Start, parse_date, "start")?,
-            end: fields.parsed(EventFields::End, parse_date, "end")?,
-            style: fields.get_or(EventFields::Style, "Default").to_string(),
-            name: fields.get_or(EventFields::Name, "").to_string(),
-            effect: fields.get_or(EventFields::Effect, "").to_string(),
-            text: fields.get(EventFields::Text).to_string(),
+            marked: fields.parsed_or(Marked, parse_boolean, "marked", false),
+            layer: fields.parsed_or(Layer, parse_int, "layer", 0),
+            start: fields.parsed(Start, parse_date, "start")?,
+            end: fields.parsed(End, parse_date, "end")?,
+            style: fields.get_or(Style, "Default").to_string(),
+            name: fields.get_or(Name, "").to_string(),
+            effect: fields.get_or(Effect, "").to_string(),
+            text: fields.get(Text).to_string(),
         });
         Ok(())
     }
 }
 
-impl ASSElementReader for ASSReader {
-    fn try_read(mut self, file: impl std::io::BufRead) -> Result<ASSContainer, ASSElementReaderError> {
+impl<T: AuxTable> ASSElementReader<T> for ASSReader {
+    fn try_read(mut self, file: impl std::io::BufRead) -> Result<ASSContainer<T>, ASSElementReaderError> {
+        use ASSFileSection::*;
+
         // Parse the file
         let mut skip_that_section = false;
         for line in file.lines() {
@@ -337,9 +322,9 @@ impl ASSElementReader for ASSReader {
                 };
             } else if !skip_that_section {
                 match self.section {
-                    Some(ASSFileSection::ScriptInfo) => self.read_script_info(line)?,
-                    Some(ASSFileSection::V4Styles) => self.read_v4_style(line)?,
-                    Some(ASSFileSection::Events) => self.read_event(line)?,
+                    Some(ScriptInfo) => self.read_script_info(line)?,
+                    Some(V4Styles) => self.read_v4_style(line)?,
+                    Some(Events) => self.read_event(line)?,
                     None => {
                         return Err(ASSElementReaderError::Custom(format!(
                             "found the following line without a section: {line}"
diff --git a/src/Rust/vvs_ass/src/reader/json.rs b/src/Rust/vvs_ass/src/reader/json.rs
index b6df22660a63567121c6baed741b698cba79d07c..fb12dbc45755e4e69e0307468ede9dd3c24ab85b 100644
--- a/src/Rust/vvs_ass/src/reader/json.rs
+++ b/src/Rust/vvs_ass/src/reader/json.rs
@@ -1,12 +1,12 @@
-use crate::{reader::ASSElementReader, ASSContainer, ASSElementReaderError};
+use crate::{reader::ASSElementReader, ASSContainer, ASSElementReaderError, AuxTable};
 
 /// Documentation available here: http://www.tcax.org/docs/ass-specs.html or in the `utils/manual`
 /// folder.
 #[derive(Debug, Default)]
 pub struct JSONReader {}
 
-impl ASSElementReader for JSONReader {
-    fn try_read(self, _file: impl std::io::BufRead) -> Result<ASSContainer, ASSElementReaderError> {
+impl<T: AuxTable> ASSElementReader<T> for JSONReader {
+    fn try_read(self, _file: impl std::io::BufRead) -> Result<ASSContainer<T>, ASSElementReaderError> {
         todo!()
     }
 }
diff --git a/src/Rust/vvs_ass/src/reader/mod.rs b/src/Rust/vvs_ass/src/reader/mod.rs
index 70f904a9d664113a6fb22452e74cb29a5cff7591..b2165a0588c28fa4a5255071fdc6bb1fda8084b7 100644
--- a/src/Rust/vvs_ass/src/reader/mod.rs
+++ b/src/Rust/vvs_ass/src/reader/mod.rs
@@ -1,7 +1,7 @@
 //! Read the content of an ASS file / a Vivy subtitle file and creates an
 //! [vvs_ass::elements::lines::ASSLinesPtr] structure accordingly.
 
-use crate::ASSContainer;
+use crate::{ASSContainer, AuxTable};
 use std::{
     fs::File,
     io::{BufReader, Error as IoError},
@@ -38,11 +38,11 @@ pub enum ASSElementReaderError {
     Custom(String),
 }
 
-trait ASSElementReader {
-    fn try_read(self, file: impl std::io::BufRead) -> Result<ASSContainer, ASSElementReaderError>;
+trait ASSElementReader<T: AuxTable> {
+    fn try_read(self, file: impl std::io::BufRead) -> Result<ASSContainer<T>, ASSElementReaderError>;
 }
 
-pub fn ass_container_from_file(file: impl AsRef<Path>) -> Result<ASSContainer, ASSElementReaderError> {
+pub fn ass_container_from_file<T: AuxTable>(file: impl AsRef<Path>) -> Result<ASSContainer<T>, ASSElementReaderError> {
     let file = file.as_ref();
     let Some(extension) = file.extension() else {
         return Err(ASSElementReaderError::NoExtension(file.to_path_buf()));
@@ -57,10 +57,10 @@ pub fn ass_container_from_file(file: impl AsRef<Path>) -> Result<ASSContainer, A
     }
 }
 
-pub fn ass_container_from_str(
+pub fn ass_container_from_str<T: AuxTable>(
     extension: ContainerFileType,
     str: impl AsRef<str>,
-) -> Result<ASSContainer, ASSElementReaderError> {
+) -> Result<ASSContainer<T>, ASSElementReaderError> {
     use ContainerFileType::*;
     let content = BufReader::new(str.as_ref().as_bytes());
     match extension {
diff --git a/src/Rust/vvs_ass/src/styles.rs b/src/Rust/vvs_ass/src/styles.rs
index 81252927a34c624b9c392c61bd352438f1d9073b..612e64df91a186d653dc23e95d376cb0b0d7d654 100644
--- a/src/Rust/vvs_ass/src/styles.rs
+++ b/src/Rust/vvs_ass/src/styles.rs
@@ -17,7 +17,7 @@ pub struct ASSStyle {
     pub font_name: String,
 
     /// The size of the font. Don't use a thing that is too big... Must be positive.
-    pub font_size: i64,
+    pub font_size: i32,
 
     /// The colour that a subtitle will normally appear in.
     pub primary_color: ASSColor,
@@ -84,23 +84,24 @@ pub struct ASSStyle {
     /// subtitle text will be displayed.
     ///
     /// Must be a positive integer.
-    pub margin_l: i64,
+    pub margin_l: i32,
 
     /// This defines the Right Margin in pixels. It is the distance from the right-hand edge of the
     /// screen. The three onscreen margins (margin_l, margin_r, margin_v) define areas in which the
     /// subtitle text will be displayed.
-    pub margin_r: i64,
+    pub margin_r: i32,
 
     /// This defines the vertical Left Margin in pixels.
     /// - For a subtitle, it is the distance from the bottom of the screen.
     /// - For a toptitle, it is the distance from the top of the screen.
     /// - For a midtitle, the value is ignored - the text will be vertically centred
-    pub margin_v: i64,
+    pub margin_v: i32,
 }
 
 impl std::str::FromStr for ASSBorderStyle {
     type Err = String;
 
+    #[inline]
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         match s.trim() {
             "1" => Ok(ASSBorderStyle::OutlineAndDropShadow),
@@ -111,10 +112,12 @@ impl std::str::FromStr for ASSBorderStyle {
 }
 
 impl ASSStyle {
+    #[inline]
     pub fn default_name() -> &'static str {
         "Default"
     }
 
+    #[inline]
     pub fn default_name_string() -> String {
         Self::default_name().to_string()
     }
@@ -122,9 +125,19 @@ impl ASSStyle {
 
 impl Default for ASSStyle {
     fn default() -> Self {
+        let font = vvs_font::embeded_fonts()
+            .first()
+            .expect("we should at least bundle one font");
+        let font = vvs_font::Font::try_from(font.1).expect("the font we bundle is not valid");
+        let font_name = font.name().expect("the font we bundle doesn't have a valid name");
+        match &font.font_types()[..] {
+            [vvs_font::FontType::Regular] => {}
+            _ => panic!("the font we bundle is not regular"),
+        }
+
         Self {
             name: Self::default_name_string(),
-            font_name: Default::default(),
+            font_name,
             font_size: 14,
             primary_color: ASSColor::WHITE,
             secondary_color: ASSColor::RED,
diff --git a/src/Rust/vvs_ass/src/tests.rs b/src/Rust/vvs_ass/src/tests.rs
index 12c6ec72cd1c0f35d88dffac3c7e80cfc8793a51..a85f04b45e8538a8062479eac96174e6a81dbbfe 100644
--- a/src/Rust/vvs_ass/src/tests.rs
+++ b/src/Rust/vvs_ass/src/tests.rs
@@ -1,3 +1,5 @@
+use crate::*;
+
 mod color {
     use crate::*;
 
@@ -32,10 +34,7 @@ mod color {
         assert!(ASSColor::try_from_rgba("AABBCC").is_ok());
         assert!(ASSColor::try_from_rgba("AABBCCAA").is_ok());
 
-        assert_eq!(
-            ASSColor::try_from_rgba("AABBCC").unwrap(),
-            ASSColor::try_from_bgra("CCBBAA").unwrap()
-        );
+        assert_eq!(ASSColor::try_from_rgba("AABBCC").unwrap(), ASSColor::try_from_bgra("CCBBAA").unwrap());
     }
 
     #[test]
@@ -46,18 +45,9 @@ mod color {
             let ASSColor::HSLA { h, s, l, .. } = ASSColor::try_from_rgba(rgb).unwrap().into_hsla() else {
                 unreachable!()
             };
-            assert!(
-                (h_target - h).abs() <= EPSILON_DEG,
-                "invalid convertion for color #{rgb}, hue {h_target} != {h}"
-            );
-            assert!(
-                (s - s1_target).abs() <= EPSILON_0_1,
-                "invalid convertion for color #{rgb}, s {s1_target} != {s}"
-            );
-            assert!(
-                (l - l1_target).abs() <= EPSILON_0_1,
-                "invalid convertion for color #{rgb}, l {l1_target} != {l}"
-            );
+            assert!((h_target - h).abs() <= EPSILON_DEG, "invalid convertion for color #{rgb}, hue {h_target} != {h}");
+            assert!((s - s1_target).abs() <= EPSILON_0_1, "invalid convertion for color #{rgb}, s {s1_target} != {s}");
+            assert!((l - l1_target).abs() <= EPSILON_0_1, "invalid convertion for color #{rgb}, l {l1_target} != {l}");
         }
     }
 
@@ -81,13 +71,21 @@ mod color {
             eq! { b_target, b, "invalid convertion on blue for #{rgb}: {b_target} != {b}"}
         }
     }
+}
 
-    #[test]
-    fn test_parse_empty_ass() {
-        use crate::reader::ass_container_from_str;
-        let content = include_str!("../utils/empty.ass");
-        if let Err(err) = ass_container_from_str(reader::ContainerFileType::ASS, content) {
-            panic!("{err}")
+#[test]
+fn test_parse_empty_ass() {
+    #[derive(Default, Clone, Copy, PartialEq, Eq)]
+    struct AT();
+    impl AuxTable for AT {
+        fn deep_clone(&self) -> Self {
+            *self
         }
     }
+
+    if let Err(err) =
+        reader::ass_container_from_str::<AT>(reader::ContainerFileType::ASS, include_str!("../utils/empty.ass"))
+    {
+        panic!("{err}")
+    }
 }
diff --git a/src/Rust/vvs_ass/src/types.rs b/src/Rust/vvs_ass/src/types.rs
index a3db26679a57b7879c7fd8862234d71f22f707c8..f217f8a47848b95724ce53efb05df7ac03b9ca47 100644
--- a/src/Rust/vvs_ass/src/types.rs
+++ b/src/Rust/vvs_ass/src/types.rs
@@ -50,6 +50,7 @@ pub enum ASSType {
 
 impl ASSType {
     /// Get the name of the ASS type.
+    #[inline]
     pub fn as_str(&self) -> &'static str {
         match self {
             ASSType::Lines => "lines",
@@ -60,6 +61,7 @@ impl ASSType {
     }
 
     /// Get the name of the type, but padded with spaces.
+    #[inline]
     pub fn as_padded_str(&self) -> &'static str {
         match self {
             ASSType::Lines => "lines   ",
@@ -70,6 +72,7 @@ impl ASSType {
     }
 
     /// Returns the base type.
+    #[inline]
     pub fn base_type(&self) -> Self {
         match self {
             ASSType::Lines | ASSType::Line => ASSType::Line,
@@ -78,6 +81,7 @@ impl ASSType {
     }
 
     /// Returns the vec type.
+    #[inline]
     pub fn vec_type(&self) -> Self {
         match self {
             ASSType::Lines | ASSType::Line => ASSType::Lines,
@@ -87,12 +91,14 @@ impl ASSType {
 }
 
 impl AsRef<str> for ASSType {
+    #[inline]
     fn as_ref(&self) -> &str {
         self.as_str()
     }
 }
 
 impl std::fmt::Display for ASSType {
+    #[inline]
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         f.write_str(self.as_str())
     }
diff --git a/src/Rust/vvs_ass/src/values.rs b/src/Rust/vvs_ass/src/values.rs
deleted file mode 100644
index 32a1681984392632070e14ada2b58787f6570096..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_ass/src/values.rs
+++ /dev/null
@@ -1,200 +0,0 @@
-use serde::{Deserialize, Serialize};
-use std::{collections::HashMap, convert::TryFrom};
-
-/// The values that can be added to an ASS element.
-#[derive(Clone, PartialEq, Serialize, Deserialize)]
-pub enum ASSAuxValue {
-    Integer(i64),
-    Floating(f64),
-    Boolean(bool),
-    String(String),
-}
-
-/// The auxiliary table of user values associated to ASS elements.
-#[derive(Debug, Default, Clone, PartialEq)]
-pub struct ASSAuxTable(HashMap<String, ASSAuxValue>);
-
-impl std::fmt::Debug for ASSAuxValue {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Self::Integer(arg0) => write!(f, "{arg0}"),
-            Self::Floating(arg0) => write!(f, "{arg0}"),
-            Self::String(arg0) => write!(f, "{arg0:?}"),
-            Self::Boolean(arg0) => write!(f, "{arg0}"),
-        }
-    }
-}
-
-impl ASSAuxValue {
-    pub fn type_str(&self) -> &'static str {
-        match self {
-            ASSAuxValue::Floating(_) => "floating",
-            ASSAuxValue::Integer(_) => "integer",
-            ASSAuxValue::Boolean(_) => "boolean",
-            ASSAuxValue::String(_) => "string",
-        }
-    }
-
-    pub fn coerce_like(self, like: &ASSAuxValue) -> Option<ASSAuxValue> {
-        use ASSAuxValue::*;
-        match (&self, like) {
-            (Floating(_), Floating(_))
-            | (Integer(_), Integer(_))
-            | (Boolean(_), Boolean(_))
-            | (String(_), String(_)) => Some(self),
-
-            (Integer(v), Floating(_)) => Some(Floating(i32::try_from(*v).ok()? as f64)),
-            (Integer(0), Boolean(_)) => Some(Boolean(false)),
-            (Integer(_), Boolean(_)) => Some(Boolean(true)),
-
-            (Boolean(v), String(_)) => Some(String(format!("{v}"))),
-            (Integer(v), String(_)) => Some(String(format!("{v}"))),
-            (Floating(v), String(_)) => Some(String(format!("{v}"))),
-
-            (Boolean(v), Integer(_)) => Some(Integer(*v as i64)),
-
-            (String(_), Integer(_)) => todo!(),
-            (String(_), Floating(_)) => todo!(),
-            (String(_), Boolean(_)) => todo!(),
-
-            (Floating(_), Integer(_)) | (Floating(_), Boolean(_)) | (Boolean(_), Floating(_)) => {
-                log::error!(target: "lua", "invalid convertion from type `{}` to `{}`", self.type_str(), like.type_str());
-                None
-            }
-        }
-    }
-}
-
-impl From<String> for ASSAuxValue {
-    fn from(value: String) -> Self {
-        Self::String(value)
-    }
-}
-
-impl From<&str> for ASSAuxValue {
-    fn from(value: &str) -> Self {
-        Self::String(value.to_string())
-    }
-}
-
-impl From<bool> for ASSAuxValue {
-    fn from(value: bool) -> Self {
-        Self::Boolean(value)
-    }
-}
-
-impl From<f32> for ASSAuxValue {
-    fn from(value: f32) -> Self {
-        Self::Floating(value as f64)
-    }
-}
-
-impl From<f64> for ASSAuxValue {
-    fn from(value: f64) -> Self {
-        Self::Floating(value)
-    }
-}
-
-impl From<i64> for ASSAuxValue {
-    fn from(value: i64) -> Self {
-        Self::Integer(value)
-    }
-}
-
-impl From<i32> for ASSAuxValue {
-    fn from(value: i32) -> Self {
-        Self::Integer(value as i64)
-    }
-}
-
-impl From<u32> for ASSAuxValue {
-    fn from(value: u32) -> Self {
-        Self::Integer(value as i64)
-    }
-}
-
-impl From<i16> for ASSAuxValue {
-    fn from(value: i16) -> Self {
-        Self::Integer(value as i64)
-    }
-}
-
-impl From<u16> for ASSAuxValue {
-    fn from(value: u16) -> Self {
-        Self::Integer(value as i64)
-    }
-}
-
-impl From<i8> for ASSAuxValue {
-    fn from(value: i8) -> Self {
-        Self::Integer(value as i64)
-    }
-}
-
-impl From<u8> for ASSAuxValue {
-    fn from(value: u8) -> Self {
-        Self::Integer(value as i64)
-    }
-}
-
-impl std::fmt::Display for ASSAuxValue {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            ASSAuxValue::Floating(val) => write!(f, "{val}"),
-            ASSAuxValue::Integer(val) => write!(f, "{val}"),
-            ASSAuxValue::Boolean(val) => write!(f, "{val}"),
-            ASSAuxValue::String(val) => f.write_str(val),
-        }
-    }
-}
-
-impl ASSAuxTable {
-    pub fn new() -> Self {
-        Default::default()
-    }
-
-    pub fn set(&mut self, name: impl AsRef<str>, value: ASSAuxValue) {
-        let name = name.as_ref();
-        let new = value.type_str();
-        match self.0.get_mut(name) {
-            Some(old) => match value.coerce_like(old) {
-                Some(new) => *old = new,
-                None => log::error!(
-                    target: "lua",
-                    "can't set new value for `{name}`, old value was of type `{}` and new one is of type `{new}`",
-                    old.type_str()
-                ),
-            },
-            None => {
-                let _ = self.0.insert(name.to_string(), value);
-            }
-        }
-    }
-
-    pub fn get_copy(&self, name: impl AsRef<str>) -> Option<ASSAuxValue> {
-        self.0.get(name.as_ref()).cloned()
-    }
-
-    pub fn get(&self, name: impl AsRef<str>) -> Option<&ASSAuxValue> {
-        self.0.get(name.as_ref())
-    }
-
-    pub fn get_mut(&mut self, name: impl AsRef<str>) -> Option<&mut ASSAuxValue> {
-        self.0.get_mut(name.as_ref())
-    }
-}
-
-impl IntoIterator for ASSAuxTable {
-    type Item = <HashMap<String, ASSAuxValue> as IntoIterator>::Item;
-    type IntoIter = <HashMap<String, ASSAuxValue> as IntoIterator>::IntoIter;
-
-    fn into_iter(self) -> Self::IntoIter {
-        self.0.into_iter()
-    }
-}
-
-impl FromIterator<(String, ASSAuxValue)> for ASSAuxTable {
-    fn from_iter<T: IntoIterator<Item = (String, ASSAuxValue)>>(iter: T) -> Self {
-        Self(HashMap::from_iter(iter))
-    }
-}
diff --git a/src/Rust/vvs_cli/Cargo.toml b/src/Rust/vvs_cli/Cargo.toml
index 004cbf2662f52157f3948e890c96e9a6f7a4e83f..2f958d4b5ed1a8990f181b679817732f416b352b 100644
--- a/src/Rust/vvs_cli/Cargo.toml
+++ b/src/Rust/vvs_cli/Cargo.toml
@@ -11,26 +11,23 @@ name = "vvcc"
 path = "src/main.rs"
 
 [dependencies]
-vvs_font = { path = "../vvs_font" }
-vvs_utils = { path = "../vvs_utils" }
+vvs_ass.workspace     = true
+vvs_font.workspace    = true
+vvs_utils.workspace   = true
+vvs_parser.workspace  = true
+vvs_runtime.workspace = true
+vvs_codegen.workspace = true
 
 thiserror.workspace = true
-anyhow.workspace = true
-serde.workspace = true
-toml.workspace = true
-log.workspace = true
+anyhow.workspace    = true
+serde.workspace     = true
+toml.workspace      = true
+log.workspace       = true
 
-clap_mangen = "^0.2"
-clap_complete = "^4"
-clap = { version = "^4", default-features = false, features = [
-    "usage",
-    "help",
-    "std",
-    "suggestions",
-    "error-context",
-    "derive",
-    "wrap_help",
-] }
+clap_mangen.workspace   = true
+clap_complete.workspace = true
+clap.workspace          = true
 
-[target.'cfg(unix)'.dependencies]
-# vvs_repl = { path = "../vvs_repl" }
+[build-dependencies]
+anyhow.workspace   = true
+vvs_llvm.workspace = true
diff --git a/src/Rust/vvs_cli/build.rs b/src/Rust/vvs_cli/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a01480722a65c2a0de92058e860bdc41610328d4
--- /dev/null
+++ b/src/Rust/vvs_cli/build.rs
@@ -0,0 +1,3 @@
+fn main() -> anyhow::Result<()> {
+    vvs_llvm::build::llvm_link()
+}
diff --git a/src/Rust/vvs_cli/src/args.rs b/src/Rust/vvs_cli/src/args.rs
index 1c1d6343e8644ad1147bb0660d34fac8fefd0911..9f75870f5beebbeed4763fa6fe89b713cedea39d 100644
--- a/src/Rust/vvs_cli/src/args.rs
+++ b/src/Rust/vvs_cli/src/args.rs
@@ -2,44 +2,17 @@ use crate::parser::FileTypeValueParser;
 use clap::Parser;
 use clap_complete::Shell;
 use std::path::PathBuf;
-use vvs_utils::*;
-
-fn get_cli_groups() -> impl IntoIterator<Item = clap::ArgGroup> {
-    #[cfg(unix)]
-    fn is_unix_target() -> bool {
-        true
-    }
-    #[cfg(not(unix))]
-    fn is_unix_target() -> bool {
-        false
-    }
-
-    use clap::ArgGroup as grp;
-    [
-        grp::new("action").args(["manpage", "shell", "font-file", "script.vvs"]),
-        grp::new("ass")
-            .args(["subtitle.ass"])
-            .conflicts_with_all(["manpage", "font-file"]),
-        grp::new("opts")
-            .args(["options.toml"])
-            .conflicts_with_all(["shell", "manpage", "font-file"]),
-        grp::new("infos")
-            .args(["info"])
-            .conflicts_with_all(["shell", "manpage", "font-file"]),
-    ]
-    .into_iter()
-    .chain(either!(!is_unix_target() => None; Some(
-        clap::ArgGroup::new("repl")  .args(["interactive"]) .conflicts_with_all(["shell", "manpage", "font-file"])
-    )))
-}
 
 #[derive(Parser, Debug)]
 #[command( author
          , version
          , about
-         , name = "vvcc"
-         , groups = get_cli_groups()
-)]
+         , name   = "vvcc"
+         , groups = [ clap::ArgGroup::new("action").args(["manpage", "shell", "font-file", "script.vvs"])
+                    , clap::ArgGroup::new("ass")   .args(["subtitle.ass"]).conflicts_with_all(["manpage", "font-file"])
+                    , clap::ArgGroup::new("opts")  .args(["options.ini"]) .conflicts_with_all(["shell", "manpage", "font-file"])
+                    , clap::ArgGroup::new("infos") .args(["info"])        .conflicts_with_all(["shell", "manpage", "font-file"])
+])]
 pub struct Args {
     /// The script to run.
     ///
@@ -68,8 +41,8 @@ pub struct Args {
     #[arg( short        = 't'
          , long         = "option"
          , action       = clap::ArgAction::Set
-         , id           = "options.toml"
-         , value_parser = FileTypeValueParser::new("toml")
+         , id           = "options.ini"
+         , value_parser = FileTypeValueParser::new("ini")
     )]
     pub options: Option<PathBuf>,
 
@@ -85,17 +58,6 @@ pub struct Args {
     )]
     pub include_folders: Vec<PathBuf>,
 
-    /// Launch vvcc REPL after loading the passed script if any.
-    ///
-    /// In REPL mode you must not touch to fields that begins by underscores, never. Those fields
-    /// are reserved for vivy or for library developpers. Note that even library developpers must
-    /// not touch or call fields from vivy that begins by underscores.
-    #[cfg(unix)]
-    #[arg( short  = 'i'
-         , action = clap::ArgAction::SetTrue
-    )]
-    pub interactive: bool,
-
     /// Shows informations about a script.
     ///
     /// The informations consists of the loaded modules, all the options, their possible values,
@@ -129,12 +91,14 @@ pub struct Args {
     /// `$HOME/.local/share/man/man1/` or `/usr/share/man/man1` folder
     #[arg( long   = "manpage"
          , action = clap::ArgAction::SetTrue
+         , hide   = true
     )]
     pub manpage: bool,
 
     /// Generate completion script for the given shell
     #[arg( long   = "shell"
          , action = clap::ArgAction::Set
+         , hide   = true
     )]
     pub shell: Option<Shell>,
 }
diff --git a/src/Rust/vvs_cli/src/config.rs b/src/Rust/vvs_cli/src/config.rs
index 38b4d3040d0a292ffbb13e44292f53a289b18d95..0222b83d2f3338f549828a08875c1f2d3d06cfde 100644
--- a/src/Rust/vvs_cli/src/config.rs
+++ b/src/Rust/vvs_cli/src/config.rs
@@ -29,7 +29,6 @@ pub struct Config {
     pub script: Option<PathBuf>,
     pub ass_file: Option<PathBuf>,
     pub options: Option<PathBuf>,
-    pub interactive: bool,
     pub info: bool,
     pub manpage: bool,
     pub shell: Option<Shell>,
@@ -92,23 +91,26 @@ impl Extend<Args> for Config {
                 append     args => self, { include_folders };
                 set_if_not args => self, { script, ass_file, options, shell, font_info };
                 max        args => self, { verbose };
-                override   args => self, { info, manpage, interactive };
+                override   args => self, { info, manpage };
             }
         });
     }
 }
 
 impl ConfigFile {
+    #[inline]
     pub fn serialize(&self) -> Result<String, Box<dyn std::error::Error>> {
         Ok(toml::to_string_pretty(self).map_err(Box::new)?)
     }
 
+    #[inline]
     pub fn deserialize(input: String) -> Result<Self, Box<dyn std::error::Error>> {
         Ok(toml::from_str(&input).map_err(Box::new)?)
     }
 }
 
 impl Default for ConfigKaraMaker {
+    #[inline]
     fn default() -> Self {
         Self { kara_maker: "Viieux".to_string(), email: Default::default() }
     }
diff --git a/src/Rust/vvs_cli/src/main.rs b/src/Rust/vvs_cli/src/main.rs
index da51848fb4528aff924b7a16f7f1495181a3bbb1..345a2bbe6bd8c4dff0463a6d2cf8b5bd9461c3f8 100644
--- a/src/Rust/vvs_cli/src/main.rs
+++ b/src/Rust/vvs_cli/src/main.rs
@@ -1,12 +1,18 @@
 //! The VivyScript cli
-#![forbid(unsafe_code)]
 
-use anyhow::{Context, Result};
+use crate::args::Args;
+use anyhow::{anyhow, Context, Result};
+use clap::CommandFactory;
+use std::{fs, io};
+use vvs_ass::{ass_container_from_file, ASSContainer};
 use vvs_cli::{
     args,
     config::{Config, ConfigFile},
     logger,
 };
+use vvs_codegen::LowererBuilder;
+use vvs_parser::prelude::*;
+use vvs_runtime::{types::VVRTTable, JIT};
 use vvs_utils::xdg::*;
 
 fn print_face_info(name: &str, font: &[u8]) -> Result<()> {
@@ -20,10 +26,7 @@ fn print_face_info(name: &str, font: &[u8]) -> Result<()> {
         .join(", ");
 
     println!("###");
-    println!(
-        "# Family Name:        {}",
-        font.name().with_context(|| "failed to get the font name")?
-    );
+    println!("# Family Name:        {}", font.name().context("failed to get the font name")?);
     println!("# Name(s):            {}", font.family_names().join(", "));
     println!("# Font Type(s):       {font_types}");
     println!("# Number of glyph(s): {}", font.number_of_glyphs());
@@ -32,68 +35,100 @@ fn print_face_info(name: &str, font: &[u8]) -> Result<()> {
 }
 
 fn main() -> Result<()> {
-    logger::init(None).map_err(Box::new)?;
-
+    logger::init(None).context("failed to init logger")?;
     let mut config = Config::default();
     config.extend([
         XDGConfig::<ConfigFile, XDGConfigMergedSilent>::new("vvcc", ConfigFile::deserialize)
             .file("vvcc.toml")
             .read_or_default(ConfigFile::serialize),
     ]);
-    config.extend([<args::Args as clap::Parser>::parse()]);
+    config.extend([<Args as clap::Parser>::parse()]);
     let Config {
         script,
-        ass_file: _,
-        options: _,
-        #[cfg(unix)]
-        interactive,
-        info: _,
+        ass_file: ass_file_path,
+        options: options_path,
+        info,
         manpage,
         shell,
         font_info,
         verbose,
         include_folders: _,
-        ..
+        kara_maker,
     } = config;
-    #[cfg(not(unix))]
-    let interactive = false;
     logger::level(verbose);
 
     if manpage {
         log::debug!(target: "vvcc", "generate the manpage for vvcc");
-        use clap::CommandFactory;
-        return clap_mangen::Man::new(args::Args::command())
-            .render(&mut std::io::stdout())
-            .with_context(|| "failed to render manpage for vvcc");
-    } else if let Some(shell) = shell {
+        return clap_mangen::Man::new(Args::command())
+            .render(&mut io::stdout())
+            .context("failed to render manpage for vvcc");
+    }
+
+    if let Some(shell) = shell {
         log::debug!(target: "vvcc", "generate shell completion script for shell {shell}");
-        use clap::CommandFactory;
-        let mut command = args::Args::command();
+        let mut command = Args::command();
         let command_name = command.get_name().to_string();
-        clap_complete::generate(shell, &mut command, command_name, &mut std::io::stdout());
+        clap_complete::generate(shell, &mut command, command_name, &mut io::stdout());
         return Ok(());
-    } else if let Some(font_info) = font_info {
-        match font_info {
-            Some(path) => {
-                let font =
-                    std::fs::read(&path).with_context(|| format!("failed to read font: {}", path.to_string_lossy()))?;
-                print_face_info(&path.to_string_lossy(), &font)?;
+    }
+
+    if let Some(font_info) = font_info {
+        return match font_info {
+            Some(path) => print_face_info(
+                &path.to_string_lossy(),
+                &fs::read(&path).with_context(|| format!("failed to read font: {}", path.to_string_lossy()))?,
+            ),
+            None => vvs_font::embeded_fonts()
+                .iter()
+                .try_for_each(|(n, f)| print_face_info(n, f)),
+        };
+    }
+
+    match script {
+        None => Args::command()
+            .print_help()
+            .context("failed to print help message for vvcc"),
+
+        Some(script) => {
+            let script = SourceCode::from_path(script)?;
+            log::info!("run as `{kara_maker}` script `{}`", script.name());
+            if let Some(ref options) = options_path {
+                log::info!("use option file `{}`", options.display())
             }
-            None => {
-                for (name, font) in vvs_font::embeded_fonts() {
-                    print_face_info(name, font)?;
+
+            let output = FrontendPipeline::new(&script)
+                .passes(&[])
+                .options(options_path.as_ref())
+                .context("failed to parse option file")?
+                .run()
+                .context("failed to parse script files")?;
+
+            if info {
+                match ass_file_path {
+                    Some(ref path) => println!("ass file ........... {}", path.display()),
+                    None => println!("ass file ........... ø"),
+                }
+                match options_path {
+                    Some(path) => println!("options file ....... {}", path.display()),
+                    None => println!("options file ....... ø"),
                 }
+                println!("{output}");
             }
-        }
-        return Ok(());
-    }
 
-    if script.is_none() && !interactive {
-        use clap::CommandFactory;
-        return args::Args::command()
-            .print_help()
-            .with_context(|| "failed to print help message for vvcc");
-    }
+            // let FrontendOutput { ast, imports, main, options, library } = output;
 
-    Ok(())
+            let ass: ASSContainer<VVRTTable> = ass_container_from_file(
+                ass_file_path.ok_or_else(|| anyhow!("no subtitle file to run the script `{}` on", script.name()))?,
+            )
+            .context("failed to parse the subtitle file")?;
+
+            let jit = JIT::new()?;
+            let module = unsafe { LowererBuilder::new(script.name(), jit.ctx()) }.build().lower();
+            unsafe { jit.add_module(module)? };
+
+            log::error!("use the ASS container and insert it into the JIT: {ass:#?}");
+
+            unimplemented!()
+        }
+    }
 }
diff --git a/src/Rust/vvs_cli/src/parser.rs b/src/Rust/vvs_cli/src/parser.rs
index 21f29bfd2c7dfa81092cf289294bf4102ed88079..1e03bbc71f039064636ad4b9c9eeb5b90120f598 100644
--- a/src/Rust/vvs_cli/src/parser.rs
+++ b/src/Rust/vvs_cli/src/parser.rs
@@ -42,19 +42,13 @@ impl TypedValueParser for FileTypeValueParser {
                 None => {
                     err.insert(
                         ContextKind::InvalidValue,
-                        ContextValue::String(format!(
-                            "file has no extension, expected extension {}",
-                            self.extension
-                        )),
+                        ContextValue::String(format!("file has no extension, expected extension {}", self.extension)),
                     );
                     Err(err)
                 }
             },
             None => {
-                err.insert(
-                    ContextKind::InvalidValue,
-                    ContextValue::String("invalid utf8 string".to_string()),
-                );
+                err.insert(ContextKind::InvalidValue, ContextValue::String("invalid utf8 string".to_string()));
                 Err(err)
             }
         }
diff --git a/src/Rust/vvs_codegen/Cargo.toml b/src/Rust/vvs_codegen/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..39d9009a8a15a410ccde25c5f138d8af5fb2a3ee
--- /dev/null
+++ b/src/Rust/vvs_codegen/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "vvs_codegen"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+description = "The codegen into LLVM for Vivy Script"
+
+[dependencies]
+log.workspace        = true
+serde.workspace      = true
+serde_json.workspace = true
+anyhow.workspace     = true
+hashbrown.workspace  = true
+
+vvs_runtime_types.workspace = true
+vvs_utils.workspace         = true
+vvs_llvm.workspace          = true
+vvs_lang.workspace          = true
+
+[build-dependencies]
+vvs_llvm = { workspace = true, features = ["link"] }
+anyhow.workspace = true
diff --git a/src/Rust/vvs_codegen/build.rs b/src/Rust/vvs_codegen/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a01480722a65c2a0de92058e860bdc41610328d4
--- /dev/null
+++ b/src/Rust/vvs_codegen/build.rs
@@ -0,0 +1,3 @@
+fn main() -> anyhow::Result<()> {
+    vvs_llvm::build::llvm_link()
+}
diff --git a/src/Rust/vvs_codegen/src/context.rs b/src/Rust/vvs_codegen/src/context.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6088a63392892ff5f0a7e8c1600f1e9e7872e4c8
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/context.rs
@@ -0,0 +1,105 @@
+use crate::Value;
+use hashbrown::HashMap;
+use vvs_llvm::*;
+use vvs_runtime_types::vvll::LLVMTypeIsManaged;
+
+/// Just a hashmap used to store values in scope.
+#[derive(Default, Clone)]
+pub(crate) struct ValueContext {
+    /// The values in context.
+    values: HashMap<Box<str>, Value>,
+
+    /// The values that are to be droped, in the order of their définition! They must be dropped in
+    /// the reverse order in which they are stored!
+    to_drop: Vec<Value>,
+
+    /// The number of anon values present in this context.
+    anon_count: u64,
+}
+
+impl ValueContext {
+    /// Create a new sub-context. We clone the available values but not the destructors to run as
+    /// we don't want to run them too early.
+    pub fn sub_context(&self) -> Self {
+        let Self { values, anon_count: i, .. } = self;
+        Self { values: values.clone(), anon_count: *i, to_drop: vec![] }
+    }
+
+    /// Register a new value in the context. We don't give a shit about its name, see if we need a
+    /// destructor for this value.
+    pub fn register_anon(&mut self, value: Value) {
+        if let Some(name) = value.as_str() {
+            let name = format!(".anon.{}:{}", self.anon_count, name);
+            self.anon_count += 1;
+            self.register(name, value)
+        }
+    }
+
+    /// Clone the context and register a new value into it. Used to reduce a bit calls to clone
+    /// everywhere...
+    pub fn to_register(&self, name: impl AsRef<str>, value: Value) -> Self {
+        let mut this = self.clone();
+        this.register(name, value);
+        this
+    }
+
+    /// Clone the context and register a new value into it. Used to reduce a bit calls to clone
+    /// everywhere...
+    pub fn to_register_anon(&self, value: Value) -> Self {
+        let mut this = self.clone();
+        this.register_anon(value);
+        this
+    }
+
+    /// Register a new value in the context.
+    pub fn register(&mut self, name: impl AsRef<str>, value: Value) {
+        fn inner(this: &mut ValueContext, name: &str, value: Value) {
+            log::error!("take into account destructors for {name}");
+            if Value::Nil == value {
+                panic!("can't register nil value `{name}`")
+            } else if this.values.insert(name.into(), value).is_some() {
+                panic!("multiple definitions of `{name}`")
+            }
+        }
+        inner(self, name.as_ref(), value)
+    }
+
+    /// Register a multiple values in the context.
+    pub fn register_all(&mut self, iter: impl IntoIterator<Item = (impl AsRef<str>, Value)>) {
+        iter.into_iter().for_each(|(name, value)| self.register(name, value));
+    }
+
+    /// Get the values to drop in this context in the order of their definition. Also remove them
+    /// from this context.
+    pub fn get_values_to_drop(&mut self) -> Vec<Value> {
+        std::mem::take(&mut self.to_drop)
+    }
+
+    /// Forget a value to drop by its llvm value ref. This way we can also forget anon values.
+    pub fn forget_by_llvm_value(&mut self, value: LLVMValueRef) {
+        use Value::*;
+        if let Some(idx) = self.to_drop.iter().enumerate().find_map(|(idx, val)| {
+            matches!(*val, Const(_, val) | Alloca(_, _, val) | Function(_, _, val) if val == value).then_some(idx)
+        }) {
+            self.to_drop.remove(idx);
+        }
+    }
+
+    /// Add values to drop from another context to extend their lifetime. We can't fail that thing
+    /// because we ignore values that are re-registered.
+    pub fn add_values_to_drop(&mut self, mut values: Vec<Value>) {
+        values.retain(|v| {
+            v.llvm_value()
+                .is_some_and(|v| self.to_drop.iter().any(|u| u.llvm_value().is_some_and(|u| u == v)))
+                && v.llvm_type().is_some_and(|t| unsafe { LLVMTypeIsManaged(t) })
+        });
+        self.to_drop.append(&mut values);
+    }
+
+    /// Get the value by its name in the context, or panic!
+    pub fn get_value(&self, name: impl AsRef<str>) -> &Value {
+        self.values
+            .get(name.as_ref())
+            .unwrap_or_else(|| panic!("failed to find value `{}`", name.as_ref()))
+    }
+}
diff --git a/src/Rust/vvs_codegen/src/graph.rs b/src/Rust/vvs_codegen/src/graph.rs
new file mode 100644
index 0000000000000000000000000000000000000000..51388796c18151008c8f36df269106c662443e36
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/graph.rs
@@ -0,0 +1,103 @@
+//! Small utility to store a basic block graph of a function to compute dominance of values.
+
+use hashbrown::HashSet;
+use std::{collections::VecDeque, hash::Hash, iter};
+
+#[derive(Debug)]
+pub(crate) struct Graph<N: Copy + Clone + PartialEq + Eq + Hash> {
+    /// The nodes of the graph.
+    content: Vec<N>,
+
+    /// Encodes the edges of the graph. In general we have at most 2 outgoing edges per node (one
+    /// for test false, one for test true). We should not encounter a switch, or at least not that
+    /// many...
+    adjacence: Vec<(usize, usize)>,
+}
+
+impl<N: Copy + Clone + PartialEq + Eq + Hash> Default for Graph<N> {
+    fn default() -> Self {
+        Self { content: Vec::default(), adjacence: Vec::default() }
+    }
+}
+
+impl<N: Copy + Clone + PartialEq + Eq + Hash> Graph<N> {
+    /// Create a new empty graph but with a given capacity.
+    pub fn with_capacity(capacity: usize) -> Self {
+        Self { content: Vec::with_capacity(capacity), adjacence: Vec::with_capacity(capacity.saturating_mul(2)) }
+    }
+
+    /// Insert a new node in the graph. If the node is already present we do nothing.
+    pub fn add_node(mut self, node: N) -> Self {
+        if !self.content.contains(&node) {
+            self.content.push(node);
+        }
+        self
+    }
+
+    /// Insert a list of nodes in the graph.
+    pub fn add_nodes(self, nodes: impl IntoIterator<Item = N>) -> Self {
+        nodes.into_iter().fold(self, |this, node| this.add_node(node))
+    }
+
+    /// Insert an edge in the graph. If the edge already exists we do nothing.
+    pub fn add_edge(mut self, from: N, to: N) -> Self {
+        let (from, to) = (self.node_index(from), self.node_index(to));
+        if !self.adjacence.iter().any(|(ef, et)| *ef == from && *et == to) {
+            self.adjacence.push((from, to));
+        }
+        self
+    }
+
+    /// Find the index of a node in the graph or panic!
+    fn node_index(&self, node: N) -> usize {
+        self.content
+            .iter()
+            .enumerate()
+            .find_map(|(idx, n)| (*n == node).then_some(idx))
+            .expect("failed to find node")
+    }
+
+    /// Get all the direct next nodes from a given node.
+    fn nexts(&self, from: N) -> Vec<N> {
+        let node = self.node_index(from);
+        self.adjacence
+            .iter()
+            .filter(|&&(from, _)| (from == node))
+            .map(|&(_, to)| self.content[to])
+            .collect()
+    }
+
+    /// Returns all the nodes in all the simple paths between two nodes. The nodes can be the same,
+    /// in this case we return only this node. When computing the the paths we don't take loop edges.
+    pub fn any_path_content(&self, from: N, to: N) -> HashSet<N> {
+        // Don't ever reallocate.
+        let mut visited = VecDeque::with_capacity(self.content.len());
+        let mut stack = Vec::with_capacity(self.content.len());
+        let mut ret = HashSet::with_capacity(self.content.len());
+
+        // Init the state.
+        visited.push_front(from);
+        stack.push(self.nexts(from));
+
+        // Just do the search.
+        while let Some(children) = stack.last_mut() {
+            match children.pop() {
+                Some(child) if child == to => {
+                    ret.extend(visited.iter().copied().chain(iter::once(to)));
+                }
+                Some(child) if !visited.contains(&child) => {
+                    visited.push_front(child);
+                    stack.push(self.nexts(child));
+                }
+                Some(_visited_child) => {}
+                None => {
+                    visited.pop_back();
+                    stack.pop();
+                }
+            }
+        }
+
+        // We only have to returns the traversed nodes from the paths that found to.
+        ret
+    }
+}
diff --git a/src/Rust/vvs_codegen/src/lib.rs b/src/Rust/vvs_codegen/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8f74fd9dbe8ab9ae93e7867b78a63e1ab558590a
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/lib.rs
@@ -0,0 +1,29 @@
+//! The code used to lower the Vivy Script AST into LLVM code.
+
+mod context;
+mod graph;
+mod lowerer;
+mod value;
+
+// Exports in this crate.
+use crate::{context::*, graph::*, value::*};
+
+// Re-exports.
+pub use lowerer::{Lowerer, LowererBuilder};
+
+type LLVMLowerContext = (vvs_llvm::LLVMModuleRef, vvs_llvm::LLVMContextRef, vvs_llvm::LLVMBuilderRef);
+
+/// The number of temp / unnamed values.
+static mut TEMP_NAME_COUNTER: u64 = 0;
+
+#[macro_export]
+macro_rules! cstr {
+    ($str: literal, $($arg: expr),+ $(,)?) => {
+        format!(concat!($str, "\0"), $($arg),+).as_ptr() as *const i8
+    };
+
+    () => {{
+        $crate::TEMP_NAME_COUNTER += 1;
+        format!(".temp.{}\0", $crate::TEMP_NAME_COUNTER).as_ptr() as *const i8
+    }};
+}
diff --git a/src/Rust/vvs_codegen/src/lowerer/calls.rs b/src/Rust/vvs_codegen/src/lowerer/calls.rs
new file mode 100644
index 0000000000000000000000000000000000000000..b9d0be84745db6340f37115bf7aeee52750df422
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/lowerer/calls.rs
@@ -0,0 +1,108 @@
+use crate::lowerer::*;
+use vvs_lang::ast::*;
+use vvs_llvm::*;
+
+/// Lower a single instruction.
+pub(super) struct CallLowerer<'a> {
+    llvm: LLVMLowerContext,
+    ctx: &'a ValueContext,
+}
+
+impl<'a> CallLowerer<'a> {
+    pub(super) fn new(llvm: LLVMLowerContext, ctx: &'a ValueContext) -> Self {
+        Self { llvm, ctx }
+    }
+
+    pub(super) unsafe fn call_intrinsic<const N: usize>(
+        name: &'static str,
+        (m, _, b): LLVMLowerContext,
+        ret: LLVMTypeRef,
+        mut args: [LLVMValueRef; N],
+    ) -> LLVMValueRef {
+        let id = LLVMLookupIntrinsicID(name.as_ptr() as *const _, name.len());
+        let mut args_ty: Vec<_> = args.iter().map(|val| LLVMTypeOf(*val)).collect();
+        let (args_ty, args_len, args) = (args_ty.as_mut_ptr(), args.len().try_into().unwrap(), args.as_mut_ptr());
+        let (functy, func) = (
+            LLVMFunctionType(ret, args_ty, args_len, 0),
+            LLVMGetIntrinsicDeclaration(m, id, args_ty, args_len as usize),
+        );
+        LLVMBuildCall2(b, functy, func, args, args_len, cstr!())
+    }
+
+    pub(super) fn lower_method_invok(
+        self,
+        obj: &ASTExpr,
+        func: impl AsRef<str>,
+        args: &[ASTExpr],
+    ) -> (ValueContext, Value) {
+        let Self { llvm: llvm @ (_, c, b), ctx } = self;
+
+        let (ctx, object) = ExpressionLowerer::with_assumed_type(llvm, obj, ctx).lower();
+        let (oty, obj) = (object.get_ast_type(), object.loaded(c, b));
+
+        let (aargs, rty, lty, lfn) = match ctx.get_value(VVRTSymbol::method(oty, func.as_ref()).unwrap().to_string()) {
+            Value::Function(ASTType::Function(aargs, rty), lty, lfn) if args.len() == aargs.len() => {
+                (aargs.clone(), rty.clone(), *lty, *lfn)
+            }
+            val => unreachable!("unexpected not a function value: {val:?}"),
+        };
+
+        let mut largs = Vec::with_capacity(args.len());
+        let largc = 1 + args.len() as u32;
+        largs.push(obj);
+        let ctx = args.iter().zip(aargs).fold(ctx, |ctx, (arg, ty)| {
+            let (ctx, arg) = ExpressionLowerer::with_expected_type(llvm, arg, &ty, &ctx).lower();
+            largs.push(arg.loaded(c, b));
+            ctx
+        });
+
+        match *rty {
+            ASTType::Nil => unsafe {
+                LLVMBuildCall2(b, lty, lfn, largs.as_mut_ptr(), largc, c"".as_ptr());
+                (ctx, Value::Nil)
+            },
+            ty => unsafe {
+                let ret_ty = TypeLowerer::new(c, &ty).lower();
+                let ptr = LLVMBuildAlloca(b, ret_ty, cstr!());
+                let val = LLVMBuildCall2(b, lty, lfn, largs.as_mut_ptr(), largc, cstr!());
+                LLVMBuildStore(b, val, ptr);
+                (ctx, Value::Alloca(ty, ret_ty, ptr))
+            },
+        }
+    }
+
+    pub(super) fn lower_func_call(self, func: &ASTExpr, args: &[ASTExpr]) -> (ValueContext, Value) {
+        let Self { llvm: llvm @ (_, c, b), ctx } = self;
+
+        let (ctx, aty, rty_ast, lty, lfn) =
+            match ExpressionLowerer::with_expected_type(llvm, func, &ASTType::Nil, ctx).lower() {
+                (ctx, Value::Function(ASTType::Function(aty, rty), lty, lfn)) if args.len() == aty.len() => {
+                    (ctx, aty, rty, lty, lfn)
+                }
+                (_, what) => unreachable!("unexpected not-a-function-thingy: {what:?}"),
+            };
+
+        let mut largs = Vec::with_capacity(args.len());
+        let args_len = args.len().try_into().expect("too many arguments");
+        let mut ctx = args.iter().zip(aty).fold(ctx, |ctx, (arg, ty)| {
+            let (ctx, expr) = ExpressionLowerer::with_expected_type(llvm, arg, &ty, &ctx).lower();
+            largs.push(expr.loaded(c, b));
+            ctx
+        });
+
+        match unsafe { LLVMGetReturnType(lty) } {
+            rty if rty == unsafe { LLVMVoidTypeInContext(c) } => unsafe {
+                LLVMBuildCall2(b, lty, lfn, largs.as_mut_ptr(), args_len, c"".as_ptr());
+                (ctx, Value::Nil)
+            },
+            rty => unsafe {
+                let val = LLVMBuildCall2(b, lty, lfn, largs.as_mut_ptr(), args_len, cstr!());
+                let ptr = LLVMBuildAlloca(b, rty, c".ignored".as_ptr());
+                LLVMBuildStore(b, val, ptr);
+                let value = Value::Alloca(*rty_ast, rty, ptr);
+                ctx.register_anon(value.clone());
+                (ctx, value)
+            },
+        }
+    }
+}
diff --git a/src/Rust/vvs_codegen/src/lowerer/cast.rs b/src/Rust/vvs_codegen/src/lowerer/cast.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4d818f3ab21fea9f7e00a4ce2c8811367d839748
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/lowerer/cast.rs
@@ -0,0 +1,329 @@
+use crate::lowerer::*;
+use vvs_lang::ast::*;
+use vvs_llvm::*;
+use vvs_runtime_types::{types::*, vvll::LLVMExported};
+
+pub(super) struct CastLowerer<'a> {
+    llvm: LLVMLowerContext,
+
+    source: &'a Value,
+    from_type: &'a ASTType,
+    as_type: &'a ASTType,
+
+    ctx: &'a ValueContext,
+}
+
+/// Represents the value that was casted by the [CastLowerer] lowerer.
+#[derive(Debug)]
+pub(super) enum CastedValue {
+    /// A value can be [CastedValue::Unchanged] which means that we did nothing to it. you don't
+    /// need to register it again to trop it as it's nothing new...
+    Unchanged { value: Value },
+
+    /// A value can be [CastedValue::Dynamic] which means that we generated code to try to convert
+    /// the thing at runtime. The first element is the flag which is set to true if we did succeed,
+    /// false otherwise. This is an `i8` and must be checked at runtime. Because we created a
+    /// value, we muste register it to be dropped latter if needed.
+    Dynamic { flag: LLVMValueRef, value: Value },
+
+    /// A value can be [CastedValue::Static], which means that we did generate the code to cast the
+    /// thing and that we will always succeed. We still need to register this value to be dropped
+    /// if necessary...
+    Static { value: Value },
+}
+
+impl<'a> CastLowerer<'a> {
+    /// Create a new [CastLowerer] from an AST value.
+    pub fn from_ast(llvm: LLVMLowerContext, source: &'a ASTVar, as_type: &'a ASTType, ctx: &'a ValueContext) -> Self {
+        Self::from_llvm(llvm, ctx.get_value(source.name()), as_type, ctx)
+    }
+
+    /// Create a new [CastLowerer] from a LLVM value.
+    pub fn from_llvm(llvm: LLVMLowerContext, source: &'a Value, as_type: &'a ASTType, ctx: &'a ValueContext) -> Self {
+        Self { llvm, source, as_type, from_type: source.get_ast_type(), ctx }
+    }
+
+    /// Tells if the types are the same and we don't need to do the casting.
+    fn is_same_type(from: &ASTType, to: &ASTType) -> bool {
+        (to == from)
+            || (to.is_table() && from.is_table())
+            || (to.is_sequence() && from.is_sequence())
+            || (to.is_variant() && from.is_variant())
+    }
+
+    /// Lower in a static context, meaning that we assume that the casting process must succeed and
+    /// must not require a runtime check.
+    pub fn lower_static(self) -> CastedValue {
+        use ASTType::*;
+        let Self { llvm: llvm @ (_, c, b), source, from_type, as_type, ctx } = self;
+
+        if matches!(as_type, Nil) {
+            return CastedValue::Unchanged { value: ConstantLowerer::new(c, &ASTConst::Nil).lower() };
+        } else if Self::is_same_type(from_type, as_type) {
+            return CastedValue::Unchanged { value: source.clone() };
+        }
+
+        let loaded = source.loaded(c, b);
+        let store_into_ptr = |ty: ASTType, value: LLVMValueRef| unsafe {
+            let ptr = LLVMBuildAlloca(b, LLVMTypeOf(value), cstr!());
+            LLVMBuildStore(b, value, ptr);
+            CastedValue::Static { value: Value::Alloca(ty, LLVMTypeOf(value), ptr) }
+        };
+
+        macro_rules! build_into {
+            ($ty: ident: $conv: ident) => {
+                unsafe {
+                    let llvm_type = TypeLowerer::new(c, &$ty).lower();
+                    let ptr = LLVMBuildAlloca(b, llvm_type, cstr!());
+                    LLVMBuildStore(b, $conv(b, loaded, llvm_type, cstr!()), ptr);
+                    CastedValue::Static { value: Value::Alloca($ty, llvm_type, ptr) }
+                }
+            };
+        }
+
+        match from_type {
+            Nil => match as_type {
+                Integer => CastedValue::Static {
+                    value: Value::Const(Integer, unsafe {
+                        LLVMConstInt(TypeLowerer::new(c, &Integer).lower(), Default::default(), 0)
+                    }),
+                },
+                Floating => CastedValue::Static {
+                    value: Value::Const(Floating, unsafe {
+                        LLVMConstReal(TypeLowerer::new(c, &Floating).lower(), Default::default())
+                    }),
+                },
+                Boolean => CastedValue::Static {
+                    value: Value::Const(Boolean, unsafe {
+                        LLVMConstInt(TypeLowerer::new(c, &Boolean).lower(), Default::default(), 0)
+                    }),
+                },
+                ty if ty.is_table() => store_into_ptr(AnyTable, ctx.get_value("VVRTTable_new").call(b, [])),
+                ty if ty.is_sequence() => store_into_ptr(AnySequence, ctx.get_value("VVRTSeq_new").call(b, [])),
+                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_nil").call(b, [])),
+                as_type => panic!("can't convert `{from_type} into {as_type}`"),
+            },
+
+            Integer => match as_type {
+                Integer => CastedValue::Unchanged { value: source.clone() },
+                Boolean => build_into! { Boolean: LLVMBuildIntCast },
+                Floating => build_into! { Floating: LLVMBuildSIToFP },
+                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_from_integer").call(b, [loaded])),
+                as_type => panic!("can't convert `{from_type} into {as_type}`"),
+            },
+
+            Floating => match as_type {
+                Floating => CastedValue::Unchanged { value: source.clone() },
+                Integer => build_into! { Integer: LLVMBuildFPToSI },
+                Boolean => build_into! { Boolean: LLVMBuildFPToSI },
+                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_from_floating").call(b, [loaded])),
+                as_type => panic!("can't convert `{from_type} into {as_type}`"),
+            },
+
+            Boolean => match as_type {
+                Boolean => CastedValue::Unchanged { value: source.clone() },
+                Integer => build_into! { Integer: LLVMBuildIntCast },
+                Floating => build_into! { Floating: LLVMBuildSIToFP },
+                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_from_boolean").call(b, [loaded])),
+                as_type => panic!("can't convert `{from_type} into {as_type}`"),
+            },
+
+            ty if ty.is_sequence() => match as_type {
+                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_from_seq").call(b, [source.loaded(c, b)])),
+                as_type => panic!("can't convert `{from_type} into {as_type}`"),
+            },
+
+            Tuple(tuple) => match as_type {
+                Tuple(as_tuple) if tuple.len() == as_tuple.len() => unsafe {
+                    let as_llvm = TypeLowerer::new(c, as_type).lower();
+                    let from_tuple = TypeLowerer::new(c, from_type).lower();
+                    let ptr = LLVMBuildAlloca(b, as_llvm, cstr!());
+
+                    tuple.iter().enumerate().for_each(|(idx, from)| {
+                        // Get the value that we must coerce.
+                        let from_ptr = LLVMBuildStructGEP2(b, from_tuple, loaded, idx as u32, cstr!());
+                        let from_val = Value::Alloca(from.clone(), TypeLowerer::new(c, from).lower(), from_ptr);
+
+                        // Because of how we define tuples, we don't have to register the temp
+                        // values here, they should only be integers, floats or booleans.
+                        let value = match CastLowerer::from_llvm(llvm, &from_val, as_type, ctx).lower_static() {
+                            CastedValue::Unchanged { value } | CastedValue::Static { value } => value.loaded(c, b),
+                            casted => unreachable!("should have statically casted, got: {casted:?}"),
+                        };
+                        let mut idxs = [
+                            LLVMConstInt(LLVMInt32TypeInContext(c), 0, 0),
+                            LLVMConstInt(LLVMInt32TypeInContext(c), idx as u64, 0),
+                        ];
+                        let ptr = LLVMBuildGEP2(b, as_llvm, ptr, idxs.as_mut_ptr(), idxs.len() as u32, cstr!());
+                        LLVMBuildStore(b, value, ptr);
+                    });
+
+                    CastedValue::Static { value: Value::Alloca(as_type.clone(), as_llvm, ptr) }
+                },
+
+                ty if ty.is_numeric() && tuple.len() == 1 => unsafe {
+                    let from_val = Value::Alloca(
+                        tuple[0].clone(),
+                        TypeLowerer::new(c, &tuple[0]).lower(),
+                        LLVMBuildStructGEP2(b, TypeLowerer::new(c, from_type).lower(), loaded, 0, cstr!()),
+                    );
+                    CastLowerer::from_llvm(llvm, &from_val, ty, ctx).lower_static()
+                },
+
+                ty if ty.is_table() => unsafe {
+                    let table = ctx.get_value("VVRTTable_new").call(b, []);
+                    let from_tuple = TypeLowerer::new(c, from_type).lower();
+
+                    tuple.iter().enumerate().for_each(|(idx, from)| {
+                        let from_ptr = LLVMBuildStructGEP2(b, from_tuple, loaded, idx as u32, cstr!());
+                        let from_val = Value::Alloca(from.clone(), TypeLowerer::new(c, from).lower(), from_ptr);
+
+                        // Here we don't need to clone because we know that all types whithing a
+                        // tuple are trivially copiable.
+                        let value = match CastLowerer::from_llvm(llvm, &from_val, &Any, ctx).lower_static() {
+                            CastedValue::Unchanged { value } | CastedValue::Static { value } => value.loaded(c, b),
+                            casted => unreachable!("should have statically casted, got: {casted:?}"),
+                        };
+
+                        let key = idx.to_string();
+                        let (key, len) = (
+                            LLVMConstStringInContext(c, key.as_ptr() as *const _, key.len() as u32, 1),
+                            LLVMConstInt(LLVMInt32TypeInContext(c), key.len() as u64, 0),
+                        );
+                        ctx.get_value("VVRTTable_insert_from_raw_key")
+                            .call(b, [table, key, len, value]);
+                    });
+
+                    let ptr = LLVMBuildAlloca(b, VVRTTable::llvm_type(c), cstr!());
+                    LLVMBuildStore(b, table, ptr);
+                    CastedValue::Static { value: Value::Alloca(AnyTable, VVRTTable::llvm_type(c), ptr) }
+                },
+
+                ty if ty.is_sequence() => unsafe {
+                    let seq = ctx.get_value("VVRTSeq_new").call(b, []);
+                    let from_tuple = TypeLowerer::new(c, from_type).lower();
+
+                    tuple.iter().enumerate().for_each(|(idx, from)| {
+                        let from_ptr = LLVMBuildStructGEP2(b, from_tuple, loaded, idx as u32, cstr!());
+                        let from_val = Value::Alloca(from.clone(), TypeLowerer::new(c, from).lower(), from_ptr);
+
+                        // Here we don't need to clone because we know that all types whithing a
+                        // tuple are trivially copiable.
+                        let value = match CastLowerer::from_llvm(llvm, &from_val, &Any, ctx).lower_static() {
+                            CastedValue::Unchanged { value } | CastedValue::Static { value } => value.loaded(c, b),
+                            casted => unreachable!("should have statically casted, got: {casted:?}"),
+                        };
+
+                        ctx.get_value("VVRTSeq_push").call(b, [seq, value]);
+                    });
+
+                    let ptr = LLVMBuildAlloca(b, VVRTSeq::llvm_type(c), cstr!());
+                    LLVMBuildStore(b, seq, ptr);
+                    CastedValue::Static { value: Value::Alloca(AnySequence, VVRTSeq::llvm_type(c), ptr) }
+                },
+
+                as_type => panic!("can't convert `{from_type} into {as_type}`"),
+            },
+
+            ty if ty.is_variant() => match as_type {
+                as_type if as_type.is_table() => todo!(),
+                String => store_into_ptr(String, ctx.get_value("VVRTVariant_to_string").call(b, [loaded])),
+                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_from_variant").call(b, [loaded])),
+                as_type => panic!("can't convert `{from_type} into {as_type}`"),
+            },
+
+            // Forbiden casts or Dynamic casts
+            ty => panic!("can't cast a value of type `{ty}` or this type need a runtime check to do the cast"),
+        }
+    }
+
+    /// Try to do the lowering at runtime, if it failed we guarenty that the value will be nil and
+    /// that no values will need to be dropped. In case of success we calling function must
+    /// register the value in the context.
+    pub fn lower_dynamic(self) -> CastedValue {
+        use ASTType::*;
+        let Self { llvm: (_, c, b), source, from_type, as_type, ctx } = self;
+
+        if matches!(as_type, Nil) && !matches!(from_type, ASTType::Any) {
+            return CastedValue::Unchanged { value: ConstantLowerer::new(c, &ASTConst::Nil).lower() };
+        } else if Self::is_same_type(from_type, as_type) {
+            return CastedValue::Unchanged { value: source.clone() };
+        }
+
+        let loaded = source.loaded(c, b);
+        let store_into_ptr = |ty: ASTType, value: LLVMValueRef| unsafe {
+            let ptr = LLVMBuildAlloca(b, LLVMTypeOf(value), cstr!());
+            LLVMBuildStore(b, value, ptr);
+            Value::Alloca(ty, LLVMTypeOf(value), ptr)
+        };
+        let any_is_ty = |ty: VVRTType| {
+            ctx.get_value("VVRTAny_is_ty")
+                .call(b, [loaded, unsafe { ty.as_llvm_const(c) }])
+        };
+
+        match from_type {
+            ty if ty.is_table() => match as_type {
+                Any => CastedValue::Static {
+                    value: store_into_ptr(Any, ctx.get_value("VVRTAny_from_table").call(b, [loaded])),
+                },
+                ty if ty.is_variant() => todo!(),
+                ty if ty.is_sequence() => todo!(),
+                as_type => panic!("can't convert `{from_type} into {as_type}`"),
+            },
+
+            // Get value out of any.
+            Any => match as_type {
+                Nil => CastedValue::Dynamic {
+                    flag: any_is_ty(VVRTType::Nil),
+                    value: ConstantLowerer::new(c, &ASTConst::Nil).lower(),
+                },
+                Integer => CastedValue::Dynamic {
+                    flag: any_is_ty(VVRTType::Number),
+                    value: store_into_ptr(Integer, ctx.get_value("VVRTAny_maybe_as_integer").call(b, [loaded])),
+                },
+                Boolean => CastedValue::Dynamic {
+                    flag: any_is_ty(VVRTType::Number),
+                    value: store_into_ptr(Boolean, ctx.get_value("VVRTAny_maybe_as_boolean").call(b, [loaded])),
+                },
+                Floating => CastedValue::Dynamic {
+                    flag: any_is_ty(VVRTType::Number),
+                    value: store_into_ptr(Floating, ctx.get_value("VVRTAny_maybe_as_floating").call(b, [loaded])),
+                },
+                String => {
+                    let val = ctx.get_value("VVRTAny_maybe_as_string").call(b, [loaded]);
+                    let val = ctx.get_value("VVRTString_clone").call(b, [val]);
+                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::String), value: store_into_ptr(String, val) }
+                }
+                Syllabe => {
+                    let val = ctx.get_value("VVRTAny_maybe_as_syllabe").call(b, [loaded]);
+                    let val = ctx.get_value("VVRTSyllabe_clone").call(b, [val]);
+                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::ASSSyllabe), value: store_into_ptr(Syllabe, val) }
+                }
+                Line => {
+                    let val = ctx.get_value("VVRTAny_maybe_as_line").call(b, [loaded]);
+                    let val = ctx.get_value("VVRTLine_clone").call(b, [val]);
+                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::ASSLine), value: store_into_ptr(Line, val) }
+                }
+                ty if ty.is_variant() => {
+                    let val = ctx.get_value("VVRTAny_maybe_as_variant").call(b, [loaded]);
+                    let val = ctx.get_value("VVRTVariant_clone").call(b, [val]);
+                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::Variant), value: store_into_ptr(Variant, val) }
+                }
+                ty if ty.is_table() => {
+                    let val = ctx.get_value("VVRTAny_maybe_as_table").call(b, [loaded]);
+                    let val = ctx.get_value("VVRTTable_clone").call(b, [val]);
+                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::Table), value: store_into_ptr(AnyTable, val) }
+                }
+                ty if ty.is_sequence() => {
+                    let val = ctx.get_value("VVRTAny_maybe_as_seq").call(b, [loaded]);
+                    let val = ctx.get_value("VVRTSeq_clone").call(b, [val]);
+                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::Seq), value: store_into_ptr(AnySequence, val) }
+                }
+                as_type => panic!("can't convert `{from_type} into {as_type}`"),
+            },
+
+            // Don't need to perform a runtime check to do the cast, use the lower function
+            _ => self.lower_static(),
+        }
+    }
+}
diff --git a/src/Rust/vvs_codegen/src/lowerer/constant.rs b/src/Rust/vvs_codegen/src/lowerer/constant.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e8a67e172b4a79b50f9220d9f8d260570c289dc9
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/lowerer/constant.rs
@@ -0,0 +1,59 @@
+use crate::Value;
+use std::mem;
+use vvs_lang::ast::*;
+use vvs_llvm::*;
+
+/// Lower a single constant. We only need the LLVM context what should be the type...
+pub(crate) struct ConstantLowerer<'a> {
+    /// The context.
+    c: LLVMContextRef,
+
+    /// We expression we want to lower.
+    constant: &'a ASTConst,
+}
+
+impl<'a> ConstantLowerer<'a> {
+    /// Create a new constant expression lowerer.
+    pub fn new(c: LLVMContextRef, constant: &'a ASTConst) -> Self {
+        Self { c, constant }
+    }
+
+    /// Create a sub-lowerer, for constants that need a recursive descent.
+    fn sub_lowerer(&self, constant: &'a ASTConst) -> Self {
+        Self { c: self.c, constant }
+    }
+
+    /// Lower the constant.
+    pub fn lower(self) -> Value {
+        let Self { c, constant } = self;
+        let ty = constant.get_const_type();
+        use {ASTConst::*, Value::*};
+        unsafe {
+            match constant {
+                ASTConst::Nil => Const(ty, LLVMConstPointerNull(LLVMInt64TypeInContext(c))),
+                False => Const(ty, LLVMConstInt(LLVMInt1TypeInContext(c), 0, 0)),
+                True => Const(ty, LLVMConstInt(LLVMInt1TypeInContext(c), 1, 0)),
+                Floating(f) => Const(ty, LLVMConstReal(LLVMFloatTypeInContext(c), *f as f64)),
+                String(s) => {
+                    let (ptr, len) = (s.as_bytes().as_ptr() as *const _, s.len().try_into().unwrap());
+                    Const(ty, LLVMConstString(ptr, len, 1))
+                }
+                Integer(i) => {
+                    let int = mem::transmute::<i64, u64>(*i as i64);
+                    Const(ty, LLVMConstInt(LLVMInt32TypeInContext(c), int, 1))
+                }
+                Tuple(inner) => {
+                    let i = inner.iter().map(|cnst| match self.sub_lowerer(cnst).lower() {
+                        Value::Const(_, val) => val,
+                        val => unreachable!("expected a constant, got {val:?}"),
+                    });
+                    let mut i = i.collect::<Vec<_>>();
+                    let (ptr, len) = (i.as_mut_ptr(), i.len().try_into().unwrap());
+                    Const(ty, LLVMConstStructInContext(c, ptr, len, 0))
+                }
+                Color(_) => panic!("need to implement colors"),
+                Table(_) => panic!("need to implement tables"),
+            }
+        }
+    }
+}
diff --git a/src/Rust/vvs_codegen/src/lowerer/drops.rs b/src/Rust/vvs_codegen/src/lowerer/drops.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3c56022ce8c6dbb584e167ec7f7ce30ea4ab3989
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/lowerer/drops.rs
@@ -0,0 +1,109 @@
+use crate::{value::Value, Graph, ValueContext};
+use std::collections::BTreeSet;
+use vvs_llvm::*;
+
+/// Drop all the values in the correct order at the end of a given basic block. We take into
+/// account any terminator of said basic block.
+pub(super) struct DropLowerer<'a> {
+    /// The context.
+    c: LLVMContextRef,
+
+    /// Our own builder.
+    b: LLVMBuilderRef,
+
+    /// The values to drop, they are in the order of their declaration. We drop them in the reverse
+    /// order!
+    values: &'a [Value],
+
+    /// The function from which the values must be dropped.
+    func: LLVMValueRef,
+
+    /// The basic block to use to drop things. We will create our own builder to do the thing, so
+    /// we don't need others things to pass their builder.
+    bb: LLVMBasicBlockRef,
+
+    /// The value context.
+    ctx: &'a ValueContext,
+}
+
+impl<'a> DropLowerer<'a> {
+    /// Create a new lowerer to drop the specified values from a given function at the end of a
+    /// given basic block.
+    ///
+    /// # Safety
+    /// All the values must have been declared inside the passed the function. The basic block must
+    /// be from the passed function.
+    pub unsafe fn new(
+        c: LLVMContextRef,
+        func: LLVMValueRef,
+        values: &'a [Value],
+        bb: LLVMBasicBlockRef,
+        ctx: &'a ValueContext,
+    ) -> Self {
+        let b = unsafe { LLVMCreateBuilderInContext(c) };
+        Self { c, b, values, func, bb, ctx }
+    }
+
+    pub fn lower(self) {
+        use LLVMOpcode::*;
+        let Self { c, b, values, bb, func, ctx } = self;
+
+        // Position the builder correcly.
+
+        unsafe {
+            match LLVMGetLastInstruction(bb) {
+                last if last.is_null() => LLVMPositionBuilderAtEnd(b, bb),
+                last => match LLVMGetInstructionOpcode(last) {
+                    LLVMRet | LLVMBr | LLVMSwitch | LLVMIndirectBr | LLVMCallBr => LLVMPositionBuilderBefore(b, last),
+                    _ => LLVMPositionBuilderAtEnd(b, bb),
+                },
+            };
+        };
+
+        // Get the dominance graph to filter the values that we must really drop here!
+
+        let bbs_iter = unsafe { LLVMFunctionIter::new(func) };
+        let bbs = Graph::with_capacity(bbs_iter.count()).add_nodes(bbs_iter);
+        let bbs = bbs_iter.fold(bbs, |bbs, bb| unsafe {
+            match LLVMBasicBlockIter::new(bb).last() {
+                Some(instr) => match LLVMGetInstructionOpcode(instr) {
+                    LLVMBr => match LLVMGetNumOperands(instr) {
+                        1 => bbs.add_edge(bb, LLVMValueAsBasicBlock(LLVMGetOperand(instr, 0))),
+                        3 => bbs
+                            .add_edge(bb, LLVMValueAsBasicBlock(LLVMGetOperand(instr, 1)))
+                            .add_edge(bb, LLVMValueAsBasicBlock(LLVMGetOperand(instr, 2))),
+                        n => unreachable!("got br instruction with {n} operands"),
+                    },
+                    LLVMSwitch => todo!("handle switch, got {} operands", LLVMGetNumOperands(instr)),
+                    LLVMIndirectBr => todo!("handle indirectbr, got {} operands", LLVMGetNumOperands(instr)),
+                    _ => bbs,
+                },
+                None => bbs,
+            }
+        });
+
+        // Filter the values that we must really delete and call the destructors. We can destroy
+        // the values in any order because things are reference-counted. Also, just drop the values
+
+        let declared_values: BTreeSet<LLVMValueRef> = unsafe {
+            bbs.any_path_content(LLVMGetEntryBasicBlock(func), bb)
+                .into_iter()
+                .flat_map(|bb| LLVMBasicBlockIter::new(bb))
+                .collect()
+        };
+
+        values
+            .iter()
+            .filter(|val| val.llvm_value().map_or(false, |val| declared_values.contains(&val)))
+            .flat_map(|val| val.get_dropper_name().map(|drop| (val, drop)))
+            .for_each(|(val, drop)| {
+                ctx.get_value(drop).call(b, [val.loaded(c, b)]);
+            });
+    }
+}
+
+impl<'a> Drop for DropLowerer<'a> {
+    fn drop(&mut self) {
+        unsafe { LLVMDisposeBuilder(self.b) };
+    }
+}
diff --git a/src/Rust/vvs_codegen/src/lowerer/expression.rs b/src/Rust/vvs_codegen/src/lowerer/expression.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6caad5f2c15a085be5979fb43d4404eb4dc43c9c
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/lowerer/expression.rs
@@ -0,0 +1,347 @@
+use crate::{lowerer::*, Value, ValueContext};
+use vvs_lang::ast::*;
+use vvs_llvm::{LLVMIntPredicate::*, LLVMRealPredicate::*, *};
+use vvs_runtime_types::{
+    types::{VVRTString, VVRTTable},
+    vvll::LLVMExported,
+};
+use vvs_utils::either;
+
+/// Lower a single expression.
+pub(super) struct ExpressionLowerer<'a> {
+    llvm: LLVMLowerContext,
+
+    /// We expression we want to lower.
+    expr: &'a ASTExpr,
+
+    /// The expected type, to see if we need to generate coertion.
+    as_type: Option<&'a ASTType>,
+
+    /// The value context, this stores available already-lowered LLVM values.
+    ctx: &'a ValueContext,
+}
+
+impl<'a> ExpressionLowerer<'a> {
+    /// Create a new expression lowerer.
+    pub(super) fn with_assumed_type(llvm: LLVMLowerContext, expr: &'a ASTExpr, ctx: &'a ValueContext) -> Self {
+        Self { llvm, expr, as_type: None, ctx }
+    }
+
+    /// Create a new expression lowerer with an expected type for the lowered expression. If needed
+    /// the lower process will call [CastLowerer].
+    pub(super) fn with_expected_type(
+        llvm: LLVMLowerContext,
+        expr: &'a ASTExpr,
+        as_type: &'a ASTType,
+        ctx: &'a ValueContext,
+    ) -> Self {
+        Self { llvm, expr, as_type: Some(as_type), ctx }
+    }
+
+    /// Overwrite the used [ValueContext] used to do the lowering.
+    pub(super) fn with_ctx(mut self, ctx: &'a ValueContext) -> Self {
+        self.ctx = ctx;
+        self
+    }
+
+    /// Set the type that is expected by the expression, calling the [CastLowerer] if needed!
+    pub(super) fn into_type(mut self, ty: &'a ASTType) -> Self {
+        self.as_type = Some(ty);
+        self
+    }
+
+    /// Create a new sub-expression lowerer. Used for recusive descent to lower complexe
+    /// expressions, thus private.
+    fn sub_lowerer(&self, expr: &'a ASTExpr) -> Self {
+        let Self { llvm, ctx, .. } = *self;
+        Self { llvm, expr, as_type: None, ctx }
+    }
+
+    /// Lower an equality.
+    unsafe fn lower_equality(
+        llvm @ (_, c, b): LLVMLowerContext,
+        ctx: &ValueContext,
+        (l, lty): (LLVMValueRef, &ASTType),
+        (r, rty): (LLVMValueRef, &ASTType),
+    ) -> LLVMValueRef {
+        use ASTType::*;
+        match lty {
+            Nil => LLVMConstInt(LLVMInt1TypeInContext(c), 1, 0),
+            Boolean | Integer => LLVMBuildICmp(b, LLVMIntEQ, l, r, cstr!()),
+            Floating => {
+                let flt = LLVMFloatTypeInContext(c);
+                let diff = LLVMBuildFSub(b, l, r, c"".as_ptr());
+                let diff = CallLowerer::call_intrinsic("llvm.fabs.f32", llvm, flt, [diff]);
+                LLVMBuildFCmp(b, LLVMRealOLE, diff, LLVMConstReal(flt, 10e-5), c"".as_ptr())
+            }
+
+            Tuple(lt) => match rty {
+                Tuple(rt) if lt.len() == rt.len() => lt.iter().zip(rt).enumerate().fold(
+                    LLVMConstInt(LLVMInt1TypeInContext(c), 1, 0),
+                    |acc, (idx, (lt, rt))| {
+                        let idx = idx.try_into().expect("too many elements");
+                        let l = LLVMBuildStructGEP2(b, LLVMTypeOf(l), l, idx, cstr!());
+                        let r = LLVMBuildStructGEP2(b, LLVMTypeOf(r), r, idx, cstr!());
+                        let ret = Self::lower_equality(llvm, ctx, (l, lt), (r, rt));
+                        LLVMBuildAnd(b, ret, acc, cstr!())
+                    },
+                ),
+                _ => LLVMConstInt(LLVMInt1TypeInContext(c), 0, 0),
+            },
+
+            Any => ctx.get_value("VVRTAny_eq").call(b, [l, r]),
+            Line => ctx.get_value("VVRTLine_eq").call(b, [l, r]),
+            String => ctx.get_value("VVRTString_eq").call(b, [l, r]),
+            Syllabe => ctx.get_value("VVRTSyllabe_eq").call(b, [l, r]),
+            ty if ty.is_sequence() => ctx.get_value("VVRTSeq_eq").call(b, [l, r]),
+            ty if ty.is_variant() => ctx.get_value("VVRTVariant_eq").call(b, [l, r]),
+            ty if ty.is_table() => ctx.get_value("VVRTTable_eq").call(b, [l, r]),
+
+            _ => panic!("can't apply `{:?}` to expressions of type `{lty}` and `{rty}`", ASTBinop::CmpEQ),
+        }
+    }
+
+    /// Lower the value into LLVM-IR at the position specified by the builder passed at
+    /// construction time. If any value is created it will be added in the returned [ValueContext].
+    pub(super) fn lower(self) -> (ValueContext, Value) {
+        let Self { llvm: llvm @ (_, c, b), expr: ASTExpr { content, .. }, as_type, ctx } = self;
+        let (bln, int, flt) = (unsafe { LLVMInt1TypeInContext(c) }, unsafe { LLVMInt32TypeInContext(c) }, unsafe {
+            LLVMFloatTypeInContext(c)
+        });
+        let (false_, true_, zero_, one_) = (
+            unsafe { LLVMConstInt(bln, 0, 0) },
+            unsafe { LLVMConstInt(bln, 1, 0) },
+            unsafe { LLVMConstInt(int, 0, 0) },
+            unsafe { LLVMConstInt(int, 1, 0) },
+        );
+        let store_scalar = |ctx: ValueContext, val: LLVMValueRef, ty: LLVMTypeRef, ast: ASTType| unsafe {
+            let ptr = LLVMBuildAlloca(b, ty, cstr!());
+            LLVMBuildStore(b, val, ptr);
+            (ctx, Value::Alloca(ast, ty, ptr))
+        };
+
+        match content {
+            ASTExprVariant::Var(var) => (ctx.clone(), ctx.get_value(var.name()).clone()),
+
+            ASTExprVariant::Const(value) => {
+                let value = ConstantLowerer::new(c, value).lower();
+                match as_type {
+                    Some(expected_type) if expected_type != value.get_ast_type() => {
+                        match CastLowerer::from_llvm(llvm, &value, expected_type, ctx).lower_static() {
+                            CastedValue::Unchanged { value } => (ctx.clone(), value),
+                            CastedValue::Static { value } => (ctx.to_register_anon(value.clone()), value),
+                            CastedValue::Dynamic { .. } => unreachable!(),
+                        }
+                    }
+                    _ => (ctx.clone(), value),
+                }
+            }
+
+            ASTExprVariant::Tuple(tuple) => unsafe {
+                let (mut lowered_tuple, mut types, mut tuple_ty) =
+                    (Vec::with_capacity(tuple.len()), Vec::with_capacity(tuple.len()), Vec::with_capacity(tuple.len()));
+
+                let ctx = tuple.iter().fold(self.ctx.clone(), |ctx, item| {
+                    let (ctx, expr) = self.sub_lowerer(item).with_ctx(&ctx).lower();
+                    let (ast_type, expr) = (expr.get_ast_type(), expr.loaded(c, b));
+                    lowered_tuple.push(expr);
+                    types.push(LLVMTypeOf(expr));
+                    tuple_ty.push(ast_type.clone());
+                    ctx
+                });
+
+                let tuple_len = types.len().try_into().expect("too many elements");
+                let types = LLVMStructTypeInContext(c, types.as_mut_ptr(), tuple_len, 0);
+                let tuple_ptr = LLVMBuildAlloca(b, types, c"".as_ptr());
+
+                for (idx, val) in lowered_tuple.into_iter().enumerate() {
+                    let idx = idx.try_into().expect("too many elements");
+                    let ptr = LLVMBuildStructGEP2(b, types, tuple_ptr, idx, c"".as_ptr());
+                    LLVMBuildStore(b, val, ptr);
+                }
+
+                (ctx, Value::Alloca(ASTType::Tuple(tuple_ty), types, tuple_ptr))
+            },
+
+            ASTExprVariant::Table(table) => unsafe {
+                let ty = VVRTTable::llvm_type(c);
+                let ptr = LLVMBuildAlloca(b, ty, c"".as_ptr());
+                LLVMBuildStore(b, ctx.get_value("VVRTTable_new").call(b, []), ptr);
+                let mut ctx = table.iter().fold(self.ctx.clone(), |_, (key, value)| {
+                    // Static key! The table will create it's own string.
+                    let key_len: u32 = key.len().try_into().expect("too many elements");
+                    let key = LLVMConstStringInContext(c, key.as_ptr() as *const _, key_len, 1);
+                    let key_len = LLVMConstInt(LLVMInt32TypeInContext(c), key_len as u64, 0);
+
+                    // Lower the value and cast it into an Any.
+                    let (mut ctx, value) = self.sub_lowerer(value).into_type(&ASTType::Any).lower();
+                    let value = value.loaded(c, b);
+                    ctx.forget_by_llvm_value(value);
+
+                    // Insert the value with the correct key.
+                    ctx.get_value("VVRTTable_insert_from_raw_key")
+                        .call(b, [ptr, key, key_len, value]);
+                    ctx
+                });
+                let value = Value::Alloca(ASTType::AnyTable, ty, ptr);
+                ctx.register_anon(value.clone());
+                (ctx, value)
+            },
+
+            ASTExprVariant::FuncCall(func, args) => {
+                let (ctx, value) = CallLowerer::new(llvm, self.ctx).lower_func_call(func, args);
+                (ctx.to_register_anon(value.clone()), value)
+            }
+            ASTExprVariant::MethodInvok(obj, method, args) => {
+                let (ctx, value) = CallLowerer::new(llvm, self.ctx).lower_method_invok(obj, method, args);
+                (ctx.to_register_anon(value.clone()), value)
+            }
+
+            ASTExprVariant::Unop(op, inner) => unsafe {
+                use vvs_lang::ast::{ASTType::*, ASTUnop::*};
+
+                let (ctx, inner) = match as_type {
+                    Some(ty) => self.sub_lowerer(inner).into_type(ty).lower(),
+                    None => self.sub_lowerer(inner).lower(),
+                };
+                let (ty, inner) = (inner.get_ast_type(), inner.loaded(c, b));
+                let call_len = |ctx: ValueContext, func: &str| {
+                    let value = ctx.get_value(func).call(b, [inner]);
+                    store_scalar(ctx, value, int, Integer)
+                };
+
+                match op {
+                    LogicNot | BitNot | Neg if matches!(ty, Boolean) => {
+                        let cmp = LLVMBuildICmp(b, LLVMIntEQ, inner, false_, cstr!());
+                        let res = LLVMBuildSelect(b, cmp, true_, false_, cstr!());
+                        store_scalar(ctx, res, bln, Boolean)
+                    }
+
+                    LogicNot if matches!(ty, Integer) => {
+                        let cmp = LLVMBuildICmp(b, LLVMIntEQ, inner, zero_, cstr!());
+                        let res = LLVMBuildSelect(b, cmp, one_, zero_, cstr!());
+                        store_scalar(ctx, res, int, Integer)
+                    }
+
+                    BitNot if matches!(ty, Integer) => {
+                        let res = CallLowerer::call_intrinsic("llvm.bitreverse.i32", llvm, int, [inner]);
+                        store_scalar(ctx, res, int, Integer)
+                    }
+
+                    #[rustfmt::skip] Neg if matches!(ty, Integer ) => store_scalar(ctx, LLVMBuildNeg (b, inner, cstr!()), int, Integer ),
+                    #[rustfmt::skip] Neg if matches!(ty, Floating) => store_scalar(ctx, LLVMBuildFNeg(b, inner, cstr!()), flt, Floating),
+
+                    #[rustfmt::skip] Len => match ty {
+                        Line                   => call_len(ctx, "VVRTLine_len"),
+                        String                 => call_len(ctx, "VVRTString_len"),
+                        Syllabe                => call_len(ctx, "VVRTSyllabe_len"),
+                        ty if ty.is_sequence() => call_len(ctx, "VVRTSeq_len"),
+                        ty if ty.is_table()    => call_len(ctx, "VVRTTable_len"),
+                        Tuple(len) => {
+                            let len = TryInto::<i32>::try_into(len.len()).expect("too many elements") as u64;
+                            (ctx, Value::Const(Integer, LLVMConstInt(int, len, 0)))
+                        }
+                        ty => panic!("can't apply `{op:?}` to expression of type `{ty}`"),
+                    },
+
+                    op => panic!("can't apply `{op:?}` to expression of type `{ty}`"),
+                }
+            },
+
+            ASTExprVariant::Binop(left, op, right) => unsafe {
+                use vvs_lang::ast::{ASTBinop::*, ASTType::*};
+
+                let (ctx, left) = match as_type {
+                    Some(ty) => self.sub_lowerer(left).into_type(ty).lower(),
+                    None => self.sub_lowerer(left).lower(),
+                };
+                let lty = left.get_ast_type();
+                let (ctx, right) = self
+                    .sub_lowerer(right)
+                    .into_type(either!(*op == Power => &Integer; lty))
+                    .with_ctx(&ctx)
+                    .lower();
+                let (l, r, rty) = (left.loaded(c, b), right.loaded(c, b), right.get_ast_type());
+                let (is_int, is_flt, is_bln) =
+                    (matches!(lty, Integer), matches!(lty, Floating), matches!(lty, Boolean));
+
+                let (res, ty, ast) = match op {
+                    Power if is_int => todo!(),
+                    Power if is_flt => todo!(),
+
+                    #[rustfmt::skip] Mul if is_int => (LLVMBuildMul (b, l, r, cstr!()), int, Integer),
+                    #[rustfmt::skip] Div if is_int => (LLVMBuildSDiv(b, l, r, cstr!()), int, Integer),
+                    #[rustfmt::skip] Add if is_int => (LLVMBuildAdd (b, l, r, cstr!()), int, Integer),
+                    #[rustfmt::skip] Sub if is_int => (LLVMBuildSub (b, l, r, cstr!()), int, Integer),
+
+                    #[rustfmt::skip] Mul if is_flt => (LLVMBuildFMul(b, l, r, cstr!()), flt, Floating),
+                    #[rustfmt::skip] Div if is_flt => (LLVMBuildFDiv(b, l, r, cstr!()), flt, Floating),
+                    #[rustfmt::skip] Add if is_flt => (LLVMBuildFAdd(b, l, r, cstr!()), flt, Floating),
+                    #[rustfmt::skip] Sub if is_flt => (LLVMBuildFSub(b, l, r, cstr!()), flt, Floating),
+
+                    #[rustfmt::skip] Mod if is_int => (LLVMBuildSRem(b, l, r, cstr!()), int, Integer ),
+                    #[rustfmt::skip] Mod if is_flt => (LLVMBuildFRem(b, l, r, cstr!()), flt, Floating),
+
+                    #[rustfmt::skip] StrCat if matches!(lty, String) => {
+                        (ctx.get_value("VVRTString_cat").call(b, [l, r]), VVRTString::llvm_type(c), String)
+                    },
+
+                    #[rustfmt::skip] CmpLE if is_int => (LLVMBuildICmp(b, LLVMIntSLE,  l, r, cstr!()), bln, Boolean),
+                    #[rustfmt::skip] CmpLT if is_int => (LLVMBuildICmp(b, LLVMIntSLT,  l, r, cstr!()), bln, Boolean),
+                    #[rustfmt::skip] CmpGE if is_int => (LLVMBuildICmp(b, LLVMIntSGE,  l, r, cstr!()), bln, Boolean),
+                    #[rustfmt::skip] CmpGT if is_int => (LLVMBuildICmp(b, LLVMIntSGT,  l, r, cstr!()), bln, Boolean),
+
+                    #[rustfmt::skip] CmpLE if is_flt => (LLVMBuildFCmp(b, LLVMRealOLE, l, r, cstr!()), flt, Floating),
+                    #[rustfmt::skip] CmpLT if is_flt => (LLVMBuildFCmp(b, LLVMRealOLT, l, r, cstr!()), flt, Floating),
+                    #[rustfmt::skip] CmpGE if is_flt => (LLVMBuildFCmp(b, LLVMRealOGE, l, r, cstr!()), flt, Floating),
+                    #[rustfmt::skip] CmpGT if is_flt => (LLVMBuildFCmp(b, LLVMRealOGT, l, r, cstr!()), flt, Floating),
+
+                    #[rustfmt::skip] BitAnd | LogicAnd if is_bln => (LLVMBuildAnd(b, l, r, cstr!()), bln, Boolean),
+                    #[rustfmt::skip] BitXor | LogicXor if is_bln => (LLVMBuildXor(b, l, r, cstr!()), bln, Boolean),
+                    #[rustfmt::skip] BitOr  | LogicOr  if is_bln => (LLVMBuildOr (b, l, r, cstr!()), bln, Boolean),
+
+                    #[rustfmt::skip] BitAnd   if is_int => (LLVMBuildAnd(b, l, r, cstr!()), int, Integer),
+                    #[rustfmt::skip] BitXor   if is_int => (LLVMBuildXor(b, l, r, cstr!()), int, Integer),
+                    #[rustfmt::skip] BitOr    if is_int => (LLVMBuildOr (b, l, r, cstr!()), int, Integer),
+                    #[rustfmt::skip] LogicAnd if is_int => (LLVMBuildICmp(b, LLVMIntEQ, LLVMBuildAnd(b, l, r, cstr!()), one_, cstr!()), bln, Boolean),
+                    #[rustfmt::skip] LogicXor if is_int => (LLVMBuildICmp(b, LLVMIntEQ, LLVMBuildXor(b, l, r, cstr!()), one_, cstr!()), bln, Boolean),
+                    #[rustfmt::skip] LogicOr  if is_int => (LLVMBuildICmp(b, LLVMIntEQ, LLVMBuildOr (b, l, r, cstr!()), one_, cstr!()), bln, Boolean),
+
+                    #[rustfmt::skip] BitShiftLeft  if is_int => (LLVMBuildShl (b, l, r, cstr!()), int, Integer),
+                    #[rustfmt::skip] BitShiftRight if is_int => (LLVMBuildAShr(b, l, r, cstr!()), int, Integer),
+
+                    CmpEQ => (Self::lower_equality(llvm, &ctx, (l, lty), (r, rty)), bln, Boolean),
+                    CmpNE => {
+                        let not = Self::lower_equality(llvm, &ctx, (l, lty), (r, rty));
+                        (LLVMBuildNot(b, not, cstr!()), bln, Boolean)
+                    }
+
+                    op => panic!("can't apply `{op:?}` to expressions of type `{lty}` and `{rty}`"),
+                };
+                store_scalar(ctx, res, ty, ast)
+            },
+
+            ASTExprVariant::Suffixed(table, _fields) => {
+                let (_ctx, _table) = self.sub_lowerer(table).lower();
+                todo!()
+            }
+
+            ASTExprVariant::Color(variant) | ASTExprVariant::Movement(variant) => {
+                let mut arguments = Vec::with_capacity(variant.args_len());
+                let _ctx = variant.args().iter().fold(ctx.clone(), |ctx, expr| {
+                    let (ctx, expr) = self.sub_lowerer(expr).with_ctx(&ctx).lower();
+                    arguments.push(expr);
+                    ctx
+                });
+                let _variant = variant.variant();
+
+                todo!()
+            }
+
+            ASTExprVariant::Default(_) => todo!(),
+
+            // See later for clozures
+            ASTExprVariant::FuncBind(_, _) => unreachable!(),
+        }
+    }
+}
diff --git a/src/Rust/vvs_codegen/src/lowerer/function.rs b/src/Rust/vvs_codegen/src/lowerer/function.rs
new file mode 100644
index 0000000000000000000000000000000000000000..fd8ab0870c39c666eb0cdde6db946863bbc44892
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/lowerer/function.rs
@@ -0,0 +1,55 @@
+use crate::{lowerer::*, ValueContext};
+use vvs_lang::ast::*;
+use vvs_llvm::*;
+
+pub(super) struct FunctionLowerer<'a> {
+    llvm: LLVMLowerContext,
+
+    /// The global context, we store a reference, then we will add it the arguments of the
+    /// function.
+    ctx: &'a ValueContext,
+
+    /// The llvm function.
+    value: LLVMValueRef,
+
+    /// The vivy function.
+    function: &'a ASTFunction,
+}
+
+impl<'a> FunctionLowerer<'a> {
+    pub fn new(llvm: LLVMLowerContext, ctx: &'a ValueContext, v: LLVMValueRef, f: &'a ASTFunction) -> Self {
+        Self { llvm, ctx, value: v, function: f }
+    }
+
+    pub fn lower(self) {
+        let Self { llvm: llvm @ (_, c, b), value, function, .. } = self;
+        let ASTFunction { arguments, content, returns, .. } = function;
+        let mut ctx = self.ctx.clone();
+
+        let mut ctx = unsafe {
+            LLVMPositionBuilderAtEnd(b, LLVMAppendBasicBlockInContext(c, value, c"entry".as_ptr()));
+            for (idx, arg) in arguments.iter().enumerate() {
+                let ty = arg
+                    .get_specified_type()
+                    .expect("the type should be specified at this point");
+                let llvm_ty = TypeLowerer::new(c, ty).lower();
+                let arg_name = CString::new(arg.name().as_ref()).expect("invalid name");
+                let arg_param = LLVMGetParam(value, idx.try_into().expect("too many arguments"));
+                let ptr = LLVMBuildAlloca(b, llvm_ty, arg_name.as_ptr());
+                LLVMBuildStore(b, arg_param, ptr);
+                ctx.register(arg.name(), Value::Alloca(ty.clone(), llvm_ty, ptr));
+            }
+
+            InstructionLowerer::new(llvm, value, content, returns.clone(), ctx).lower()
+        };
+
+        let to_drop = ctx.get_values_to_drop();
+        unsafe { LLVMFunctionIter::new(value) }
+            .filter(|&bb| unsafe {
+                LLVMBasicBlockIter::new(bb)
+                    .last()
+                    .map_or(false, |instr| LLVMGetInstructionOpcode(instr) == LLVMOpcode::LLVMRet)
+            })
+            .for_each(|bb| unsafe { DropLowerer::new(c, value, &to_drop, bb, &ctx) }.lower());
+    }
+}
diff --git a/src/Rust/vvs_codegen/src/lowerer/instruction.rs b/src/Rust/vvs_codegen/src/lowerer/instruction.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d731bfd93a73079e4cfa7e933da62f6f7fae92bb
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/lowerer/instruction.rs
@@ -0,0 +1,431 @@
+use crate::lowerer::*;
+use std::sync::OnceLock;
+use vvs_lang::{anon_expression, anon_instruction, ast::*};
+use vvs_llvm::*;
+use vvs_utils::either;
+
+#[derive(Clone, Copy)]
+struct BBLoop {
+    body_entry: LLVMBasicBlockRef,
+    loop_exit: LLVMBasicBlockRef,
+}
+
+/// Lower a single instruction.
+pub(super) struct InstructionLowerer<'a> {
+    llvm: LLVMLowerContext,
+
+    /// The function containing the instruction to lower.
+    func: LLVMValueRef,
+
+    /// Remeber the last loop to be able to break or continue.
+    last_loop: Option<BBLoop>,
+
+    /// The instruction we want to lower.
+    instr: &'a ASTInstr,
+
+    /// The return type of the function, to see if we need to generetate coertion.
+    func_return_type: ASTType,
+
+    /// The value context, this stores available already-lowered LLVM values.
+    ctx: ValueContext,
+}
+
+impl<'a> InstructionLowerer<'a> {
+    /// Create a new expression lowerer.
+    pub(super) fn new(
+        llvm: LLVMLowerContext,
+        func: LLVMValueRef,
+        instruction: &'a ASTInstr,
+        func_return_type: ASTType,
+        ctx: ValueContext,
+    ) -> Self {
+        let last_loop = Default::default();
+        Self { llvm, func, instr: instruction, func_return_type, ctx, last_loop }
+    }
+
+    /// Create a new sub-expression lowerer. Used for recusive descent to lower complexe
+    /// expressions, thus private.
+    fn sub_lowerer(&self, instruction: &'a ASTInstr) -> Self {
+        let Self { llvm, func, last_loop, .. } = *self;
+        let func_return_type = self.func_return_type.clone();
+        let ctx = self.ctx.clone();
+        Self { llvm, instr: instruction, func, func_return_type, ctx, last_loop }
+    }
+
+    /// Short-hand to create an expression lowerer by passing some arguments correctly.
+    fn expr(&'a self, expr: &'a ASTExpr) -> ExpressionLowerer<'a> {
+        ExpressionLowerer::with_assumed_type(self.llvm, expr, &self.ctx)
+    }
+
+    /// Get a new sub-expression lowerer. We need to know the exit block of this scope so that we
+    /// can build the calls to drop for this scope.
+    fn scoped_lowerer(&mut self, exit_bb: LLVMBasicBlockRef, cb: impl FnOnce(Self) -> ValueContext) {
+        static mut NOOP: OnceLock<ASTInstr> = OnceLock::new();
+
+        // Save context.
+        let pre_ctx = self.ctx.clone();
+        self.ctx = pre_ctx.sub_context();
+
+        // Build an empty instruction to give as parent lowerer in scope.
+        let Self { llvm: llvm @ (_, c, _), func, last_loop, .. } = *self;
+        let instruction = unsafe { NOOP.get_or_init(|| anon_instruction!(Noop)) };
+        let func_return_type = self.func_return_type.clone();
+        let ctx = self.ctx.sub_context();
+        let this = Self { llvm, func, last_loop, instr: instruction, func_return_type, ctx };
+
+        // Drop what was declared in the scope
+        let mut ctx = cb(this);
+        unsafe { DropLowerer::new(c, func, &ctx.get_values_to_drop(), exit_bb, &ctx) }.lower();
+
+        // Restore context.
+        self.ctx = pre_ctx;
+    }
+
+    /// Set the last loop to lower a given instruction.
+    fn with_loop(mut self, r#loop: BBLoop) -> Self {
+        self.last_loop = Some(r#loop);
+        self
+    }
+
+    /// Set the value context.
+    fn with_ctx(mut self, ctx: ValueContext) -> Self {
+        self.ctx = ctx;
+        self
+    }
+
+    pub(super) fn lower(mut self) -> ValueContext {
+        let Self { llvm: llvm @ (_, c, b), func, instr: ASTInstr { content, span }, .. } = self;
+        match content {
+            // Nop
+            ASTInstrVariant::Noop => self.ctx,
+
+            // A simple list of instructions
+            ASTInstrVariant::Block(instructions) => unsafe {
+                let exit = LLVMAppendBasicBlockInContext(c, self.func, c".block".as_ptr());
+                self.scoped_lowerer(exit, |this| {
+                    instructions
+                        .iter()
+                        .fold(this.ctx.clone(), |ctx, instruction| this.sub_lowerer(instruction).with_ctx(ctx).lower())
+                });
+                LLVMBuildBr(b, exit);
+                LLVMPositionBuilderAtEnd(b, exit);
+                self.ctx
+            },
+
+            // Breaks/Continue
+            ASTInstrVariant::Break | ASTInstrVariant::Continue if self.last_loop.is_none() => {
+                panic!("try to lower break/continue while not being inside a loop")
+            }
+            ASTInstrVariant::Break => unsafe {
+                LLVMBuildBr(b, self.last_loop.expect("internal error").loop_exit);
+                self.ctx
+            },
+            ASTInstrVariant::Continue => unsafe {
+                LLVMBuildBr(b, self.last_loop.expect("internal error").body_entry);
+                self.ctx
+            },
+
+            // Return from function
+            ASTInstrVariant::Return(expr) => unsafe {
+                let (ctx, value) = self.expr(expr).lower();
+                match value {
+                    Value::Nil => LLVMBuildRetVoid(b),
+                    Value::Function(..) => panic!("error at `{span}`: can't return a function for now"),
+                    value => LLVMBuildRet(b, value.loaded(c, b)),
+                };
+                ctx
+            },
+
+            // Assignation
+            ASTInstrVariant::Assign(dests, srcs) if dests.len() != srcs.len() => {
+                unreachable!("internal error: verifier failed for assignations at `{span}`")
+            }
+            ASTInstrVariant::Assign(dests, srcs) => dests.iter().zip(srcs).fold(self.ctx, |ctx, (dest, src)| {
+                let (dest, dest_ty) = Self::compute_dest_location(c, b, &ctx, dest);
+                let (ctx, src) = ExpressionLowerer::with_expected_type(llvm, src, dest_ty, &ctx).lower();
+                Self::store_into(c, b, dest, &src);
+                ctx
+            }),
+
+            // Declarations
+            ASTInstrVariant::Decl(dests, srcs) if dests.len() != srcs.len() => {
+                unreachable!("internal error: verifier failed for declarations at `{span}`")
+            }
+            ASTInstrVariant::Decl(dests, srcs) => {
+                let mut declarations = Vec::with_capacity(dests.len());
+                let ctx = dests.iter().zip(srcs).fold(self.ctx.clone(), |ctx, (dest, src)| {
+                    let dest_ast_ty = dest.get_specified_type().expect("internal error");
+                    let dest_llvm_ty = TypeLowerer::new(c, dest_ast_ty).lower();
+                    let val = unsafe { LLVMBuildAlloca(b, dest_llvm_ty, cstr!("{}", dest.name())) };
+                    let (ctx, expr) = self.expr(src).with_ctx(&ctx).into_type(dest_ast_ty).lower();
+                    Self::store_into(c, b, val, &expr);
+                    declarations.push((dest.name(), Value::Alloca(dest_ast_ty.clone(), dest_llvm_ty, val)));
+                    ctx
+                });
+                declarations.into_iter().fold(ctx, |mut ctx, (name, val)| {
+                    ctx.register(name, val);
+                    ctx
+                })
+            }
+
+            // Call a function, discard the result
+            ASTInstrVariant::FuncCall(func, args) => {
+                let (ctx, value) = CallLowerer::new(llvm, &self.ctx).lower_func_call(func, args);
+                ctx.to_register_anon(value)
+            }
+            ASTInstrVariant::MethodInvok(obj, method, args) => {
+                let (ctx, value) = CallLowerer::new(llvm, &self.ctx).lower_method_invok(obj, method, args);
+                ctx.to_register_anon(value)
+            }
+
+            // If/Else/Elseif blocks
+            ASTInstrVariant::Cond { if_blocks, else_block } => unsafe {
+                let exit = LLVMAppendBasicBlockInContext(c, self.func, c".if.exit".as_ptr());
+                let pre_ctx = self.ctx.clone();
+                let true_cond = ASTCondition::BooleanTrue(anon_expression!(Const(ASTConst::True)));
+
+                let get_bb = move |idx: usize, what: &str| {
+                    LLVMAppendBasicBlockInContext(c, self.func, cstr!(".if.{}.{}", idx, what))
+                };
+                let mut bbs: HashMap<usize, LLVMBasicBlockRef> = Default::default();
+                let mut get_bb_cond = move |idx| *bbs.entry(idx).or_insert_with(move || get_bb(idx, "condition"));
+
+                /// Use a macro to not write the same code twice by forgeting something...
+                macro_rules! build_cond_block {
+                    (($if_num: expr, $if_cond: expr, $if_inner: expr), $else_bb: expr, $exit: expr) => {{
+                        let (if_bb_body, if_bb_body_exit) = (get_bb($if_num, "body"), get_bb($if_num, "body.exit"));
+                        self.scoped_lowerer(if_bb_body_exit, |mut scoped| {
+                            // CONDITION: We don't need to drop things even if we didn't succeded,
+                            //            add the new ctx to lower the conditional body. The head
+                            //            BB of the conditional is cached by it's number.
+                            LLVMPositionBuilderAtEnd(b, get_bb_cond($if_num));
+                            let ctx = scoped.lower_condition($if_cond, if_bb_body, $else_bb);
+
+                            // BODY: We need to drop things after the exit of the loop, we also
+                            //       drop the conditional stuff
+                            LLVMPositionBuilderAtEnd(b, if_bb_body);
+                            let ctx = scoped.sub_lowerer($if_inner).with_ctx(ctx).lower();
+                            LLVMBuildBr(b, if_bb_body_exit);
+                            LLVMPositionBuilderAtEnd(b, if_bb_body_exit);
+                            LLVMBuildBr(b, $exit);
+
+                            // WARN: scoped.ctx -> contains also the temporary values! We must drop
+                            //       all of those if we succeded or not.
+                            DropLowerer::new(c, func, &scoped.ctx.get_values_to_drop(), $else_bb, &ctx).lower();
+                            DropLowerer::new(c, func, &scoped.ctx.get_values_to_drop(), if_bb_body_exit, &ctx).lower();
+
+                            ctx
+                        })
+                    }};
+                }
+
+                let else_block = else_block.as_ref().map(|instr| (&true_cond, instr.as_ref()));
+                let if_blocks = if_blocks.iter().map(|(cond, instr): &_| (cond, instr));
+                let blocks = if_blocks.chain(else_block).enumerate().collect::<Vec<(_, (&_, &_))>>();
+                assert!(!blocks.is_empty(), "empty conditionals not allowed");
+
+                // IF -> Need to jump to the first condition checker
+                LLVMBuildBr(b, get_bb_cond(0));
+
+                // Build IF, for ELSE -> will be handled at next iteration
+                blocks.windows(2).for_each(|slice| match slice {
+                    [(if_num, (if_cond, if_inner)), (else_num, _)] => {
+                        build_cond_block!((*if_num, if_cond, if_inner), get_bb_cond(*else_num), exit)
+                    }
+                    _ => unreachable!(),
+                });
+
+                // ELSE / IF in the case where we have only one conditional -> Handle last item
+                let (else_num, (else_cond, else_inner)) = blocks.last().expect("internal error");
+                build_cond_block!((*else_num, else_cond, else_inner), exit, exit);
+
+                LLVMPositionBuilderAtEnd(b, exit);
+                pre_ctx
+            },
+
+            // While loops
+            ASTInstrVariant::WhileDo(condition, inner) => unsafe {
+                let (cond, exit, body, body_exit) = (
+                    LLVMAppendBasicBlockInContext(c, self.func, c".while.cond".as_ptr()),
+                    LLVMAppendBasicBlockInContext(c, self.func, c".while.exit".as_ptr()),
+                    LLVMAppendBasicBlockInContext(c, self.func, c".while.body".as_ptr()),
+                    LLVMAppendBasicBlockInContext(c, self.func, c".while.body.exit".as_ptr()),
+                );
+
+                self.scoped_lowerer(body_exit, |mut scoped| {
+                    // For a WhileDo the condition binding variables are only visible in the body
+                    // of the loop. Here we ensure variables are only available inside the loop.
+                    LLVMBuildBr(b, cond);
+                    LLVMPositionBuilderAtEnd(b, cond);
+                    let ctx = scoped.lower_condition(condition, body, exit);
+
+                    LLVMPositionBuilderAtEnd(b, body);
+                    let ctx = scoped
+                        .sub_lowerer(inner)
+                        .with_ctx(ctx)
+                        .with_loop(BBLoop { body_entry: body, loop_exit: exit })
+                        .lower();
+
+                    // Drop what was
+                    LLVMBuildBr(b, body_exit);
+                    LLVMPositionBuilderAtEnd(b, body_exit);
+                    DropLowerer::new(c, func, &scoped.ctx.get_values_to_drop(), body_exit, &ctx).lower();
+                    LLVMBuildBr(b, cond);
+                    ctx
+                });
+
+                LLVMPositionBuilderAtEnd(b, exit);
+                self.ctx
+            },
+
+            // For loop
+            ASTInstrVariant::ForLoop { var, lower: l, upper: u, step, body: inner } => unsafe {
+                let (cond, exit, body, body_exit) = (
+                    LLVMAppendBasicBlockInContext(c, self.func, c".forloop.cond".as_ptr()),
+                    LLVMAppendBasicBlockInContext(c, self.func, c".forloop.exit".as_ptr()),
+                    LLVMAppendBasicBlockInContext(c, self.func, c".forloop.body".as_ptr()),
+                    LLVMAppendBasicBlockInContext(c, self.func, c".forloop.body.exit".as_ptr()),
+                );
+
+                let (ctx, lower) = self.expr(l).into_type(&ASTType::Integer).lower();
+                let (mut ctx, upper) = self.expr(u).with_ctx(&ctx).into_type(&ASTType::Integer).lower();
+                let (lower, upper) = (lower.loaded(c, b), upper.loaded(c, b));
+
+                // Setup the index
+                let t_i32 = LLVMInt32TypeInContext(c);
+                let step = step.unwrap_or(1) as i64;
+                assert!(step > 0, "the for-loop step must be strictly positive");
+                let step = LLVMConstInt(t_i32, std::mem::transmute_copy(&step), 0);
+
+                let index = LLVMBuildAlloca(b, t_i32, cstr!(".index.{}", var));
+                ctx.register(var.name(), Value::Alloca(ASTType::Integer, t_i32, index));
+                LLVMBuildStore(b, lower, index);
+
+                // Build the condition check
+                LLVMBuildBr(b, cond);
+                LLVMPositionBuilderAtEnd(b, cond);
+                const PREDICATE: LLVMIntPredicate = LLVMIntPredicate::LLVMIntSLT;
+                let loaded = LLVMBuildLoad2(b, t_i32, index, cstr!(".index.{}.loaded", var));
+                let cont = LLVMBuildICmp(b, PREDICATE, loaded, upper, cstr!(".index.{}.flag", var));
+                LLVMBuildCondBr(b, cont, body, exit);
+
+                // Lower the body, we need a scope for that.
+                self.scoped_lowerer(body_exit, |scoped| {
+                    LLVMPositionBuilderAtEnd(b, body);
+                    let ctx = scoped
+                        .sub_lowerer(inner)
+                        .with_loop(BBLoop { body_entry: body, loop_exit: exit })
+                        .lower();
+                    let loaded = LLVMBuildLoad2(b, t_i32, index, cstr!(".index.{}.loaded", var));
+                    let loaded = LLVMBuildAdd(b, loaded, step, cstr!(".index.{}.incremented", var));
+                    LLVMBuildStore(b, loaded, index);
+                    LLVMBuildBr(b, body_exit);
+                    LLVMPositionBuilderAtEnd(b, body_exit);
+                    LLVMBuildBr(b, cond);
+                    ctx
+                });
+
+                // End of loop
+                LLVMPositionBuilderAtEnd(b, exit);
+                ctx
+            },
+            ASTInstrVariant::ForInto { .. } => unsafe {
+                let (_cond, _exit, _body, _body_exit) = (
+                    LLVMAppendBasicBlockInContext(c, self.func, c".foreach.cond".as_ptr()),
+                    LLVMAppendBasicBlockInContext(c, self.func, c".foreach.exit".as_ptr()),
+                    LLVMAppendBasicBlockInContext(c, self.func, c".foreach.body".as_ptr()),
+                    LLVMAppendBasicBlockInContext(c, self.func, c".foreach.body.exit".as_ptr()),
+                );
+                todo!()
+            },
+        }
+    }
+
+    /// Store the content of a value into a location in memory.
+    ///
+    /// TODO: Do that in the Value enum
+    fn store_into(c: LLVMContextRef, b: LLVMBuilderRef, dest: LLVMValueRef, src: &Value) {
+        match src {
+            Value::Function(_, _, _) => panic!("we don't handle function pointers for now"),
+            Value::Const(_, v) => unsafe { LLVMBuildStore(b, *v, dest) },
+            Value::Nil => match ConstantLowerer::new(c, &ASTConst::Nil).lower() {
+                Value::Const(_, v) => unsafe { LLVMBuildStore(b, v, dest) },
+                _ => unreachable!(),
+            },
+            Value::Alloca(_, ty, v) => unsafe {
+                let v = LLVMBuildLoad2(b, *ty, *v, cstr!());
+                LLVMBuildStore(b, v, dest)
+            },
+        };
+    }
+
+    /// Get the address and the type of a variable to store into it.
+    fn compute_dest_location<'b>(
+        _c: LLVMContextRef,
+        _b: LLVMBuilderRef,
+        _ctx: &'b ValueContext,
+        _expr: &'b ASTExpr,
+    ) -> (LLVMValueRef, &'b ASTType) {
+        todo!()
+    }
+
+    /// Lower the condition. Returns the new context with the added binded values if needed. If the
+    /// condition is not checked we don't need to drop anything from the returned value context.
+    /// This means that we must drop the returned context only on the then condition path.
+    ///
+    /// If things where allocated to check the condition, then we add them to the current context,
+    /// but not to the returned context! This means that may the condition succeed or not, you must
+    /// drop the context of the calling lowerer at the end of the `then` and `else` paths.
+    ///
+    /// Most of the time the context is already scopped, so it shouldn't be too difficult trop
+    /// things at the right moment.
+    fn lower_condition(
+        &mut self,
+        condition: &ASTCondition,
+        bb_then: LLVMBasicBlockRef,
+        bb_else: LLVMBasicBlockRef,
+    ) -> ValueContext {
+        let Self { llvm: llvm @ (_, c, b), .. } = *self;
+        match condition {
+            ASTCondition::BooleanTrue(cond) => unsafe {
+                let (mut ctx, cond) = self.expr(cond).into_type(&ASTType::Boolean).lower();
+                LLVMBuildCondBr(b, cond.loaded(c, b), bb_then, bb_else);
+
+                let ret_ctx = self.ctx.clone();
+                self.ctx.add_values_to_drop(ctx.get_values_to_drop());
+                ret_ctx
+            },
+
+            ASTCondition::CoercibleInto { new, as_type, source: src }
+                if src
+                    .get_specified_type()
+                    .expect("should be setted")
+                    .coercible_to(as_type) =>
+            unsafe {
+                let llvm_true = LLVMConstInt(LLVMInt1TypeInContext(c), 1, 0);
+                let (register, flag, src) = match CastLowerer::from_ast(llvm, src, as_type, &self.ctx).lower_dynamic() {
+                    CastedValue::Dynamic { flag, value } => (true, flag, value),
+                    CastedValue::Static { value } => (true, llvm_true, value),
+                    CastedValue::Unchanged { value } => (false, llvm_true, value),
+                };
+                LLVMBuildCondBr(b, flag, bb_then, bb_else);
+
+                LLVMPositionBuilderAtEnd(b, bb_then);
+                let ty = TypeLowerer::new(c, as_type).lower();
+                let dest = LLVMBuildAlloca(b, ty, cstr!(".{}.alloca", new));
+                LLVMBuildStore(b, src.loaded(c, b), dest);
+
+                either!(!register => self.ctx.clone();
+                    self.ctx.to_register(new.name(), Value::Alloca(as_type.clone(), ty, dest))
+                )
+            },
+
+            ASTCondition::CoercibleInto { .. } => unsafe {
+                LLVMBuildBr(b, bb_else);
+                self.ctx.clone()
+            },
+
+            ASTCondition::BindVariant { .. } => todo!(),
+        }
+    }
+}
diff --git a/src/Rust/vvs_codegen/src/lowerer/mod.rs b/src/Rust/vvs_codegen/src/lowerer/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2de616388b6d914b890880d722894bf06374af8f
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/lowerer/mod.rs
@@ -0,0 +1,221 @@
+mod calls;
+mod cast;
+mod constant;
+mod drops;
+mod expression;
+mod function;
+mod instruction;
+mod types;
+
+use crate::{
+    cstr,
+    lowerer::{calls::*, cast::*, drops::*, expression::*, function::*, instruction::*, types::*},
+    value::Value,
+    LLVMLowerContext, ValueContext,
+};
+use hashbrown::HashMap;
+use std::ffi::{CStr, CString};
+use vvs_lang::ast::*;
+use vvs_llvm::*;
+use vvs_runtime_types::{VVRTSymbol, VVRTSymbolType};
+
+// Re-export the constant lowerer because it can be usefull in other parts of the codegen.
+pub(crate) use self::constant::ConstantLowerer;
+
+pub struct Lowerer<'a> {
+    llvm: LLVMLowerContext,
+
+    functions: Vec<(ASTString, ASTString, &'a ASTFunction)>,
+    globals: HashMap<(ASTString, ASTString), &'a ASTConst>,
+
+    ctx: ValueContext,
+}
+
+pub struct LowererBuilder<'a> {
+    name: CString,
+    c: LLVMContextRef,
+    m: Option<LLVMModuleRef>,
+    b: LLVMBuilderRef,
+    programs: Option<&'a ASTProgram>,
+    modules: Vec<&'a ASTModule>,
+}
+
+impl<'a> LowererBuilder<'a> {
+    /// Create a new lowerer builder. We need a name and the context from the JIT thing.
+    ///
+    /// # Safety
+    /// This function is unsafe because we use the LLVM context pointer passed from anywhere. This
+    /// pointer must be not null and be a valid LLVM context.
+    pub unsafe fn new(name: impl AsRef<str>, c: LLVMContextRef) -> Self {
+        Self {
+            c,
+            name: CString::new(name.as_ref()).expect("invalid module name"),
+            b: LLVMCreateBuilderInContext(c),
+            m: Default::default(),
+            modules: Default::default(),
+            programs: Default::default(),
+        }
+    }
+
+    /// Add a complete program to lower. If any other program was present, overwrite it.
+    pub fn program(mut self, program: &'a ASTProgram) -> Self {
+        self.programs = Some(program);
+        self
+    }
+
+    /// Add a module to lower to the list of things to lower.
+    pub fn module(mut self, module: &'a ASTModule) -> Self {
+        self.modules.push(module);
+        self
+    }
+
+    /// Build the lowerer from this builder.
+    pub fn build(self) -> Lowerer<'a> {
+        let Self { c, m, b, programs, modules, name } = self;
+
+        // Get all the modules that will be lowered inside the final LLVM module. By doing this we
+        // have a similar thing to LTO for Vivy Script.
+
+        let init = HashMap::<ASTString, &'a ASTModule>::default();
+        let modules = modules
+            .into_iter()
+            .chain(programs.iter().flat_map(|prog| prog.modules()))
+            .fold(init, |mut map, module| match map.entry(module.name()) {
+                hashbrown::hash_map::Entry::Occupied(_) => map,
+                hashbrown::hash_map::Entry::Vacant(entry) => {
+                    entry.insert(module);
+                    map
+                }
+            });
+
+        // Get the globals that needs to be lowered / needs to be known by the lowerer. We first
+        // collect the setted options from the program as those will overwrite values from the
+        // modules, then we get what is defined as default in the module. To ensure we doesn't
+        // overwrite things, we only insert in the final hashmap if the thing was not already
+        // defined in the hashmap. Other than setted overwriting defaults, there should not be any
+        // other collisions.
+
+        let init: HashMap<(ASTString, ASTString), &'a ASTConst> = programs
+            .iter()
+            .flat_map(|prog| {
+                prog.setted_options()
+                    .iter()
+                    .map(|((m, n), v)| ((m.clone(), n.clone()), v))
+            })
+            .collect();
+        let globals = modules.iter().flat_map(|(mname, m)| {
+            let hdl = |(var, val): (&'a ASTVar, &'a _)| (mname.clone(), var.name(), val);
+            m.consts(ASTVisibilityRule::any()).map(hdl).chain(m.options().map(hdl))
+        });
+        let globals = globals.fold(init, |mut globals, (mn, n, val)| match globals.entry((mn, n)) {
+            hashbrown::hash_map::Entry::Occupied(_) => globals,
+            hashbrown::hash_map::Entry::Vacant(entry) => {
+                entry.insert(val);
+                globals
+            }
+        });
+
+        // Get the functions that are available in all the module to lower them. Should not be any
+        // collision.
+
+        let functions = modules.iter().flat_map(|(mname, m)| {
+            m.functions(ASTVisibilityRule::any())
+                .map(|(fname, f)| (mname.clone(), fname, f))
+        });
+        let functions = functions.collect();
+
+        // Now we can create the lowerer with the specified LLVM module or by creating a new one.
+
+        let m = m.unwrap_or_else(|| unsafe { LLVMModuleCreateWithNameInContext(name.as_ptr(), c) });
+        let mut ctx = ValueContext::default();
+        ctx.register_all(
+            unsafe { vvs_runtime_types::vvll::LLVMRegisterExportedIntoModule(c, m) }
+                .into_iter()
+                .map(|(name, asttype, val, ty)| (name, Value::Function(asttype, ty, val))),
+        );
+
+        Lowerer { llvm: (m, c, b), functions, globals, ctx }
+    }
+}
+
+impl<'a> Lowerer<'a> {
+    /// Lower the content of the programs and modules, then returns the LLVM module containing
+    /// everything...
+    pub fn lower(self) -> LLVMModuleRef {
+        let Self { llvm: llvm @ (m, c, b), functions, globals, mut ctx } = self;
+
+        // Register all the globals in the context, they will be directly inlined in the lowering
+        // process.
+
+        ctx.register_all(
+            globals
+                .into_iter()
+                .map(|((m, n), cnst)| (format!("{m}.{n}"), ConstantLowerer::new(c, cnst).lower())),
+        );
+
+        // Lower all the functions. First declare the things and register them with the mangled
+        // name and the unmagnled name. As we collect the iterator we ensure that all the functions
+        // are declared before we generate them. Doing so allows us to use recursion and we don't
+        // need to find a good order to define-use the functions like in C. When we latter lower
+        // the content of the functions we try to find the first error and return it.
+
+        functions.into_iter().for_each(|(module, name, function)| {
+            // Declare the thing
+            let mangled = VVRTSymbol::new(VVRTSymbolType::Function, &module, &name)
+                .expect("invalid function names")
+                .mangle();
+            let ast_function_type = function.function_type();
+            let ty = TypeLowerer::new(c, &ast_function_type).lower();
+            let value = unsafe { LLVMAddFunction(m, mangled.as_ptr(), ty) };
+
+            // Register it. When we collect the iterator.
+            let to_register = Value::Function(ast_function_type, ty, value);
+            ctx.register(mangled.to_str().expect("invalid function names"), to_register.clone());
+            ctx.register(format!("{module}.{name}"), to_register);
+
+            // We will generate it latter
+            FunctionLowerer::new(llvm, &ctx, value, function).lower();
+        });
+
+        // Cleanup and optimize the code.
+
+        unsafe {
+            LLVMDisposeBuilder(b);
+            Self::verify_and_apply_optimizations(m, 3)
+        }
+    }
+
+    /// Run the optimization passes on a module.
+    unsafe fn verify_and_apply_optimizations(m: LLVMModuleRef, lvl: u8) -> LLVMModuleRef {
+        let mut cmsg = std::ptr::null_mut();
+        if 0 != LLVMVerifyModule(m, LLVMVerifierFailureAction::LLVMPrintMessageAction, &mut cmsg) {
+            let msg = CStr::from_ptr(cmsg).to_string_lossy().to_string();
+            LLVMDisposeMessage(cmsg);
+            panic!("invalid module: {msg}");
+        }
+
+        let pbo = LLVMCreatePassBuilderOptions();
+        let pm = LLVMCreatePassManager();
+        let tm = LLVMCreateTargetMachine(
+            LLVMGetTargetFromName(LLVMGetTarget(m)),
+            LLVMGetDefaultTargetTriple(),
+            LLVMGetHostCPUName(),
+            LLVMGetHostCPUFeatures(),
+            LLVMCodeGenOptLevel::LLVMCodeGenLevelAggressive,
+            LLVMRelocMode::LLVMRelocPIC,
+            LLVMCodeModel::LLVMCodeModelDefault,
+        );
+
+        let err = LLVMRunPasses(m, cstr!("default<O{}>", lvl), tm, pbo);
+        if !err.is_null() {
+            let msg = CStr::from_ptr(LLVMGetErrorMessage(err)).to_string_lossy().to_string();
+            LLVMConsumeError(err);
+            panic!("failed to run optimizer with level O{lvl} on module: {msg}")
+        }
+
+        LLVMDisposePassBuilderOptions(pbo);
+        LLVMDisposePassManager(pm);
+        LLVMDisposeTargetMachine(tm);
+        m
+    }
+}
diff --git a/src/Rust/vvs_codegen/src/lowerer/types.rs b/src/Rust/vvs_codegen/src/lowerer/types.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5e1b47482002da089da0d8642da96c37c3db8a73
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/lowerer/types.rs
@@ -0,0 +1,57 @@
+use vvs_lang::ast::*;
+use vvs_llvm::*;
+use vvs_runtime_types::{types::*, vvll::LLVMExported};
+
+pub(super) struct TypeLowerer<'a> {
+    c: LLVMContextRef,
+    vivy_type: &'a ASTType,
+}
+
+impl<'a> TypeLowerer<'a> {
+    pub(super) fn new(c: LLVMContextRef, vivy_type: &'a ASTType) -> Self {
+        Self { c, vivy_type }
+    }
+
+    fn sub_lowerer(&self, ty: &'a ASTType) -> Self {
+        Self { c: self.c, vivy_type: ty }
+    }
+
+    pub(super) fn lower(self) -> LLVMTypeRef {
+        let Self { c, vivy_type } = self;
+        match vivy_type {
+            // Easy stuff...
+            ASTType::Nil => unsafe { LLVMVoidTypeInContext(c) },
+            ASTType::Integer => unsafe { LLVMInt32TypeInContext(c) },
+            ASTType::Floating => unsafe { LLVMFloatTypeInContext(c) },
+            ASTType::Boolean => unsafe { LLVMInt1TypeInContext(c) },
+
+            // Functions
+            ASTType::Function(args, returns) => unsafe {
+                let mut args = args.iter().map(|ty| self.sub_lowerer(ty).lower()).collect::<Vec<_>>();
+                LLVMFunctionType(
+                    self.sub_lowerer(returns).lower(),
+                    args.as_mut_ptr(),
+                    args.len().try_into().expect("too many arguments"),
+                    0,
+                )
+            },
+
+            // The tuple
+            ASTType::Tuple(inner) => unsafe {
+                let mut inner = inner.iter().map(|ty| self.sub_lowerer(ty).lower()).collect::<Vec<_>>();
+                LLVMStructType(inner.as_mut_ptr(), inner.len().try_into().expect("too many elements"), 0)
+            },
+
+            // Special structs, query the runtime for that...
+            ASTType::Any => unsafe { VVRTAny::llvm_type(c) },
+            ASTType::String => unsafe { VVRTString::llvm_type(c) },
+            ASTType::Syllabe => unsafe { VVRTSyllabe::llvm_type(c) },
+            ASTType::Line => unsafe { VVRTLine::llvm_type(c) },
+            ty if ty.is_table() => unsafe { VVRTTable::llvm_type(c) },
+            ty if ty.is_variant() => unsafe { VVRTVariant::llvm_type(c) },
+            ty if ty.is_sequence() => unsafe { VVRTSeq::llvm_type(c) },
+
+            _ => unreachable!(),
+        }
+    }
+}
diff --git a/src/Rust/vvs_codegen/src/value.rs b/src/Rust/vvs_codegen/src/value.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d7302af027e5b6fb25eef3e78172f50d8d64ee30
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/value.rs
@@ -0,0 +1,100 @@
+use crate::{cstr, lowerer};
+use vvs_lang::ast::{ASTConst, ASTType, Typed};
+use vvs_llvm::*;
+
+#[derive(Debug, Default, Clone, PartialEq, Eq)]
+pub(crate) enum Value {
+    /// Just the Nil/Null/None/nullptr value.
+    #[default]
+    Nil,
+
+    /// A constant.
+    Const(ASTType, LLVMValueRef),
+
+    /// A pointer to the stack plus the underlying type.
+    Alloca(ASTType, LLVMTypeRef, LLVMValueRef),
+
+    /// A function with its function type.
+    Function(ASTType, LLVMTypeRef, LLVMValueRef),
+}
+
+impl Value {
+    /// Try to get the name of the value. Only [Value::Nil] have no name.
+    pub fn as_str(&self) -> Option<&str> {
+        use Value::*;
+        match *self {
+            Nil => None,
+            Function(.., val) | Const(_, val) | Alloca(.., val) => unsafe {
+                let mut len = 0;
+                let str = LLVMGetValueName2(val, &mut len) as *const _;
+                Some(std::str::from_utf8_unchecked(std::slice::from_raw_parts(str, len)))
+            },
+        }
+    }
+
+    pub fn llvm_type(&self) -> Option<LLVMTypeRef> {
+        match self {
+            Value::Const(..) | Value::Nil => None,
+            Value::Alloca(_, t, _) | Value::Function(_, t, _) => Some(*t),
+        }
+    }
+
+    pub fn llvm_value(&self) -> Option<LLVMValueRef> {
+        match self {
+            Value::Nil => None,
+            Value::Const(_, v) | Value::Alloca(_, _, v) | Value::Function(_, _, v) => Some(*v),
+        }
+    }
+
+    pub fn loaded(&self, c: LLVMContextRef, b: LLVMBuilderRef) -> LLVMValueRef {
+        match self {
+            Value::Nil => lowerer::ConstantLowerer::new(c, &ASTConst::Nil).lower().loaded(c, b),
+            Value::Const(_, val) => *val,
+            Value::Alloca(_, ty, ptr) => unsafe { LLVMBuildLoad2(b, *ty, *ptr, cstr!()) },
+            Value::Function(_, _, func_ptr) => *func_ptr,
+        }
+    }
+
+    /// Get the name of the dropper function, if any!
+    pub fn get_dropper_name(&self) -> Option<&'static str> {
+        match self.get_ast_type() {
+            ty if ty.is_variant() => Some("VVRTVariant_drop"),
+            ty if ty.is_table() => Some("VVRTTable_drop"),
+            ty if ty.is_sequence() => Some("VVRTSeq_drop"),
+            ASTType::Syllabe => Some("VVRTSyllabe_drop"),
+            ASTType::String => Some("VVRTString_drop"),
+            ASTType::Line => Some("VVRTLine_drop"),
+            ASTType::Any => Some("VVRTAny_drop"),
+
+            ASTType::Function(_, _) => todo!("handle functions and clozures..."),
+            _ => None,
+        }
+    }
+
+    /// Call a function with some values. Note that this function won't create memory manage points
+    /// for the passed values (see types that are managed and the ones that are not.)
+    pub fn call<const N: usize>(&self, b: LLVMBuilderRef, mut args: [LLVMValueRef; N]) -> LLVMValueRef {
+        match self {
+            Value::Function(_, func_ty, func_val) => unsafe {
+                let args_ptr = args.as_mut_ptr();
+                let args_len = args.len().try_into().expect("too much arguments");
+                LLVMBuildCall2(b, *func_ty, *func_val, args_ptr, args_len, c"".as_ptr())
+            },
+            val => panic!("can't call a non-function value: {val:?}"),
+        }
+    }
+
+    pub fn get_ast_type(&self) -> &ASTType {
+        const NIL: ASTType = ASTType::Nil;
+        match self {
+            Value::Nil => &NIL,
+            Value::Const(ty, _) | Value::Alloca(ty, _, _) | Value::Function(ty, _, _) => ty,
+        }
+    }
+}
+
+impl Typed for Value {
+    fn get_type(&self, _: &vvs_lang::ast::ASTTypeContext) -> ASTType {
+        self.get_ast_type().clone()
+    }
+}
diff --git a/src/Rust/vvs_font/Cargo.toml b/src/Rust/vvs_font/Cargo.toml
index 838aa4cfe8f2a0c17b03ec1372ebe818ccbc9cf3..48c9c5faee6ab81c047c1ef89946fdedf0ba9ec2 100644
--- a/src/Rust/vvs_font/Cargo.toml
+++ b/src/Rust/vvs_font/Cargo.toml
@@ -1,14 +1,13 @@
 [package]
-name = "vvs_font"
+name              = "vvs_font"
+description       = "The font crate for VVS"
 version.workspace = true
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
-description = "The font crate for VVS"
 
 [dependencies]
-thiserror.workspace = true
-log.workspace = true
-
-ttf-parser = { version = "^0.19" }
-ab_glyph = { version = "^0.2.20" }
+thiserror.workspace  = true
+log.workspace        = true
+ttf-parser.workspace = true
+ab_glyph.workspace   = true
diff --git a/src/Rust/vvs_font/build.rs b/src/Rust/vvs_font/build.rs
index 8d38f76b5b5bd644f9b79d60d19c0b02a80c25ac..1ae4223882b997536452dc1c3b7bcc5d8d6d2b6a 100644
--- a/src/Rust/vvs_font/build.rs
+++ b/src/Rust/vvs_font/build.rs
@@ -10,6 +10,8 @@ fn rerun_directory<T: AsRef<Path> + ?Sized>(dir: &T) {
     }
 }
 
+static EXCLUDED_FONTS: &[&str] = &["FiraCode"];
+
 fn main() {
     let out_dir = Path::new(&env::var_os("OUT_DIR").expect("no OUT_DIR env variable..."))
         .canonicalize()
@@ -23,8 +25,13 @@ fn main() {
         .expect("failed to read the font folder")
         .filter_map(Result::ok)
         .filter(|file| {
-            file.file_type().map(|ft| ft.is_file()).unwrap_or_default()
-                && file.path().extension().map(|e| e == "ttf").unwrap_or(false)
+            file.file_type().map(|ft| ft.is_file()).unwrap_or_default() && {
+                let path = file.path();
+                path.file_name()
+                    .map(|f| !EXCLUDED_FONTS.iter().any(|pat| f.to_string_lossy().starts_with(pat)))
+                    .unwrap_or_default()
+                    && path.extension().map(|e| e == "ttf").unwrap_or_default()
+            }
         })
         .map(|file| {
             let (path, file_name) = (file.path(), file.file_name());
diff --git a/src/Rust/vvs_font/src/font.rs b/src/Rust/vvs_font/src/font.rs
index 5fc71f228ac230895c6240235bd83a53f671dae2..cf17c758dd91022db52f7a117ecc897b4b34a92a 100644
--- a/src/Rust/vvs_font/src/font.rs
+++ b/src/Rust/vvs_font/src/font.rs
@@ -24,6 +24,7 @@ pub struct Font<'a> {
 impl<'a> TryFrom<&'a [u8]> for Font<'a> {
     type Error = FontCreationError;
 
+    #[inline]
     fn try_from(data: &'a [u8]) -> Result<Self, Self::Error> {
         Ok(Self {
             face: ttf_parser::Face::parse(data, 0).map_err(FontCreationError::TTFParserError)?,
@@ -79,6 +80,7 @@ impl<'a> Font<'a> {
     }
 
     /// Get the number of glyphs in the font.
+    #[inline]
     pub fn number_of_glyphs(&self) -> i64 {
         self.face.number_of_glyphs() as i64
     }
diff --git a/src/Rust/vvs_font/src/rect.rs b/src/Rust/vvs_font/src/rect.rs
index 86454e17cb599bf0cf843fe1f1517a907c94b661..c52bb5b5b65b7abb71dbba0d89003fa4a8080b57 100644
--- a/src/Rust/vvs_font/src/rect.rs
+++ b/src/Rust/vvs_font/src/rect.rs
@@ -16,14 +16,13 @@ pub struct Rect {
 
 impl Rect {
     /// Create a correctly formed [Rect] that includes the passed [Point].
+    #[inline]
     pub fn new(p1: Point, p2: Point) -> Self {
-        Self {
-            top_left_corner: Point::min(p1, p2),
-            bottom_right_corner: Point::max(p1, p2),
-        }
+        Self { top_left_corner: Point::min(p1, p2), bottom_right_corner: Point::max(p1, p2) }
     }
 
     /// Returns a new [Rect] that includes the passed rectangles.
+    #[inline]
     pub fn merge(self, other: Self) -> Self {
         Self {
             top_left_corner: Point::min(self.top_left_corner, other.top_left_corner),
@@ -32,11 +31,13 @@ impl Rect {
     }
 
     /// Get the Top Left corner, the min coordinates.
+    #[inline]
     pub fn tl_corner(&self) -> Point {
         self.top_left_corner
     }
 
     /// Get the Bottom Right corner, the max coordinates.
+    #[inline]
     pub fn br_corner(&self) -> Point {
         self.bottom_right_corner
     }
@@ -44,11 +45,13 @@ impl Rect {
 
 impl Point {
     /// Returns the min components of the two [Point].
+    #[inline]
     pub fn min(p1: Point, p2: Point) -> Point {
         Point { x: min(p1.x, p2.x), y: min(p1.y, p2.y) }
     }
 
     /// Returns the max components of the two [Point].
+    #[inline]
     pub fn max(p1: Point, p2: Point) -> Point {
         Point { x: max(p1.x, p2.x), y: max(p1.y, p2.y) }
     }
diff --git a/src/Rust/vvs_lang/Cargo.toml b/src/Rust/vvs_lang/Cargo.toml
index 0f83afca939061c62ded0bdd6306a3013c96c280..538d8c5fb0c85c4d578fc6a6e4bd676914c20b32 100644
--- a/src/Rust/vvs_lang/Cargo.toml
+++ b/src/Rust/vvs_lang/Cargo.toml
@@ -1,19 +1,21 @@
 [package]
-name = "vvs_lang"
+name              = "vvs_lang"
+description       = "Vivy Script Language"
 version.workspace = true
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
-description = "Vivy Script Language"
 
 [dependencies]
-thiserror.workspace = true
-serde.workspace = true
-hashbrown.workspace = true
-log.workspace = true
-regex.workspace = true
-nom.workspace = true
-nom_locate.workspace = true
-anyhow.workspace = true
+thiserror.workspace   = true
+paste.workspace       = true
+serde.workspace       = true
+hashbrown.workspace   = true
+log.workspace         = true
+regex.workspace       = true
+anyhow.workspace      = true
+toml.workspace        = true
+derive_more.workspace = true
 
-vvs_utils = { path = "../vvs_utils" }
+vvs_utils.workspace  = true
+vvs_parser.workspace = true
diff --git a/src/Rust/vvs_lang/VVL.g4 b/src/Rust/vvs_lang/VVL.g4
deleted file mode 100644
index b64d20b2b0dcc18061a71fc46e390d3e5232b42f..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/VVL.g4
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
-BSD License
-
-Copyright (c) 2013, Kazunori Sakamoto
-Copyright (c) 2016, Alexander Alexeev
-Copyright (c) 2023, Maël Martin
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-1. Redistributions of source code must retain the above copyright notice, this
-   list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright notice,
-   this list of conditions and the following disclaimer in the documentation
-   and/or other materials provided with the distribution.
-3. Neither the NAME of Rainer Schuster nor the NAMEs of its contributors may be
-   used to endorse or promote products derived from this software without
-   specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-grammar VVL;
-
-chunk:      topblock* EOF;
-visibility: ('pub')?;
-block:      stat* laststat?;
-
-topblock: visibility 'function' NAME (':' NAME)? funcbody
-        | visibility 'job'      NAME funcbody
-        | visibility 'const'    NAME opttypespec '=' exp
-        | visibility 'option'   NAME opttypespec '=' exp
-        | ('import' | 'requires') string
-        ;
-
-stat: ';'
-    | varlist '=' explist
-    | functioncall
-    | 'do' block 'end'
-    | 'while' exp 'do' block 'end'
-    | 'repeat' block 'until' exp
-    | 'if' exp 'then' block ('elseif' exp 'then' block)* ('else' block)? 'end'
-    | 'for' NAME '=' exp ',' exp (',' exp)? 'do' block 'end'
-    | 'for' namelist 'in' explist 'do' block 'end'
-    | 'let' attnamelist ('=' explist)?
-    ;
-
-attnamelist:    NAME opttypespec (',' NAME opttypespec)*;
-opttypespec:    (':' NAME)?;
-laststat:       'return' explist? | 'break' | 'continue' ';'?;
-varlist:        var (',' var)*;
-namelist:       NAME (',' NAME)*;
-explist:        (exp ',')* exp;
-
-exp: 'nil' | 'false' | 'true'
-   | number
-   | color
-   | string
-   | prefixexp
-   | tableconstructor
-   | <assoc=right> exp operatorPower exp
-   | operatorUnary exp
-   | exp operatorMulDivMod exp
-   | exp operatorAddSub exp
-   | <assoc=right> exp operatorStrcat exp
-   | exp operatorComparison exp
-   | exp operatorAnd exp
-   | exp operatorOr exp
-   | exp operatorBitwise exp
-   | '(' exp (',' exp)+ (',')? ')'
-   ;
-
-prefixexp:          varOrExp nameAndArgs*;
-functioncall:       varOrExp nameAndArgs+;
-varOrExp:           var | '(' exp ')';
-var:                (NAME | '(' exp ')' varSuffix) varSuffix*;
-varSuffix:          nameAndArgs* ('[' exp ']' | '.' NAME);
-nameAndArgs:        (':' NAME)? args;
-args:               '(' explist? ')' | tableconstructor | string;
-funcbody:           '(' parlist? ')' '->' NAME 'begin' block 'end';
-parlist:            namelist (',')?;
-tableconstructor:   '{' fieldlist? '}';
-fieldlist:          field (fieldsep field)* fieldsep?;
-field:              '[' exp ']' '=' exp | NAME '=' exp | exp;
-fieldsep:           ',' | ';';
-
-operatorOr:         'or';
-operatorAnd:        'and';
-operatorComparison: '<' | '>' | '<=' | '>=' | '~=' | '==' | '!=';
-operatorStrcat:     '..';
-operatorAddSub:     '+' | '-';
-operatorMulDivMod:  '*' | '/' | '%' | '//' | 'mod';
-operatorBitwise:    '&' | '^' | '|' | '~' | '<<' | '>>';
-operatorUnary:      'not' | '#' | '-' | '~';
-operatorPower:      '^';
-
-color:  '#(' ... ')';
-number: INT | HEX | FLOAT | HEX_FLOAT;
-string: NORMALSTRING | CHARSTRING | LONGSTRING;
-
-// LEXER
-
-NAME:           [a-zA-Z_][a-zA-Z_0-9]*;
-NORMALSTRING:   '"' ( EscapeSequence | ~('\\'|'"') )* '"';
-CHARSTRING:     '\'' ( EscapeSequence | ~('\''|'\\') )* '\'';
-LONGSTRING:     '[' NESTED_STR ']';
-
-fragment
-NESTED_STR: '=' NESTED_STR '='
-          | '[' .*? ']'
-          ;
-
-INT: Digit+;
-HEX: '0' [xX] HexDigit+;
-
-FLOAT: Digit+ '.' Digit* ExponentPart?
-     | '.' Digit+ ExponentPart?
-     | Digit+ ExponentPart
-     ;
-
-HEX_FLOAT
-    : '0' [xX] HexDigit+ '.' HexDigit* HexExponentPart?
-    | '0' [xX] '.' HexDigit+ HexExponentPart?
-    | '0' [xX] HexDigit+ HexExponentPart
-    ;
-
-fragment
-ExponentPart
-    : [eE] [+-]? Digit+
-    ;
-
-fragment
-HexExponentPart
-    : [pP] [+-]? Digit+
-    ;
-
-fragment
-EscapeSequence
-    : '\\' '\r'? '\n'
-    ;
-
-fragment
-Digit
-    : [0-9]
-    ;
-
-fragment
-HexDigit
-    : [0-9a-fA-F]
-    ;
-
-fragment
-SingleLineInputCharacter
-    : ~[\r\n\u0085\u2028\u2029]
-    ;
-
-COMMENT
-    : '--[' NESTED_STR ']' -> channel(HIDDEN)
-    ;
-
-LINE_COMMENT
-    : '--' SingleLineInputCharacter* -> channel(HIDDEN)
-    ;
-
-WS
-    : [ \t\u000C\r\n]+ -> skip
-    ;
diff --git a/src/Rust/vvs_lang/VVS.g4 b/src/Rust/vvs_lang/VVS.g4
deleted file mode 100644
index 4b82087b3cb3b37d35406813ee426dba2923883a..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/VVS.g4
+++ /dev/null
@@ -1,117 +0,0 @@
-// MIT License
-//
-// Copyright 2023 Maël MARTIN
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
-// associated documentation files (the "Software"), to deal in the Software without restriction,
-// including without limitation the rights to use, copy, modify, merge, publish, distribute,
-// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all copies or
-// substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
-// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
-// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-grammar VVS;
-
-chunk: topblock* mainblock EOF;
-
-topblock: 'import' string
-        : 'set' NAME '.' NAME '=' exp
-        ;
-
-mainblock:
-    'main' NAME '{'
-        (NAME '=' NAME '.' NAME NAME ';')*
-
-        'write' '{' (NAME (',' NAME)* (,)?)? '}'
-    '}'
-;
-
-exp: 'nil' | 'false' | 'true'
-   | number
-   | color
-   | string
-   ;
-
-color:  '#(' ... ')';
-number: INT | HEX | FLOAT | HEX_FLOAT;
-string: NORMALSTRING | CHARSTRING | LONGSTRING;
-
-// LEXER
-
-NAME:           [a-zA-Z_][a-zA-Z_0-9]*;
-NORMALSTRING:   '"' ( EscapeSequence | ~('\\'|'"') )* '"';
-CHARSTRING:     '\'' ( EscapeSequence | ~('\''|'\\') )* '\'';
-LONGSTRING:     '[' NESTED_STR ']';
-
-fragment
-NESTED_STR: '=' NESTED_STR '='
-          | '[' .*? ']'
-          ;
-
-INT: Digit+;
-HEX: '0' [xX] HexDigit+;
-
-FLOAT: Digit+ '.' Digit* ExponentPart?
-     | '.' Digit+ ExponentPart?
-     | Digit+ ExponentPart
-     ;
-
-HEX_FLOAT
-    : '0' [xX] HexDigit+ '.' HexDigit* HexExponentPart?
-    | '0' [xX] '.' HexDigit+ HexExponentPart?
-    | '0' [xX] HexDigit+ HexExponentPart
-    ;
-
-fragment
-ExponentPart
-    : [eE] [+-]? Digit+
-    ;
-
-fragment
-HexExponentPart
-    : [pP] [+-]? Digit+
-    ;
-
-fragment
-EscapeSequence
-    : '\\' '\r'? '\n'
-    ;
-
-fragment
-Digit
-    : [0-9]
-    ;
-
-fragment
-HexDigit
-    : [0-9a-fA-F]
-    ;
-
-fragment
-SingleLineInputCharacter
-    : ~[\r\n\u0085\u2028\u2029]
-    ;
-
-COMMENT
-    : '--[' NESTED_STR ']' -> channel(HIDDEN)
-    ;
-
-LINE_COMMENT
-    : '--' SingleLineInputCharacter* -> channel(HIDDEN)
-    ;
-
-WS
-    : [ \t\u000C\r\n]+ -> skip
-    ;
-
-SHEBANG
-    : '#' '!' SingleLineInputCharacter* -> channel(HIDDEN)
-    ;
-
diff --git a/src/Rust/vvs_lang/samples/retime.vvl b/src/Rust/vvs_lang/samples/retime.vvl
deleted file mode 100644
index 3599efdf772e8c6ab925d44238a8831fc4129b1b..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/samples/retime.vvl
+++ /dev/null
@@ -1,28 +0,0 @@
--- Contains utilities to retime lines from an ASS file.
-
-
-import "math"
-
-
-option before : int = 900   --  Retime time in millisecond for the aparition of the line.
-option after  : int = 300   --  Retime time in millisecond for the disaparition of the line.
-
-
-pub job start(l: line) -> line
---  Here we set the begin of the syllabes at the begin of the line, each
---  syllabes will end when it should in fact begin.
-begin
-    for s in l do
-        s.begin = l.start - before
-    end
-end
-
-
-pub job finish(l: line) -> line
---  Here we set the end of the syllabes at the end of the line, each
--- syllabes will begin when it should in fact end.
-begin
-    for s in l do
-        s.finish = l.finish - after
-    end
-end
diff --git a/src/Rust/vvs_lang/samples/test.vvs b/src/Rust/vvs_lang/samples/test.vvs
deleted file mode 100644
index 3b3c9a603a4114aed37b25b23746bab7c2b71f70..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/samples/test.vvs
+++ /dev/null
@@ -1,24 +0,0 @@
-import "retime"
-import "utils"
-import "tag"
-
-
--- Set some options.
-set retime.before = 900
-set retime.after  = 400
-
-set outline.border = 4
-set outline.color = #(rgb: 0, 0, 0)
-
-
--- What we want to do for this script, and how we name the initial value.
-main INIT {
-    BEFORE = retime.start  INIT;
-    AFTER  = retime.finish INIT;
-
-    OUTLINED = utils.outline BEFORE, INIT, AFTER;
-    TAGGED   = tag.syl_modulo<3> OUTLINED; -- Here we tag some objects...
-
-    -- What we want to write in the file, in order.
-    write { OUTLINED }
-}
diff --git a/src/Rust/vvs_lang/src/ast/constant.rs b/src/Rust/vvs_lang/src/ast/constant.rs
new file mode 100644
index 0000000000000000000000000000000000000000..22af5e6bfa46372c1d9fc13ab260789f709885ad
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/constant.rs
@@ -0,0 +1,134 @@
+use crate::ast::*;
+use anyhow::{anyhow, ensure, Context};
+
+/// A constant expr.
+#[derive(Debug, PartialEq, Clone)]
+pub enum ASTConst {
+    Nil,
+    False,
+    True,
+    Tuple(Vec<ASTConst>),
+    Color(ASTVariant<ASTConst>),
+    String(ASTString),
+    Integer(ASTInteger),
+    Floating(ASTFloating),
+    Table(ASTTable<ASTConst>),
+}
+
+/// Get the type for a const table, returns the more specialized type ([ASTType::UniformTable], etc)
+fn get_const_table_type(table: &ASTTable<ASTConst>) -> ASTType {
+    let integer_keys = table.keys().all(|key| key.parse::<i64>().is_ok());
+    let mut uniform_values = table.values().map(|val| val.get_const_type()).collect::<Vec<_>>();
+    let uniform_values = uniform_values
+        .pop()
+        .map(|ty| uniform_values.into_iter().all(|a| ty.eq(&a)).then_some(ty));
+    match (integer_keys, uniform_values) {
+        (true, Some(Some(ty))) => ASTType::Sequence(Box::new(ty)),
+        _ => ASTType::Table(
+            table
+                .iter()
+                .map(|(key, value)| (key.clone(), value.get_const_type()))
+                .collect(),
+        ),
+    }
+}
+
+impl Typed for ASTConst {
+    #[inline]
+    fn get_type(&self, _: &ASTTypeContext) -> ASTType {
+        self.get_const_type()
+    }
+}
+
+impl std::fmt::Display for ASTConst {
+    #[inline]
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            ASTConst::Nil => f.write_str("nil"),
+            ASTConst::False => f.write_str("false"),
+            ASTConst::True => f.write_str("true"),
+            ASTConst::Color(ASTVariant { variant, args }) => write!(f, "color#{variant}{args:?}"),
+            ASTConst::String(str) => write!(f, "{str:?}"),
+            ASTConst::Integer(int) => write!(f, "{int}"),
+            ASTConst::Floating(flt) => write!(f, "{flt}"),
+            ASTConst::Table(table) => write_ast_table(f, table),
+            ASTConst::Tuple(tuple) => write_ast_tuple(f, tuple),
+        }
+    }
+}
+
+impl MaybeConstExpr for ASTConst {
+    #[inline]
+    fn is_const_expr(&self) -> bool {
+        true
+    }
+
+    #[inline]
+    fn eval_const_expr(&self) -> Option<ASTConst> {
+        Some(self.clone())
+    }
+}
+
+impl ASTConst {
+    #[inline]
+    pub fn get_const_type(&self) -> ASTType {
+        match self {
+            ASTConst::Nil => ASTType::Nil,
+            ASTConst::True | ASTConst::False => ASTType::Boolean,
+            ASTConst::Color(..) => ASTType::Color,
+            ASTConst::String(_) => ASTType::String,
+            ASTConst::Integer(_) => ASTType::Integer,
+            ASTConst::Floating(_) => ASTType::Floating,
+            ASTConst::Tuple(inner) => ASTType::Tuple(inner.iter().map(|expr| expr.get_const_type()).collect()),
+            ASTConst::Table(content) => get_const_table_type(content),
+        }
+    }
+
+    /// Try to create an [ASTConst] from a [toml::Value]. We verify that the value is valid, i.e.
+    /// we don't have nested tables and such.
+    ///
+    /// NOTE: For now we can't construct colors and/or movements from toml values...
+    pub fn from_toml_value(cache: &ASTStringCacheHandle, value: toml::Value) -> anyhow::Result<Self> {
+        use toml::Value as TomlValue;
+
+        fn table_from_toml_value(
+            cache: &ASTStringCacheHandle,
+            mut values: impl Iterator<Item = (ASTString, TomlValue)>,
+        ) -> anyhow::Result<ASTConst> {
+            let (lower, upper) = values.size_hint();
+            let table = ASTTable::with_capacity(upper.unwrap_or(lower));
+            let table = values.try_fold(table, |mut table, (key, value)| {
+                let value = ASTConst::from_toml_value(cache, value)?;
+                ensure!(!matches!(value, ASTConst::Table(_)), "forbiden nested tables");
+                table
+                    .insert(key, value)
+                    .map(|_| Err(anyhow!("redefinition of a value in the table")))
+                    .unwrap_or(Ok(table))
+            })?;
+            Ok(ASTConst::Table(table))
+        }
+
+        match value {
+            TomlValue::Datetime(date) => Ok(ASTConst::String(cache.get(date.to_string()))),
+            TomlValue::String(str) => Ok(ASTConst::String(cache.get(str))),
+
+            TomlValue::Float(num) => Ok(ASTConst::Floating(num as f32)),
+            TomlValue::Integer(num) => Ok(ASTConst::Integer(num.try_into().context("integer overflow")?)),
+            TomlValue::Boolean(true) => Ok(ASTConst::True),
+            TomlValue::Boolean(false) => Ok(ASTConst::False),
+
+            TomlValue::Array(values) => {
+                ensure!(values.len() < i32::MAX as usize, "too many elements in array");
+                let values = values
+                    .into_iter()
+                    .enumerate()
+                    .map(|(k, v)| (cache.get(k.to_string()), v));
+                table_from_toml_value(cache, values)
+            }
+            TomlValue::Table(values) => {
+                ensure!(values.len() < i32::MAX as usize, "too many elements in table");
+                table_from_toml_value(cache, values.into_iter().map(|(k, v)| (cache.get(k), v)))
+            }
+        }
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/expression.rs b/src/Rust/vvs_lang/src/ast/expression.rs
new file mode 100644
index 0000000000000000000000000000000000000000..79d482fb3a9666a1454171fd7cc2805acfb3e8e5
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/expression.rs
@@ -0,0 +1,441 @@
+use crate::ast::*;
+use std::ops::{Deref, DerefMut};
+
+#[macro_export]
+macro_rules! anon_expression {
+    (const     $variant: ident $($args: tt)?) => { $crate::anon_expression!(Const (ASTConst::$variant $($args)?)) };
+    (box const $variant: ident $($args: tt)?) => { Box::new($crate::anon_expression!(Const (ASTConst::$variant $($args)?))) };
+    (box       $variant: ident $($args: tt)?) => { Box::new($crate::anon_expression!($variant $($args)?)) };
+
+    ($variant: ident $($args: tt)?) => {
+        ASTExpr {
+            span: Default::default(),
+            content: ASTExprVariant::$variant $($args)?,
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! expression {
+    ($span: expr, $variant: ident $($args: tt)?) => {
+        ASTExpr {
+            span: $span.into(),
+            content: ASTExprVariant::$variant $($args)?,
+        }
+    };
+}
+
+/// Binops, sorted by precedence.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ASTBinop {
+    /// Assoc: right
+    Power,
+
+    Mul,
+    Div,
+    Mod,
+    Add,
+    Sub,
+
+    /// Assoc: right
+    StrCat,
+
+    CmpLE,
+    CmpLT,
+    CmpGE,
+    CmpGT,
+    CmpEQ,
+    CmpNE,
+
+    LogicAnd,
+    LogicXor,
+    LogicOr,
+
+    BitAnd,
+    BitXor,
+    BitOr,
+    BitShiftLeft,
+    BitShiftRight,
+}
+
+/// Unops.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ASTUnop {
+    LogicNot,
+    BitNot,
+    Len,
+    Neg,
+}
+
+/// Expressions. For the partial equality we skip the span field to be able to test efficiently the
+/// parsing.
+#[derive(Debug, Clone, Default)]
+pub struct ASTExpr {
+    pub content: ASTExprVariant,
+    pub span: ASTSpan,
+}
+
+/// Expressions.
+#[derive(Debug, PartialEq, Clone)]
+pub enum ASTExprVariant {
+    /// A table, like in Lua
+    Table(ASTTable<ASTExpr>),
+
+    /// A binary operation, like in most of languages.
+    Binop(Box<ASTExpr>, ASTBinop, Box<ASTExpr>),
+
+    /// A unary operation, like in most of languages.
+    Unop(ASTUnop, Box<ASTExpr>),
+
+    /// A call to a function.
+    FuncCall(Box<ASTExpr>, Vec<ASTExpr>),
+
+    /// A function where the first arguments are binded.
+    FuncBind(Box<ASTExpr>, Vec<ASTExpr>),
+
+    /// Invocation of a method. To call a function from a table, we don't use the
+    /// [ASTExprVariant::MethodInvok] thing, but a [ASTExprVariant::FuncCall] where the first
+    /// element is the dereferencing of the table. Here the name of the method must be known and be
+    /// like: `{ty}::{method}`.
+    MethodInvok(Box<ASTExpr>, ASTString, Vec<ASTExpr>),
+
+    /// We access fields from an expression.
+    Suffixed(Box<ASTExpr>, Vec<ASTField>),
+
+    /// A non-constant expression color.
+    Color(ASTVariant<ASTExpr>),
+
+    /// Represents a movement for a line or syllabe. We don't have a constant variant for this
+    /// representation because movements are very dynamic (it depends on the resolution of the
+    /// video...) and thus doesn't make much sense to have a constant movement.
+    ///
+    /// NOTE: See if other people agree to that, there can be some arguments for having a constant
+    ///       movement or an optional one.
+    Movement(ASTVariant<ASTExpr>),
+
+    /// A tuple, Lua don't have ones but because we won't be stack based we can't do the multiple
+    /// return thing without a tuple...
+    Tuple(Vec<ASTExpr>),
+
+    /// A variable load.
+    Var(ASTVar),
+
+    /// A constant expression.
+    Const(ASTConst),
+
+    /// The default value for a type.
+    Default(ASTType),
+}
+
+/// Fields indexes can be expressions or identifiers
+#[derive(Debug, PartialEq, Clone)]
+pub enum ASTField {
+    /// We index by a string or an integer...
+    Expr(ASTSpan, ASTExprVariant),
+
+    /// A name field.
+    Identifier(ASTSpan, ASTString),
+}
+
+impl PartialEq for ASTExpr {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.content == other.content
+    }
+}
+
+/// Get the type for a table, returns the more specialized type ([ASTType::UniformTable], etc)
+fn get_table_type<T: Typed>(table: &ASTTable<T>, ctx: &ASTTypeContext) -> ASTType {
+    let integer_keys = table.keys().all(|key| key.parse::<i64>().is_ok());
+    let mut uniform_values = table.values().map(|val| val.get_type(ctx)).collect::<Vec<_>>();
+    let uniform_values = uniform_values
+        .pop()
+        .map(|ty| uniform_values.into_iter().all(|a| ty.eq(&a)).then_some(ty));
+    match (integer_keys, uniform_values) {
+        (true, Some(Some(ty))) => ASTType::Sequence(Box::new(ty)),
+        _ => ASTType::Table(
+            table
+                .iter()
+                .map(|(key, value)| (key.clone(), value.get_type(ctx)))
+                .collect(),
+        ),
+    }
+}
+
+fn get_table_deref_type(ctx: &ASTTypeContext, table: ASTType, fields: &[ASTField]) -> ASTType {
+    let (first, tail) = match fields {
+        [] => return table,
+        [first, tail @ ..] => (first, tail),
+    };
+
+    match table {
+        ASTType::Tuple(_) => todo!(),
+
+        ASTType::AnyTable => ASTType::Any,
+        ASTType::Table(_) => todo!(),
+        ASTType::UniformTable(_) => todo!(),
+
+        ty @ ASTType::Syllabe | ty @ ASTType::Line => match first {
+            ASTField::Expr(..) => ASTType::Nil,
+            ASTField::Identifier(_, field) => {
+                let ty = crate::ast::get_field_extensions(ctx, ty)
+                    .find_map(|(key, ty)| key.eq(&field.as_ref()).then_some(ty.clone()))
+                    .unwrap_or(ASTType::Nil);
+                get_table_deref_type(ctx, ty, tail)
+            }
+        },
+
+        _ => ASTType::Nil,
+    }
+}
+
+impl Typed for ASTExprVariant {
+    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType {
+        use crate::ast::{ASTBinop::*, ASTUnop::*};
+        match self {
+            ASTExprVariant::FuncBind(_, _) => todo!(),
+
+            ASTExprVariant::MethodInvok(_, _, _) => todo!(),
+
+            ASTExprVariant::FuncCall(_, _) => todo!(),
+
+            ASTExprVariant::Default(ty) => ty.clone(),
+            ASTExprVariant::Color(_) => ASTType::Color,
+            ASTExprVariant::Movement(_) => ASTType::Movement,
+            ASTExprVariant::Const(r#const) => r#const.get_type(ctx),
+
+            ASTExprVariant::Var(var) => match var.get_specified_type() {
+                Some(ty) => ty.clone(),
+                None => ctx.get(var),
+            },
+
+            ASTExprVariant::Tuple(tuple) => ASTType::Tuple(tuple.iter().map(|expr| expr.get_type(ctx)).collect()),
+            ASTExprVariant::Table(table) => get_table_type(table, ctx),
+            ASTExprVariant::Suffixed(expr, fields) => get_table_deref_type(ctx, expr.get_type(ctx), fields),
+
+            ASTExprVariant::Unop(op, inner) => {
+                use ASTType::*;
+                match (op, inner.get_type(ctx)) {
+                    (BitNot | LogicNot, ty @ Integer | ty @ Boolean) => ty,
+                    (Neg, ty @ Floating | ty @ Integer | ty @ Boolean) => ty,
+                    (
+                        Len,
+                        String | Tuple(_) | Syllabe | Line | AnyTable | UniformTable(_) | AnySequence | Table(_)
+                        | Sequence(_),
+                    ) => Integer,
+                    _ => Nil,
+                }
+            }
+
+            ASTExprVariant::Binop(left, op, right) => {
+                use ASTType::*;
+                let (left, right) = (left.get_type(ctx), right.get_type(ctx));
+                match op {
+                    Power => match (left, right) {
+                        (ty @ Integer | ty @ Floating, Integer) => ty,
+                        _ => Nil,
+                    },
+
+                    Mul | Div | Add | Sub => match (left, right) {
+                        (ty @ Integer, Integer) | (ty @ Floating, Floating) => ty,
+                        _ => Nil,
+                    },
+
+                    Mod => match (left, right) {
+                        (Integer, Integer) => Integer,
+                        _ => Nil,
+                    },
+
+                    StrCat => match (left, right) {
+                        (String, String) => String,
+                        _ => Nil,
+                    },
+
+                    CmpLE | CmpLT | CmpGE | CmpGT => match (left, right) {
+                        (Integer, Integer) | (Floating, Floating) => Boolean,
+                        _ => Nil,
+                    },
+
+                    CmpEQ | CmpNE => match right.coercible_to(&left) {
+                        true => Boolean,
+                        false => Nil,
+                    },
+
+                    LogicAnd | LogicXor | LogicOr => match (left, right) {
+                        (Boolean, Boolean) => Boolean,
+                        _ => Nil,
+                    },
+
+                    BitAnd | BitXor | BitOr => match (left, right) {
+                        (Integer, Integer) => Integer,
+                        (Boolean, Boolean) => Boolean,
+                        _ => Nil,
+                    },
+
+                    BitShiftLeft | BitShiftRight => match (left, right) {
+                        (Integer, Integer) => Integer,
+                        _ => Nil,
+                    },
+                }
+            }
+        }
+    }
+}
+
+impl Deref for ASTExpr {
+    type Target = ASTExprVariant;
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        &self.content
+    }
+}
+
+impl DerefMut for ASTExpr {
+    #[inline]
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.content
+    }
+}
+
+impl VariantName for ASTExpr {
+    #[inline]
+    fn variant_name(&self) -> &'static str {
+        self.content.variant_name()
+    }
+}
+
+impl VariantName for ASTExprVariant {
+    #[inline]
+    fn variant_name(&self) -> &'static str {
+        match self {
+            ASTExprVariant::Movement(_) => "movement",
+            ASTExprVariant::Color(_) => "color",
+            ASTExprVariant::Table(_) => "table",
+            ASTExprVariant::Binop(_, _, _) => "binary operation",
+            ASTExprVariant::Unop(_, _) => "unary operation",
+            ASTExprVariant::FuncCall(_, _) => "function call",
+            ASTExprVariant::FuncBind(_, _) => "function bind",
+            ASTExprVariant::MethodInvok(_, _, _) => "method invokation",
+            ASTExprVariant::Suffixed(_, _) => "prefixed expression",
+            ASTExprVariant::Tuple(_) => "tuple",
+            ASTExprVariant::Var(_) => "variable",
+            ASTExprVariant::Const(_) => "constant",
+            ASTExprVariant::Default(_) => "default",
+        }
+    }
+}
+
+impl ASTField {
+    #[inline]
+    pub fn span(&self) -> ASTSpan {
+        match self {
+            ASTField::Expr(span, _) | ASTField::Identifier(span, _) => *span,
+        }
+    }
+}
+
+impl MaybeConstExpr for ASTExprVariant {
+    fn is_const_expr(&self) -> bool {
+        use ASTExprVariant::*;
+        match self {
+            // We don't do constant method invokation for now.
+            FuncCall(_, _) | MethodInvok(_, _, _) | FuncBind(_, _) => false,
+
+            // Depends on the content.
+            Binop(l, _, r) => l.is_const_expr() && r.is_const_expr(),
+            Unop(_, inner) => inner.is_const_expr(),
+            Tuple(inner) => inner.iter().all(|expr| expr.is_const_expr()),
+            Color(variant) | Movement(variant) => variant.is_const_expr(),
+            Suffixed(table, suffixes) => table.is_const_expr() && suffixes.iter().all(|field| field.is_const_expr()),
+            Default(ty) => ty.is_const_constructible(),
+
+            // Well, it depend, for now we will say that it's not compile time evaluable.
+            Table(_) => false,
+            Var(_) => false,
+
+            // Obviously
+            Const(_) => true,
+        }
+    }
+
+    fn eval_const_expr(&self) -> Option<ASTConst> {
+        use ASTExprVariant::*;
+        match self {
+            Const(r#const) => Some(r#const.clone()),
+
+            Binop(_, _, _) => todo!(),
+            Unop(_, _) => todo!(),
+
+            Default(ty) if ty.is_const_constructible() => Some(match ty {
+                ASTType::Nil | ASTType::Any => ASTConst::Nil,
+                ASTType::Integer => ASTConst::Integer(0),
+                ASTType::Floating => ASTConst::Floating(0.),
+                ASTType::Boolean => ASTConst::False,
+                _ => unreachable!(),
+            }),
+
+            Color(ASTVariant { variant, args }) => Some(ASTConst::Color(ASTVariant {
+                variant: variant.clone(),
+                args: args
+                    .iter()
+                    .map(|expr| expr.eval_const_expr().ok_or(()))
+                    .collect::<Result<Vec<_>, _>>()
+                    .ok()?,
+            })),
+
+            Tuple(inner) => Some(ASTConst::Tuple(
+                inner
+                    .iter()
+                    .map(|expr| expr.eval_const_expr().ok_or(()))
+                    .collect::<Result<Vec<_>, _>>()
+                    .ok()?,
+            )),
+
+            Suffixed(_, _)
+            | FuncCall(_, _)
+            | FuncBind(_, _)
+            | MethodInvok(_, _, _)
+            | Table(_)
+            | Movement(_)
+            | Default(_)
+            | Var(_) => None,
+        }
+    }
+}
+
+impl Typed for ASTField {
+    #[inline]
+    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType {
+        match self {
+            ASTField::Expr(_, expr) => expr.get_type(ctx),
+            ASTField::Identifier(sp, name) => {
+                let var = ASTVar::new(ctx.strings()).span(sp).name(name.clone()).build();
+                ctx.get(&var)
+            }
+        }
+    }
+}
+
+impl MaybeConstExpr for ASTField {
+    #[inline]
+    fn is_const_expr(&self) -> bool {
+        match self {
+            ASTField::Expr(_, expr) => expr.is_const_expr(),
+            ASTField::Identifier(_, _) => false,
+        }
+    }
+
+    #[inline]
+    fn eval_const_expr(&self) -> Option<ASTConst> {
+        match self {
+            ASTField::Identifier(..) => None,
+            ASTField::Expr(_, expr) => expr.eval_const_expr(),
+        }
+    }
+}
+
+impl Default for ASTExprVariant {
+    fn default() -> Self {
+        ASTExprVariant::Const(ASTConst::Nil)
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/extension.rs b/src/Rust/vvs_lang/src/ast/extension.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3cf13f382f70bb48eca12107a8f0a5f4d6292e57
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/extension.rs
@@ -0,0 +1,11 @@
+use crate::ast::{ASTType, ASTTypeContext};
+
+#[inline]
+pub fn get_field_extensions(_: &ASTTypeContext, ass_type: ASTType) -> impl Iterator<Item = &(&'static str, ASTType)> {
+    log::error!("todo: add user options for each item");
+    match ass_type {
+        ASTType::Syllabe => [("start", ASTType::Integer), ("finish", ASTType::Integer)].iter(),
+        ASTType::Line => [("start", ASTType::Integer), ("finish", ASTType::Integer)].iter(),
+        _ => unreachable!(),
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/function.rs b/src/Rust/vvs_lang/src/ast/function.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6c20bc5b3d2ee5a59c60962931562b2751b64693
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/function.rs
@@ -0,0 +1,36 @@
+use crate::ast::*;
+
+/// A function. Can also represent a job.
+#[derive(Debug, Clone)]
+pub struct ASTFunction {
+    pub name: ASTString,
+    pub returns: ASTType,
+    pub arguments: Vec<ASTVar>,
+    pub content: ASTInstr,
+
+    pub span: ASTSpan,
+}
+
+/// The signature of a callable thing in Vivy Script.
+pub type ASTFunctionSignature = (Vec<ASTType>, ASTType);
+
+impl ASTFunction {
+    /// Get the signature of a function.
+    #[inline]
+    pub fn signature(&self) -> ASTFunctionSignature {
+        let args = self
+            .arguments
+            .iter()
+            .flat_map(ASTVar::get_specified_type)
+            .cloned()
+            .collect();
+        (args, self.returns.clone())
+    }
+
+    /// Get the type of this function, as a function tpe.
+    #[inline]
+    pub fn function_type(&self) -> ASTType {
+        let (args, returns) = self.signature();
+        ASTType::Function(args, Box::new(returns))
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/identifier.rs b/src/Rust/vvs_lang/src/ast/identifier.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4cc9e14457433e11ea9b0620f7df5a781fbe77ea
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/identifier.rs
@@ -0,0 +1,57 @@
+use crate::ast::*;
+
+#[derive(Debug, Default, PartialEq, Eq, Clone)]
+pub enum ASTIdentifier {
+    /// We ignore the value, like in ocaml and rust, this is the '_'.
+    #[default]
+    Joker,
+
+    /// A normal identifier, one that can be used by the user.
+    String(ASTString),
+
+    /// If an identifier begins by '_' and is followed other things then it is reserved by the
+    /// parser, the generator, and other things. Those identifiers can't be used by a user and they
+    /// should never see one.
+    Reserved(ASTString),
+}
+
+impl std::fmt::Display for ASTIdentifier {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_str(self.as_ref())
+    }
+}
+
+impl AsRef<str> for ASTIdentifier {
+    fn as_ref(&self) -> &str {
+        use ASTIdentifier::*;
+        match self {
+            Joker => "_",
+            String(str) | Reserved(str) => str.as_ref(),
+        }
+    }
+}
+
+impl ASTIdentifier {
+    /// Create a new identifier. The passed string will be trimed. If the string is empty or
+    /// contains non ascii-alphanumeric-underscored characters then an error will be raised.
+    pub fn new(cache: ASTStringCacheHandle, identifier: impl AsRef<str>) -> Result<Self, String> {
+        let identifier = identifier.as_ref().trim();
+        match identifier
+            .char_indices()
+            .find(|(_, c)| '_'.ne(c) && !c.is_ascii_alphanumeric())
+        {
+            Some((idx, char)) => Err(format!("found invalid character '{char}' in identifier at index {idx}")),
+            None => {
+                if identifier.is_empty() {
+                    Err("an identifier can't be empty".to_string())
+                } else if identifier.starts_with('_') && identifier.len() == 1 {
+                    Ok(Self::Joker)
+                } else if identifier.starts_with('_') {
+                    Ok(Self::Reserved(cache.get(identifier.trim_start_matches('_'))))
+                } else {
+                    Ok(Self::Reserved(cache.get(identifier)))
+                }
+            }
+        }
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/import.rs b/src/Rust/vvs_lang/src/ast/import.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f538506dc768ea17185b396dba7d1fc8d79eb676
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/import.rs
@@ -0,0 +1,77 @@
+use crate::ast::{ASTModule, ASTModulePtr, ASTString};
+use hashbrown::HashMap;
+use std::{
+    cell::RefCell,
+    path::{Path, PathBuf},
+    rc::Rc,
+};
+
+/// Structure used to resolve module imports.
+///
+/// By default, includes the current working dir.
+#[derive(Debug)]
+pub struct ImportResolver {
+    path: Vec<PathBuf>,
+    cache: Rc<RefCell<HashMap<ASTString, ASTModulePtr>>>,
+}
+
+pub(crate) enum ResolveResult {
+    Path(PathBuf),
+    Module(ASTModulePtr),
+}
+
+impl FromIterator<PathBuf> for ImportResolver {
+    #[inline]
+    fn from_iter<T: IntoIterator<Item = PathBuf>>(iter: T) -> Self {
+        Self { path: iter.into_iter().collect(), cache: Default::default() }
+    }
+}
+
+impl Default for ImportResolver {
+    /// Get the default import resolver, always includes the current working dir...
+    #[inline]
+    fn default() -> Self {
+        Self { path: vec![std::env::current_dir().expect("failed to get the CWD")], cache: Default::default() }
+    }
+}
+
+impl ImportResolver {
+    /// Create a new empty resolver. Note that it's different from the default resolver that uses
+    /// the current working directory (CWD, PWD, etc...)
+    #[inline]
+    pub fn empty() -> Self {
+        Self { path: vec![], cache: Default::default() }
+    }
+
+    pub(crate) fn resolve(&self, module: impl AsRef<str>) -> Option<ResolveResult> {
+        let find = |prefix| Self::get_file_path(prefix, module.as_ref()).map(ResolveResult::Path);
+        self.cache
+            .borrow()
+            .get(module.as_ref())
+            .cloned()
+            .map(ResolveResult::Module)
+            .or_else(|| self.path.iter().find_map(find))
+    }
+
+    #[inline]
+    pub(crate) fn cache_module(&self, name: ASTString, module: ASTModulePtr) {
+        if let Some(module) = self.cache.borrow_mut().insert(name, module) {
+            log::error!("re-cache module `{}`", ASTModule::get(&module).name())
+        }
+    }
+
+    fn get_file_path(prefix: impl AsRef<Path>, module: impl AsRef<str>) -> Option<PathBuf> {
+        let mut file = prefix.as_ref().join(module.as_ref());
+        file.set_extension("vvl");
+        file.canonicalize()
+            .map_err(|err| match err.kind() {
+                std::io::ErrorKind::NotFound => (),
+                err => log::error!(
+                    "failed to lookup for `{}` in `{}`: {err}",
+                    module.as_ref(),
+                    prefix.as_ref().to_string_lossy()
+                ),
+            })
+            .ok()
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/instruction.rs b/src/Rust/vvs_lang/src/ast/instruction.rs
new file mode 100644
index 0000000000000000000000000000000000000000..57e64ffa2f497b3fae66521c4e5453a0b73b01fc
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/instruction.rs
@@ -0,0 +1,187 @@
+use crate::ast::*;
+use std::ops::{Deref, DerefMut};
+
+#[macro_export]
+macro_rules! anon_instruction {
+    ($variant: ident $($args: tt)?) => {
+        ASTInstr {
+            span: Default::default(),
+            content: ASTInstrVariant::$variant $($args)?,
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! instruction {
+    ($span: expr, $variant: ident $($args: tt)?) => {
+        ASTInstr {
+            span: $span.into(),
+            content: ASTInstrVariant::$variant $($args)?,
+        }
+    };
+}
+
+/// Instructions.
+#[derive(Debug, Clone)]
+pub struct ASTInstr {
+    pub content: ASTInstrVariant,
+    pub span: ASTSpan,
+}
+
+/// Instructions.
+#[derive(Debug, PartialEq, Clone)]
+pub enum ASTInstrVariant {
+    /// Declare variables with something inside.
+    Decl(Vec<ASTVar>, Vec<ASTExpr>),
+
+    /// Assign into variables.
+    Assign(Vec<ASTExpr>, Vec<ASTExpr>),
+
+    /// A function call.
+    FuncCall(Box<ASTExpr>, Vec<ASTExpr>),
+
+    /// A method invokation.
+    MethodInvok(Box<ASTExpr>, ASTString, Vec<ASTExpr>),
+
+    /// Begin a block.
+    Block(Vec<ASTInstr>),
+
+    /// A WhileDo instruction.
+    WhileDo(ASTCondition, Box<ASTInstr>),
+
+    /// Conditionals, contract the elseid blocks.
+    Cond { if_blocks: Vec<(ASTCondition, ASTInstr)>, else_block: Option<Box<ASTInstr>> },
+
+    /// For loop, the classic one:
+    /// ```vvs
+    /// for elem = 1, 3, 1 do print(elem) end
+    /// ```
+    ForLoop { var: ASTVar, lower: ASTExpr, upper: ASTExpr, step: Option<ASTInteger>, body: Box<ASTInstr> },
+
+    /// For loop with an iterable expression (table):
+    /// ```vvs
+    /// for elem in { 1, 2, 3 } do print(elem) end
+    /// for elem in ( 1, 2, 3 ) do print(elem) end
+    /// for elem in my_table    do print(elem) end
+    /// ```
+    ForInto { var: ASTVar, list: ASTExpr, body: Box<ASTInstr> },
+
+    /// Just a noop.
+    Noop,
+
+    /// Final thing: break from block.
+    Break,
+
+    /// Final thing: continue to next iteration.
+    Continue,
+
+    /// Final thing: return something.
+    Return(ASTExpr),
+}
+
+impl PartialEq for ASTInstr {
+    fn eq(&self, other: &Self) -> bool {
+        self.content == other.content
+    }
+}
+
+fn get_instruction_slice_type(ctx: &ASTTypeContext, block: &[ASTInstr]) -> ASTType {
+    let Some((last, instructions)) = block.split_last() else {
+        return ASTType::Nil;
+    };
+    let coerce_type = |from: ASTType, var: &ASTVar| {
+        let (span, ty, name) = (var.span(), var.get_specified_type().unwrap_or(&from), var.name());
+        let strings = ctx.strings();
+        let var = ASTVar::new(strings).span(span).name(name.clone());
+        if from.coercible_to(ty) {
+            var.with_type(from).build()
+        } else {
+            log::error!(target: "cc", "{span}; try to assign value of type `{from}` into `{name}: {ty}`");
+            var.with_type(ASTType::Nil).build()
+        }
+    };
+    let fold_declaration = |mut ctx, (var, from): (&ASTVar, &ASTExpr)| {
+        let var = coerce_type(from.get_type(&ctx), var);
+        let (_, var_ty) = (var.span(), var.get_type(&ctx));
+        ctx.declare(var, var_ty);
+        ctx
+    };
+    let fold_on_declaration = |ctx, instruction: &ASTInstr| match &instruction.content {
+        ASTInstrVariant::Decl(vars, froms) => vars.iter().zip(froms.iter()).fold(ctx, fold_declaration),
+        _ => ctx,
+    };
+    last.get_type(&instructions.iter().fold(ctx.for_scope(), fold_on_declaration))
+}
+
+impl Typed for ASTInstrVariant {
+    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType {
+        match self {
+            ASTInstrVariant::Decl(_, _)
+            | ASTInstrVariant::Noop
+            | ASTInstrVariant::Assign(_, _)
+            | ASTInstrVariant::Break
+            | ASTInstrVariant::Continue => ASTType::Nil,
+
+            ASTInstrVariant::WhileDo(_, _) | ASTInstrVariant::ForLoop { .. } | ASTInstrVariant::ForInto { .. } => {
+                ASTType::Nil
+            }
+
+            ASTInstrVariant::Return(expr) => expr.get_type(ctx),
+            ASTInstrVariant::Block(block) => get_instruction_slice_type(ctx, block),
+            ASTInstrVariant::Cond { if_blocks, else_block } => {
+                let mut types = else_block
+                    .as_ref()
+                    .map(|i| i.get_type(ctx))
+                    .into_iter()
+                    .chain(if_blocks.iter().map(|(_, i)| i.get_type(ctx)));
+                types
+                    .next()
+                    .and_then(|ty| types.all(|other| ty.eq(&other)).then_some(ty))
+                    .unwrap_or_default()
+            }
+
+            ASTInstrVariant::MethodInvok(_, _, _) | ASTInstrVariant::FuncCall(_, _) => todo!("implement clozures"),
+        }
+    }
+}
+
+impl Deref for ASTInstr {
+    type Target = ASTInstrVariant;
+
+    fn deref(&self) -> &Self::Target {
+        &self.content
+    }
+}
+
+impl DerefMut for ASTInstr {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.content
+    }
+}
+
+impl VariantName for ASTInstr {
+    fn variant_name(&self) -> &'static str {
+        self.content.variant_name()
+    }
+}
+
+impl VariantName for ASTInstrVariant {
+    fn variant_name(&self) -> &'static str {
+        match self {
+            ASTInstrVariant::Decl(_, _) => "variable declaration",
+            ASTInstrVariant::Assign(_, _) => "variable assignation",
+            ASTInstrVariant::FuncCall(_, _) => "function call",
+            ASTInstrVariant::MethodInvok(_, _, _) => "method invokation",
+            ASTInstrVariant::Block(_) => "instruction block",
+            ASTInstrVariant::WhileDo(_, _) => "while loop",
+            ASTInstrVariant::Cond { .. } => "conditionals",
+            ASTInstrVariant::ForLoop { step: Some(_), .. } => "for loop with step",
+            ASTInstrVariant::ForLoop { step: None, .. } => "for loop",
+            ASTInstrVariant::ForInto { .. } => "for into loop",
+            ASTInstrVariant::Noop => "noop",
+            ASTInstrVariant::Break => "break statement",
+            ASTInstrVariant::Continue => "continue statement",
+            ASTInstrVariant::Return(_) => "return statement",
+        }
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/maybe_const_expr.rs b/src/Rust/vvs_lang/src/ast/maybe_const_expr.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d0e05e45bda905e3204437f52119bb33c5fd4a7e
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/maybe_const_expr.rs
@@ -0,0 +1,26 @@
+use crate::ast::*;
+use std::ops::Deref;
+
+/// Trait for objects that are typed and may be values known at compile time.
+///
+/// As long a a type can be dereferenced into a [MaybeConstExpr] thing, it is [MaybeConstExpr].
+pub trait MaybeConstExpr: Typed {
+    /// Tells whether the thing is a constant expression or not.
+    fn is_const_expr(&self) -> bool;
+
+    /// Evaluate the expression, if it is indeed a constant expression then returns the result,
+    /// otherwise return [None].
+    fn eval_const_expr(&self) -> Option<ASTConst>;
+}
+
+impl<S: MaybeConstExpr, T: Deref<Target = S>> MaybeConstExpr for T {
+    #[inline]
+    fn is_const_expr(&self) -> bool {
+        self.deref().is_const_expr()
+    }
+
+    #[inline]
+    fn eval_const_expr(&self) -> Option<ASTConst> {
+        self.deref().eval_const_expr()
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/mod.rs b/src/Rust/vvs_lang/src/ast/mod.rs
index 99fe75f81773539ae067e481bc9e23fd5f7e82f4..8da5d32a697e4af2817e09246c41e5b127c1b000 100644
--- a/src/Rust/vvs_lang/src/ast/mod.rs
+++ b/src/Rust/vvs_lang/src/ast/mod.rs
@@ -1,7 +1,64 @@
+//! Module used to store all the definition of the AST used for parsing VVS/VVL files.
+
+mod constant;
+mod expression;
+mod extension;
+mod function;
+mod identifier;
+mod import;
+mod instruction;
+mod maybe_const_expr;
 mod module;
+mod options;
+mod pattern;
 mod program;
 mod span;
 mod string;
-mod tree;
+mod type_context;
+mod typed;
+mod types;
+mod variable;
+mod variant;
+mod visibility;
+
+use hashbrown::HashMap;
+use std::rc::Rc;
+
+pub use self::{
+    constant::*, expression::*, extension::*, function::*, identifier::*, import::*, instruction::*,
+    maybe_const_expr::*, module::*, options::*, pattern::*, program::*, span::*, string::*, type_context::*, typed::*,
+    types::*, variable::*, variant::*, visibility::*,
+};
+
+pub type ASTString = Rc<str>;
+pub type ASTFloating = f32;
+pub type ASTInteger = i32;
+pub type ASTTable<T> = HashMap<ASTString, T>;
+
+pub fn write_ast_table<T: std::fmt::Display>(f: &mut std::fmt::Formatter<'_>, table: &ASTTable<T>) -> std::fmt::Result {
+    f.write_str("{")?;
+    if let Some((key, value)) = table.iter().next() {
+        write!(f, " {key} = {value}")?;
+    }
+    for (key, value) in table.iter().skip(1) {
+        write!(f, ", {key} = {value}")?;
+    }
+    f.write_str(" }")
+}
+
+pub fn write_ast_tuple<T: std::fmt::Display>(f: &mut std::fmt::Formatter<'_>, tuple: &[T]) -> std::fmt::Result {
+    f.write_str("(")?;
+    if let Some(value) = tuple.iter().next() {
+        write!(f, " {value}")?;
+    }
+    for value in tuple.iter().skip(1) {
+        write!(f, ", {value}")?;
+    }
+    f.write_str(" )")
+}
 
-pub use self::{module::*, program::*, span::*, string::*, tree::*};
+/// Trait that allows to get a variant name out of an enum or a struct containing an enum.
+pub(crate) trait VariantName {
+    /// Get the name out of the value.
+    fn variant_name(&self) -> &'static str;
+}
diff --git a/src/Rust/vvs_lang/src/ast/module.rs b/src/Rust/vvs_lang/src/ast/module.rs
index 335c8b9aad07a0f33f0a122856e83ee80d203eb8..d7eba73a8221a7e8f2fd41f580a6b49f12a58232 100644
--- a/src/Rust/vvs_lang/src/ast/module.rs
+++ b/src/Rust/vvs_lang/src/ast/module.rs
@@ -1,82 +1,201 @@
-use super::{tree::*, ASTStringCacheHandle};
+use crate::ast::*;
 use hashbrown::{HashMap, HashSet};
-use std::{cell::RefCell, rc::Rc};
+use std::{
+    cell::UnsafeCell,
+    rc::{Rc, Weak},
+};
 
 /// A VVL module of a Vivy Script
-pub struct Module {
-    functions: HashMap<ASTString, ASTFunction>,
-    jobs: HashMap<ASTString, ASTJob>,
-    consts: HashMap<ASTString, (ASTVar, ASTConst)>,
+#[derive(Debug, Clone)]
+pub struct ASTModule {
+    /// The name of the module, should be a valid identifier.
+    name: ASTString,
+
+    /// Checks if we want to put it into the type context or not...
+    variants: HashMap<ASTString, ASTVariantRules>,
+
+    functions: HashMap<ASTString, (ASTVisibility, ASTFunction)>,
+    jobs: HashMap<ASTString, (ASTVisibility, ASTFunction)>,
+    consts: HashMap<ASTString, (ASTVisibility, ASTVar, ASTConst)>,
     options: HashMap<ASTString, (ASTVar, ASTConst)>,
-    imports: HashSet<ASTString>,
+    imports: HashMap<ASTString, (ASTSpan, ASTModulePtr)>,
+
+    /// Contains all the symbols available in the module, to be sure that options, constants,
+    /// functions and jobs doesn't enter in collision.
+    symbols: HashSet<ASTString>,
 
-    /// Caching for strings, identified by theyr hash and reuse the same memory location to reduce
+    /// Caching for strings, identified by their hash and reuse the same memory location to reduce
     /// memory footprint. Use the .finish function from the hasher to get the key.
-    strings: Rc<RefCell<HashMap<u64, ASTString>>>,
+    strings: ASTStringCacheHandle,
+
+    /// Type context intern to the module. This is self-referencing. Under the hood we use a weak
+    /// pointer and a lazy initialize thingy for the type context.
+    tyctx: ASTTypeContext,
 }
 
-/// Here, all the getters...
-impl Module {
+pub type ASTModulePtr = Rc<UnsafeCell<ASTModule>>;
+pub type ASTModuleWeakPtr = Weak<UnsafeCell<ASTModule>>;
+
+impl ASTModule {
+    /// Create a new empty module.
+    #[inline]
+    pub fn new(name: ASTString, strings: ASTStringCacheHandle) -> ASTModulePtr {
+        Rc::new_cyclic(|ptr| {
+            let colors_rules = ASTVariantRules::new_colors(strings.clone());
+            let movement_rules = ASTVariantRules::new_movements(strings.clone());
+            UnsafeCell::new(Self {
+                name,
+                strings,
+                tyctx: ASTTypeContext::new(ptr.clone()),
+                variants: HashMap::from_iter([
+                    (colors_rules.name(), colors_rules),
+                    (movement_rules.name(), movement_rules),
+                ]),
+                symbols: Default::default(),
+                functions: Default::default(),
+                jobs: Default::default(),
+                consts: Default::default(),
+                options: Default::default(),
+                imports: Default::default(),
+            })
+        })
+    }
+
+    /// Get all the variant rules.
+    #[inline]
+    pub fn all_variant_rules(&self) -> &HashMap<ASTString, ASTVariantRules> {
+        &self.variants
+    }
+
+    /// Get a set of rule for a specified variant if it exists in a mutable way. We only expose
+    /// this function to this crate because it's the only place where we want to be able to mutate
+    /// the module.
+    #[inline]
+    pub(crate) fn variant_rules_mut(&mut self, rule: impl AsRef<str>) -> Option<&mut ASTVariantRules> {
+        self.variants.get_mut(rule.as_ref())
+    }
+
+    /// Get the type context in a constant way.
+    #[inline]
+    pub fn tyctx(&self) -> &ASTTypeContext {
+        &self.tyctx
+    }
+
+    /// Get the type context in a mutable way. Only possible if we have a mutable reference to the
+    /// module anyway. If there are multiple strong references to the module it won't be correct...
+    #[inline]
+    pub fn tyctx_mut(&mut self) -> &mut ASTTypeContext {
+        &mut self.tyctx
+    }
+
+    /// Get the name of the module.
+    #[inline]
+    pub fn name(&self) -> ASTString {
+        self.name.clone()
+    }
+
+    /// Get a specific option if it exists.
+    #[inline]
+    pub fn option(&self, option: impl AsRef<str>) -> Option<&(ASTVar, ASTConst)> {
+        self.options.get(option.as_ref())
+    }
+
+    /// Get a job by its name, returns [None] if the job was not defined.
+    #[inline]
+    pub fn job(&self, name: impl AsRef<str>) -> Option<&ASTFunction> {
+        self.jobs.get(name.as_ref()).map(|(_, job)| job)
+    }
+
+    /// Get a function by its name, returns [None] if the function was not defined.
+    #[inline]
+    pub fn function(&self, name: impl AsRef<str>) -> Option<&ASTFunction> {
+        self.functions.get(name.as_ref()).map(|(_, function)| function)
+    }
+
+    /// Get all the options... All the options are public by design so no visibility rule is
+    /// necessary to query them.
+    #[inline]
+    pub fn options(&self) -> impl Iterator<Item = (&ASTVar, &ASTConst)> {
+        self.options.values().map(|(a, b): &(_, _)| (a, b))
+    }
+
+    /// Get all the constants with the specified visibility rule.
+    #[inline]
+    pub fn consts(&self, rule: ASTVisibilityRule) -> impl Iterator<Item = (&ASTVar, &ASTConst)> {
+        self.consts
+            .values()
+            .filter_map(move |(v, var, value)| (rule.allows(*v)).then_some((var, value)))
+    }
+
+    /// Get all the functions from the module with the specified visibility rule.
+    #[inline]
+    pub fn functions(&self, rule: ASTVisibilityRule) -> impl Iterator<Item = (ASTString, &ASTFunction)> {
+        self.functions
+            .values()
+            .filter_map(move |(v, f)| rule.allows(*v).then_some((f.name.clone(), f)))
+    }
+
+    /// Get all the jobs from the module with the specified visibility rule.
+    #[inline]
+    pub fn jobs(&self, rule: ASTVisibilityRule) -> impl Iterator<Item = (ASTString, &ASTFunction)> {
+        self.jobs
+            .values()
+            .filter_map(move |(v, f)| rule.allows(*v).then_some((f.name.clone(), f)))
+    }
+
+    /// Get all the callable items from the module with the specified visibility rule. This
+    /// includes jobs and functions.
+    pub(crate) fn callables(&self, rule: ASTVisibilityRule) -> impl Iterator<Item = (ASTString, &ASTFunction)> {
+        self.functions(rule).chain(self.jobs(rule))
+    }
+
+    /// Get all the jobs from a module in a mutable way, with the specified visibility rule.
+    pub(crate) fn jobs_mut(&mut self, rule: ASTVisibilityRule) -> impl Iterator<Item = (ASTString, &mut ASTFunction)> {
+        self.jobs
+            .values_mut()
+            .filter_map(move |(v, f)| rule.allows(*v).then_some((f.name.clone(), f)))
+    }
+
+    /// Get all the fonctions from a module in a mutable way, with the specified visibility rule.
+    pub(crate) fn functions_mut(
+        &mut self,
+        rule: ASTVisibilityRule,
+    ) -> impl Iterator<Item = (ASTString, &mut ASTFunction)> {
+        self.functions
+            .values_mut()
+            .filter_map(move |(v, f)| rule.allows(*v).then_some((f.name.clone(), f)))
+    }
+
+    /// Get the imported modules, required by the current module.
+    #[inline]
+    pub fn imports(&self) -> impl Iterator<Item = &ASTModule> + '_ {
+        self.imports.iter().map(|(_, (_, module))| ASTModule::get(module))
+    }
+
+    /// Get the import location of a module, for debug purpose.
+    #[inline]
+    pub fn get_import_location(&self, import: &ASTString) -> Option<ASTSpan> {
+        self.imports
+            .iter()
+            .find_map(|(module, (span, _))| import.eq(module).then_some(*span))
+    }
+
     /// Get a handle to the string cache.
-    pub fn strings(&mut self) -> ASTStringCacheHandle {
-        ASTStringCacheHandle::new(self.strings.borrow_mut())
+    #[inline]
+    pub fn strings(&self) -> &ASTStringCacheHandle {
+        &self.strings
     }
-}
 
-/// Here all the setters, we try to have pure functions.
-impl Module {
-    /// Declare a new function.
-    ///
-    /// TODO: Use the entry thingy which should be better...
-    pub fn declare_function(mut self, name: ASTString, function: ASTFunction) -> Self {
-        if self.functions.contains_key(&name) {
-            log::warn!(target: "cc", ";re-definition of function {name} at {}", function.span);
-        }
-        self.functions.insert(name, function);
-        self
-    }
-
-    /// Declare a new job.
-    ///
-    /// TODO: Use the entry thingy which should be better...
-    pub fn declare_job(mut self, name: ASTString, job: ASTJob) -> Self {
-        if self.jobs.contains_key(&name) {
-            log::warn!(target: "cc", ";re-definition of job {name} at {}", job.span);
-        }
-        self.jobs.insert(name, job);
-        self
-    }
-
-    /// Declare a new option.
-    ///
-    /// TODO: Use the entry thingy which should be better...
-    pub fn declare_option(self, var: ASTVar, value: ASTConst) -> Self {
-        todo!()
-    }
-
-    /// Declare a new constant.
-    ///
-    /// TODO: Use the entry thingy which should be better...
-    pub fn declare_const(self, var: ASTVar, value: ASTConst) -> Self {
-        todo!()
-    }
-
-    /// Declare a new import.
-    ///
-    /// TODO: Use the entry thingy which should be better...
-    pub fn declare_import(self, import: ASTString) -> Self {
-        todo!()
+    /// Get a const reference to the module. As long as you don't use the [ASTModule::get_mut]
+    /// function, this one should be Ok.
+    #[inline]
+    pub(crate) fn get(this: &ASTModulePtr) -> &ASTModule {
+        unsafe { &*this.as_ref().get() }
     }
-}
 
-impl std::fmt::Debug for Module {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("Module")
-            .field("functions", &self.functions)
-            .field("jobs", &self.jobs)
-            .field("consts", &self.consts)
-            .field("options", &self.options)
-            .field("imports", &self.imports)
-            .finish()
+    /// Get a mutable reference to the module... Unsafe!
+    #[inline]
+    pub(crate) fn get_mut(this: &ASTModulePtr) -> *mut ASTModule {
+        this.as_ref().get()
     }
 }
diff --git a/src/Rust/vvs_lang/src/ast/options.rs b/src/Rust/vvs_lang/src/ast/options.rs
new file mode 100644
index 0000000000000000000000000000000000000000..13d45a6fe8671464b11b6113932f7e6c50c60daa
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/options.rs
@@ -0,0 +1,64 @@
+use crate::ast::*;
+use anyhow::{bail, Context};
+use hashbrown::HashMap;
+
+/// Options for a program, represent the thing that is red from a file.
+pub struct OptionTable {
+    modules: HashMap<ASTString, ASTTable<ASTConst>>,
+}
+
+impl OptionTable {
+    pub fn new(cache: &ASTStringCacheHandle, values: toml::Table) -> anyhow::Result<Self> {
+        let modules = HashMap::with_capacity(values.len());
+        let modules = values.into_iter().try_fold(modules, |mut modules, (name, values)| {
+            use hashbrown::hash_map::EntryRef::*;
+            let toml::Value::Table(values) = values else {
+                bail!("expected a table for `{name}`")
+            };
+            let table = modules
+                .entry(cache.get(&name))
+                .or_insert(ASTTable::with_capacity(values.len()));
+            values
+                .into_iter()
+                .try_for_each(|(option, value)| match table.entry_ref(option.as_str()) {
+                    Occupied(_) => bail!("redefinition of option `{option}` in module `{name}`"),
+                    Vacant(entry) => {
+                        entry.insert(ASTConst::from_toml_value(cache, value)?);
+                        Ok(())
+                    }
+                })?;
+            if table.is_empty() {
+                modules.remove(name.as_str());
+            }
+            Ok(modules)
+        });
+        Ok(Self { modules: modules.context("invalid toml file")? })
+    }
+}
+
+impl Iterator for OptionTable {
+    type Item = ((ASTString, ASTString), ASTConst);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let Self { modules } = self;
+        let module = modules.keys().next()?.clone();
+
+        let values = match modules.get_mut(&module) {
+            Some(values) => values,
+            None => {
+                modules.remove(&module);
+                return None;
+            }
+        };
+
+        let (option, value) = match values.keys().next().cloned() {
+            Some(option) => values.remove_entry(&option)?,
+            None => {
+                modules.remove(&module);
+                return None;
+            }
+        };
+
+        Some(((module, option), value))
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/pattern.rs b/src/Rust/vvs_lang/src/ast/pattern.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5b3707d425486bd8dc5e8aa8ae3ed285fc331d2c
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/pattern.rs
@@ -0,0 +1,39 @@
+//! In this file we declare things needed to do the pattern matching or boolean check for
+//! conditionals.
+//!
+//! Note that we can only pattern match variants.
+
+use crate::ast::*;
+
+/// A condition, two expression must be equal, or should we try to match a thing.
+#[derive(Debug, PartialEq, Clone)]
+pub enum ASTCondition {
+    /// Usual if check.
+    BooleanTrue(ASTExpr),
+
+    /// Does the expression can be pattern-matched or not. This is only for variants.
+    BindVariant { as_type: ASTType, variant: ASTString, pattern: Vec<ASTPatternElement>, source: ASTVar },
+
+    /// Tells whever a variable is coercible into a type or not.
+    CoercibleInto { new: ASTVar, as_type: ASTType, source: ASTVar },
+}
+
+/// When we match a pattern, we can do conditionals on the value of elements, or we can bind
+/// variables that will be visible in the if/elseif/if-let statement.
+#[derive(Debug, PartialEq, Clone)]
+pub enum ASTPatternElement {
+    /// Must be equal to this thing.
+    Const(ASTConst),
+
+    /// Expose this field of the struct in the block if the struct matched.
+    Var(ASTVar),
+}
+
+impl ASTPatternElement {
+    pub fn span(&self) -> Option<ASTSpan> {
+        match self {
+            ASTPatternElement::Const(_) => None,
+            ASTPatternElement::Var(var) => Some(var.span()),
+        }
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/program.rs b/src/Rust/vvs_lang/src/ast/program.rs
index c0691a0cdb1c4b6c9df71815acebe52a93c9a5ed..67088e1efc1f6c3351b22041462517c24290efdf 100644
--- a/src/Rust/vvs_lang/src/ast/program.rs
+++ b/src/Rust/vvs_lang/src/ast/program.rs
@@ -1,19 +1,15 @@
-use crate::{ast::*, parser::*};
-use hashbrown::{HashMap, HashSet};
-use std::{cell::RefCell, rc::Rc};
+use crate::ast::*;
+use hashbrown::HashMap;
 
 /// The first element of the tuple is the destination variable, the second is the tuple to describe
 /// the job picked from a module, the last is the list of variables to use as input for this job.
-pub type ProgramOperation = (ASTString, (ASTString, ASTString), Vec<ASTString>);
+pub type ProgramOperation = (ASTSpan, ASTString, (ASTString, ASTString), Option<Vec<ASTConst>>, Vec<ASTString>);
 
 /// The main VVS file/program.
-pub struct Program {
-    modules: HashMap<ASTString, Module>,
-
-    /// Options specified in the VVL module. All options must be constants.
-    ///
-    /// TODO: Remove that, use the options from the modules directly...
-    options: Vec<((ASTString, ASTVar), ASTConst)>,
+#[derive(Debug)]
+pub struct ASTProgram {
+    /// The list of all the modules used in the program, with their import location.
+    modules: HashMap<ASTString, (ASTSpan, ASTModulePtr)>,
 
     /// The setted options, from the VVS file.
     setted: Vec<((ASTString, ASTString), ASTConst)>,
@@ -29,104 +25,116 @@ pub struct Program {
 
     /// Caching for strings, identified by theyr hash and reuse the same memory location to reduce
     /// memory footprint. Use the .finish function from the hasher to get the key.
-    strings: Rc<RefCell<HashMap<u64, ASTString>>>,
+    strings: ASTStringCacheHandle,
 }
 
-/// Here we have all the getters...
-impl Program {
+impl ASTProgram {
+    pub fn new(strings: ASTStringCacheHandle) -> Self {
+        Self {
+            initial_var: strings.get("INIT"),
+            setted: Default::default(),
+            writes: Default::default(),
+            modules: Default::default(),
+            operations: Default::default(),
+            strings,
+        }
+    }
+
+    /// Iterate over all the modules in the program.
+    #[inline]
+    pub fn modules(&self) -> impl Iterator<Item = &ASTModule> + '_ {
+        self.modules.values().map(|(_, module)| ASTModule::get(module))
+    }
+
     /// Get a handle to the string cache.
-    pub fn strings(&mut self) -> ASTStringCacheHandle {
-        ASTStringCacheHandle::new(self.strings.borrow_mut())
+    #[inline]
+    pub fn strings(&self) -> &ASTStringCacheHandle {
+        &self.strings
     }
 
     /// Get a const reference to a module.
-    pub fn module(&self, name: impl AsRef<str>) -> Option<&Module> {
-        self.modules.get(name.as_ref())
+    pub fn module(&self, name: impl AsRef<str>) -> Option<&ASTModule> {
+        self.modules
+            .get(name.as_ref())
+            .map(|(_, module)| ASTModule::get(module))
+    }
+
+    /// Get the pointer to a module. Returns [None] if the module was not present in the program.
+    ///
+    /// # Safety
+    /// With this function we create the possibility to make multiple mutable references to the
+    /// same module down the line, so we mark it as an unsafe operation for now...
+    pub(crate) unsafe fn module_ptr(&self, name: impl AsRef<str>) -> Option<ASTModulePtr> {
+        self.modules.get(name.as_ref()).map(|(_, ptr)| ptr.clone())
+    }
+
+    /// Get all the available options for this program, with their default value.
+    pub fn available_options(&self) -> impl Iterator<Item = (ASTString, &ASTVar, &ASTConst)> {
+        self.modules()
+            .flat_map(|module| module.options().map(|(var, def)| (module.name(), var, def)))
     }
 
-    /// Get a mutable reference to a module.
-    pub fn module_mut(&mut self, name: impl AsRef<str>) -> Option<&mut Module> {
-        self.modules.get_mut(name.as_ref())
+    /// Get all the setted options from the program.
+    #[inline]
+    pub fn setted_options(&self) -> &[((ASTString, ASTString), ASTConst)] {
+        self.setted.as_ref()
     }
 
     /// Get the value for an option. For the resolution: we first take the value from the setted
     /// list before the default value. Note that if we set an option that was never declared we
     /// don't return it here, it should have raised a warning and should not be used in the code
     /// anyway.
-    pub fn options(&self, module: &ASTString, name: &ASTString) -> Option<&ASTConst> {
+    pub fn option(&self, module: &ASTString, name: &ASTString) -> Option<ASTConst> {
         let default = self
-            .options
-            .iter()
-            .find_map(|((mm, var), val)| (*module == *mm && *name == *var.name()).then_some(val))?;
+            .module(module)?
+            .options()
+            .find_map(|(var, val)| var.name().eq(name).then_some(val))?
+            .clone();
         let setted = self
             .setted
             .iter()
             .find_map(|((mm, var), val)| (*module == *mm && *name == *var).then_some(val));
-        Some(setted.unwrap_or(default))
+        Some(setted.cloned().unwrap_or(default))
     }
-}
 
-/// Here we have all the setters... We always take the [Program] and return a new one for the
-/// functions to be pure.
-impl Program {
-    /// Get the operations and the variables to write. Can return an error if a variable was
-    /// assigned multiple times or if a variable to write was never assigned.
-    pub fn into_operations(self) -> VVResult<(ASTString, Vec<ProgramOperation>, Vec<ASTString>)> {
-        let assigned = HashSet::<ASTString>::from_iter(
-            self.operations
-                .iter()
-                .map(|(dest, ..)| dest.clone())
-                .chain([self.initial_var.clone()]),
-        );
-        if let Some(unwritten) = self.writes.1.iter().find(|var| !assigned.contains(*var)) {
-            return Err(VVError::ErrorMsg(
-                self.writes.0,
-                format!("variable `{unwritten}` can't be saved because it was never assigned"),
-            ));
-        }
-        let res = (self.initial_var, self.writes);
-        todo!("add the verified operations to {res:?}")
+    /// Get the operations and the variables to write. Note that no check is done here.
+    pub fn as_operations(&self) -> (ASTString, Vec<ProgramOperation>, Vec<ASTString>) {
+        (self.initial_var.clone(), self.operations.clone(), self.writes.1.clone())
+    }
+
+    #[inline]
+    pub(crate) fn writes_span(&self) -> ASTSpan {
+        self.writes.0
     }
 
     /// Set an option in the [Program], if the option was already set or was not declared in a
     /// [Module] we raise a warning.
     pub fn set_option(mut self, module: ASTString, name: ASTString, value: ASTConst) -> Self {
         if self
-            .options
-            .iter()
-            .any(|((mm, nn), _)| *mm == module && name == *nn.name())
+            .module(&module)
+            .map(|module| module.options().any(|(var, _)| var.name().eq(&name)))
+            .unwrap_or_default()
         {
             log::warn!(target: "cc", ";set option {module}.{name} which was not declared");
-        }
-        if self.setted.iter().any(|((mm, nn), _)| *mm == module && name == *nn) {
+        } else if self.setted.iter().any(|((mm, nn), _)| *mm == module && name == *nn) {
             log::warn!(target: "cc", ";re-set option {module}.{name}");
         }
         self.setted.push(((module, name), value));
         self
     }
 
-    /// Add an option to the module. We try to expose a functional semantic for the usage of the
-    /// [Program] struct to help the parsing implementation.
-    pub fn declare_option(mut self, module: ASTString, var: ASTVar, value: ASTConst) -> VVResult<Self> {
-        let key = (module, var);
-        if let Some(old) = self.options.iter().find_map(|(k, _)| key.eq(k).then_some(k.1 .0)) {
-            Err(VVError::OptionRedefined(old, key.0, key.1))
-        } else {
-            self.options.push((key, value));
-            Ok(self)
+    /// Import a module into the program.
+    #[inline]
+    pub(crate) fn import_module(mut self, name: ASTString, span: ASTSpan, module: ASTModulePtr) -> Self {
+        if let Some((_, module)) = self.modules.insert(name, (span, module)) {
+            log::warn!(target: "cc", ";re-import of module `{}`", ASTModule::get(&module).name())
         }
+        self
     }
-}
 
-impl std::fmt::Debug for Program {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("Program")
-            .field("modules", &self.modules)
-            .field("options", &self.options)
-            .field("setted", &self.setted)
-            .field("operations", &self.operations)
-            .field("writes", &self.writes)
-            .field("initial_var", &self.initial_var)
-            .finish()
+    /// Use options from a toml file to set things in the program and simplify a bit said
+    /// program...
+    pub fn with_options(self, _options: OptionTable) -> Self {
+        self
     }
 }
diff --git a/src/Rust/vvs_lang/src/ast/span.rs b/src/Rust/vvs_lang/src/ast/span.rs
index 25c56237168a3258213033a1ed94ab6c1ca48400..512ad50d1b63f85a037387efc47b173e98d07d36 100644
--- a/src/Rust/vvs_lang/src/ast/span.rs
+++ b/src/Rust/vvs_lang/src/ast/span.rs
@@ -16,6 +16,7 @@ impl std::fmt::Display for ASTSpan {
 impl ASTSpan {
     /// Create the span out of a line and column and an offset. The lines and
     /// columns begeins at 1. The offset begins at 0.
+    #[inline]
     pub fn new(line: u64, column: u64, offset: u64) -> Self {
         assert!(line >= 1);
         assert!(column >= 1);
@@ -23,16 +24,19 @@ impl ASTSpan {
     }
 
     /// Get the column of the span. The column starts at 1
+    #[inline]
     pub fn line(&self) -> u64 {
         self.line
     }
 
     /// Get the column of the span. The column starts at 1
+    #[inline]
     pub fn column(&self) -> u64 {
         self.column
     }
 
     /// Get the offset of the span.
+    #[inline]
     pub fn offset(&self) -> u64 {
         self.offset
     }
@@ -40,6 +44,7 @@ impl ASTSpan {
     /// Merge two spans. For now we just take the first one (the one with the
     /// lesser offset, i.e. the minimal one). In the future we will update the
     /// length field (when it's added to the structure...)
+    #[inline]
     pub fn merge(s1: Self, s2: Self) -> Self {
         if PartialOrd::gt(&s1, &s2) {
             s2
@@ -49,17 +54,22 @@ impl ASTSpan {
     }
 }
 
-impl From<nom_locate::LocatedSpan<&str>> for ASTSpan {
-    fn from(span: nom_locate::LocatedSpan<&str>) -> Self {
-        Self {
-            line: span.location_line() as u64,
-            column: span.naive_get_utf8_column() as u64,
-            offset: span.location_offset() as u64,
-        }
+impl From<&ASTSpan> for ASTSpan {
+    #[inline]
+    fn from(value: &ASTSpan) -> Self {
+        *value
+    }
+}
+
+impl From<&mut ASTSpan> for ASTSpan {
+    #[inline]
+    fn from(value: &mut ASTSpan) -> Self {
+        *value
     }
 }
 
 impl PartialOrd for ASTSpan {
+    #[inline]
     fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
         PartialOrd::partial_cmp(&self.offset, &other.offset)
     }
diff --git a/src/Rust/vvs_lang/src/ast/string.rs b/src/Rust/vvs_lang/src/ast/string.rs
index acd94e432b06376b03a6c0ee281f1d1d3faa8917..acec81a784300f4259745f7fe51efa0f40d9bef4 100644
--- a/src/Rust/vvs_lang/src/ast/string.rs
+++ b/src/Rust/vvs_lang/src/ast/string.rs
@@ -1,19 +1,15 @@
 use super::ASTString;
 use hashbrown::HashMap;
-use std::{cell::RefMut, collections::hash_map::DefaultHasher, hash::Hasher};
+use std::{cell::RefCell, collections::hash_map::DefaultHasher, hash::Hasher, rc::Rc};
 
 /// Used when iterating into the module with mut access, we might need to access the string
 /// cache...
-#[derive(Debug)]
-pub struct ASTStringCacheHandle<'a> {
-    strings: RefMut<'a, HashMap<u64, ASTString>>,
+#[derive(Debug, Clone, Default)]
+pub struct ASTStringCacheHandle {
+    strings: Rc<RefCell<HashMap<u64, ASTString>>>,
 }
 
-impl<'a> ASTStringCacheHandle<'a> {
-    pub(crate) fn new(strings: RefMut<'a, HashMap<u64, ASTString>>) -> Self {
-        Self { strings }
-    }
-
+impl ASTStringCacheHandle {
     /// Get the id of a string.
     fn get_id(str: impl AsRef<str>) -> u64 {
         let mut hasher = DefaultHasher::new();
@@ -21,21 +17,12 @@ impl<'a> ASTStringCacheHandle<'a> {
         hasher.finish()
     }
 
-    /// Get a string from the cache, fail if not present.
-    pub fn get(&mut self, str: impl AsRef<str>) -> Option<ASTString> {
-        self.strings.get(&Self::get_id(str.as_ref())).cloned()
-    }
-
     /// Get or create a string in the cache.
-    pub fn get_or_insert(&mut self, str: impl AsRef<str>) -> ASTString {
-        let id = Self::get_id(str.as_ref());
-        match self.strings.get(&id) {
-            Some(str) => str.clone(),
-            None => {
-                let str = ASTString::from(str.as_ref());
-                self.strings.insert(id, str.clone());
-                str
-            }
-        }
+    pub fn get(&self, str: impl AsRef<str>) -> ASTString {
+        self.strings
+            .borrow_mut()
+            .entry(Self::get_id(str.as_ref()))
+            .or_insert_with(|| ASTString::from(str.as_ref()))
+            .clone()
     }
 }
diff --git a/src/Rust/vvs_lang/src/ast/tree.rs b/src/Rust/vvs_lang/src/ast/tree.rs
deleted file mode 100644
index e9934ae32003928b248c66a51af17b7279c256c2..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/src/ast/tree.rs
+++ /dev/null
@@ -1,266 +0,0 @@
-use super::ASTSpan;
-use hashbrown::HashMap;
-use std::rc::Rc;
-
-pub type ASTString = Rc<str>;
-pub type ASTFloating = f32;
-pub type ASTInteger = i32;
-pub type ASTTable<T> = HashMap<ASTString, T>;
-
-#[macro_export]
-macro_rules! anon_expression {
-    ($variant: ident $($args: tt)?) => {
-        ASTExpr {
-            span: Default::default(),
-            content: ASTExprVariant::$variant $($args)?,
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! expression {
-    ($span: expr, $variant: ident $($args: tt)?) => {
-        ASTExpr {
-            span: $span.into(),
-            content: ASTExprVariant::$variant $($args)?,
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! anon_instruction {
-    ($variant: ident $($args: tt)?) => {
-        ASTInstr {
-            span: Default::default(),
-            content: ASTInstrVariant::$variant $($args)?,
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! instruction {
-    ($span: expr, $variant: ident $($args: tt)?) => {
-        ASTInstr {
-            span: $span.into(),
-            content: ASTInstrVariant::$variant $($args)?,
-        }
-    };
-}
-
-/// Job to execute on a line, syllabe, list of lines, etc.
-#[derive(Debug)]
-pub struct ASTJob {
-    pub name: ASTString,
-    pub returns: ASTType,
-    pub arguments: Vec<ASTVar>,
-    pub content: Vec<ASTInstr>,
-
-    pub span: ASTSpan,
-}
-
-/// A function.
-#[derive(Debug)]
-pub struct ASTFunction {
-    pub name: ASTString,
-    pub arguments: Vec<ASTVar>,
-    pub content: Vec<ASTInstr>,
-
-    pub span: ASTSpan,
-}
-
-/// Instructions.
-#[derive(Debug)]
-pub struct ASTInstr {
-    pub content: ASTInstrVariant,
-    pub span: ASTSpan,
-}
-
-/// Instructions.
-#[derive(Debug, PartialEq)]
-pub enum ASTInstrVariant {
-    /// Declare variables.
-    Decl(Vec<ASTVar>, Vec<ASTExpr>),
-
-    /// Assign into variables.
-    Assign(Vec<ASTExpr>, Vec<ASTExpr>),
-
-    /// FunctionCall.
-    FuncCall(ASTString, Vec<ASTExpr>),
-
-    /// Begin a block.
-    Block(Vec<ASTInstr>),
-
-    /// A WhileDo instruction.
-    WhileDo(ASTExpr, Vec<ASTInstr>),
-
-    /// A DoWhile instruction.
-    RepeatUntil(ASTExpr, Vec<ASTInstr>),
-
-    /// Conditionals, contract the elseid blocks.
-    Cond {
-        cond: ASTExpr,
-        then_block: Vec<ASTInstr>,
-        elseif_blocks: Vec<(ASTExpr, Vec<ASTInstr>)>,
-        else_block: Option<Vec<ASTInstr>>,
-    },
-
-    /// For loop, the classic one:
-    /// ```vvs
-    /// for elem = 1, 3, 1 do print(elem) end
-    /// ```
-    ForLoop {
-        var: ASTVar,
-        lower: ASTInteger,
-        upper: ASTInteger,
-        step: Option<ASTInteger>,
-    },
-
-    /// For loop with an iterable expression (table):
-    /// ```vvs
-    /// for elem in { 1, 2, 3 } do print(elem) end
-    /// for elem in ( 1, 2, 3 ) do print(elem) end
-    /// for elem in my_table    do print(elem) end
-    /// ```
-    ForInto { var: ASTVar, list: ASTExpr },
-
-    /// Final thing: break from block.
-    Break,
-
-    /// Final thing: continue to next iteration.
-    Continue,
-
-    /// Final thing: return something.
-    Return(ASTExpr),
-}
-
-/// Binops, sorted by precedence.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum ASTBinop {
-    /// Assoc: right
-    Power,
-
-    Mul,
-    Div,
-    Mod,
-    Add,
-    Sub,
-
-    /// Assoc: right
-    StrCat,
-
-    CmpLE,
-    CmpLT,
-    CmpGE,
-    CmpGT,
-    CmpEQ,
-    CmpNE,
-
-    LogicAnd,
-    LogicXor,
-    LogicOr,
-
-    BitAnd,
-    BitXor,
-    BitOr,
-    BitShiftLeft,
-    BitShiftRight,
-}
-
-/// Unops.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum ASTUnop {
-    LogicNot,
-    BitNot,
-    Len,
-    Neg,
-}
-
-/// Expressions. For the partial equality we skip the span field to be able to test efficiently the
-/// parsing.
-#[derive(Debug)]
-pub struct ASTExpr {
-    pub content: ASTExprVariant,
-    pub span: ASTSpan,
-}
-
-/// Expressions.
-#[derive(Debug, PartialEq)]
-pub enum ASTExprVariant {
-    Nil,
-    False,
-    True,
-    Integer(ASTInteger),
-    Floating(ASTFloating),
-    String(ASTString),
-    Table(ASTTable<ASTExpr>),
-    Binop(Box<ASTExpr>, ASTBinop, Box<ASTExpr>),
-    Unop(ASTUnop, Box<ASTExpr>),
-    FuncCall(Box<ASTExpr>, Vec<ASTExpr>),
-    MethodInvok(Box<ASTExpr>, ASTString, Vec<ASTExpr>),
-    PrefixExpr(Box<ASTExpr>, Vec<ASTField>),
-    Tuple(Vec<ASTExpr>),
-    Var(ASTVar),
-    Const(ASTConst),
-}
-
-/// Fields indexes can be expressions or identifiers
-#[derive(Debug, PartialEq)]
-pub enum ASTField {
-    Expr(ASTSpan, ASTExprVariant),
-    Identifier(ASTSpan, ASTString),
-}
-
-/// Variable thing. Have a name, a where-it-is-defined span and optionally a type. Having to no
-/// type means that the type was not already found.
-#[derive(Debug, PartialEq, Eq)]
-pub struct ASTVar(pub ASTSpan, pub ASTString, pub Option<ASTType>);
-
-/// A constant expr.
-#[derive(Debug, PartialEq)]
-pub enum ASTConst {
-    Color(ASTInteger),
-    String(ASTString),
-    Integer(ASTInteger),
-    Floating(ASTFloating),
-    Table(ASTTable<ASTConst>),
-}
-
-/// Types.
-#[derive(Debug, PartialEq, Eq)]
-pub enum ASTType {
-    Integer,
-    Floating,
-    String,
-    Color,
-    Line,
-    Syllabe,
-    Table(ASTTable<ASTType>),
-}
-
-impl PartialEq for ASTExpr {
-    fn eq(&self, other: &Self) -> bool {
-        self.content == other.content
-    }
-}
-
-impl PartialEq for ASTInstr {
-    fn eq(&self, other: &Self) -> bool {
-        self.content == other.content
-    }
-}
-
-impl ASTVar {
-    pub fn span(&self) -> ASTSpan {
-        self.0
-    }
-
-    pub fn name(&self) -> &ASTString {
-        &self.1
-    }
-}
-
-impl std::fmt::Display for ASTVar {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.write_str(self.1.as_ref())
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/type_context.rs b/src/Rust/vvs_lang/src/ast/type_context.rs
new file mode 100644
index 0000000000000000000000000000000000000000..829dcc0b799957ea34ee46aa5bd8cc595ce048c4
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/type_context.rs
@@ -0,0 +1,180 @@
+use crate::ast::*;
+use core::cell::OnceCell;
+
+/// Match any item, private or public.
+const RULE_ANY: ASTVisibilityRule = ASTVisibilityRule::AtLeast(ASTVisibility::Private);
+const RULE_PUB: ASTVisibilityRule = ASTVisibilityRule::Only(ASTVisibility::Public);
+
+/// The ast context for storing types. Any use of the module must be delayed because when we create
+/// the type context for a module, we do it with a cyclic thingy, so the [Rc] is not already
+/// constructed (no strong reference), so all we have is a [std::rc::Weak].
+#[derive(Debug, Clone)]
+pub struct ASTTypeContext {
+    module: ASTModuleWeakPtr,
+    content: OnceCell<ASTTypeContextContent>,
+}
+
+/// The content of the [ASTTypeContext] must be lazyly initialized because of cyclic references
+/// with the module and it's type context.
+type ASTTypeContextContent = (
+    HashMap<ASTString, ASTType>,         // Variables
+    HashMap<ASTString, ASTVariantRules>, // Variants
+    ASTStringCacheHandle,                // String cache
+    Vec<ASTString>,                      // Name of imported modules
+);
+
+impl ASTTypeContext {
+    fn init_content(&self) -> ASTTypeContextContent {
+        let ptr = self.module.upgrade().expect("no more strong references to module...");
+        let module = ASTModule::get(&ptr);
+
+        // We need to import things from the current module and from the imported modules. But for
+        // imported modules we must prepend the constant/option/callable name by the module name
+        // with a dot, to call those things like in lua.
+        let modules = [(None, module)]
+            .into_iter()
+            .chain(module.imports().map(|module| (Some(module.name()), module)));
+
+        let scope = modules.flat_map(|(mname, module)| {
+            let rule = if mname.is_some() { RULE_PUB } else { RULE_ANY };
+            let (mname1, mname2, mname3) = (mname.clone(), mname.clone(), mname);
+
+            let options = module.options().map(move |(var, _)| {
+                let name = mname1
+                    .as_ref()
+                    .map(|n| module.strings().get(format!("{n}.{}", var.name())))
+                    .unwrap_or_else(|| var.name());
+                (name, var.get_specified_type_or_nil())
+            });
+
+            let consts = module.consts(rule).map(move |(var, _)| {
+                let name = mname2
+                    .as_ref()
+                    .map(|n| module.strings().get(format!("{n}.{}", var.name())))
+                    .unwrap_or_else(|| var.name());
+                (name, var.get_specified_type_or_nil())
+            });
+
+            let funcs = module.callables(rule).map(move |(name, func)| {
+                let name = mname3
+                    .as_ref()
+                    .map(|n| module.strings().get(format!("{n}.{name}")))
+                    .unwrap_or(name);
+
+                let arguments = func.arguments.iter().map(|arg| arg.get_specified_type_or_nil());
+                let func_type = ASTType::Function(arguments.collect(), Box::new(func.returns.clone()));
+
+                (name, func_type)
+            });
+
+            options.chain(consts).chain(funcs)
+        });
+
+        let strings = module.strings().clone();
+        let variants = module.all_variant_rules().clone();
+        let imports = module.imports().map(|module| module.name()).collect();
+        (scope.collect(), variants, strings, imports)
+    }
+
+    fn content(&self) -> &ASTTypeContextContent {
+        self.content.get_or_init(|| self.init_content())
+    }
+
+    fn content_mut(&mut self) -> &mut ASTTypeContextContent {
+        self.content();
+        self.content.get_mut().expect("should be initialized")
+    }
+
+    #[inline]
+    pub fn new(module: ASTModuleWeakPtr) -> Self {
+        Self { module, content: OnceCell::new() }
+    }
+
+    /// Try to map rules to a pattern. Returns the matching [Some] variables with their destination
+    /// types or [None] if the matching is not possible to do. Because all rules must be kown at
+    /// compile time we can now statically if a variant mapping is correct or not!
+    pub fn variant_try_map_rule(
+        &self,
+        rule: impl AsRef<str>,
+        to: &[ASTPatternElement],
+    ) -> Option<Vec<(ASTVar, ASTType)>> {
+        // Get the rule-set.
+        let rule = self.content().1.get(rule.as_ref())?;
+
+        // The first thing must be a constant string or identifier with the name of the sub-rule.
+        use ASTPatternElement::*;
+        let (rule, content) = match to {
+            [Const(ASTConst::String(sub_rule)), content @ ..] => (rule.rule(sub_rule)?, content),
+            [Var(var), content @ ..] => {
+                debug_assert!(
+                    var.get_specified_type().is_none(),
+                    "got a specified type for `{var}`, expected just an identifier"
+                );
+                (rule.rule(var.name())?, content)
+            }
+            _ => return None,
+        };
+
+        // Be sure that we capture everything in that rule. We don't have the `..` like in rust...
+        if rule.len() != content.len() {
+            return None;
+        }
+
+        Some(
+            // Do the matching for the sub-rule.
+            rule.iter().zip(content).map(|(rule, pat)| match pat {
+                // If a constant is provided we must ensure that the types are compatible!
+                Const(pat) => rule.coercible_to(&pat.get_const_type()).then_some(None).ok_or(()),
+                // If a variable is declared then we will return it. If the variable has a
+                // specified type, we must ensure that the element in the variant can be coerced
+                // into this specified type.
+                Var(var) => match var.get_specified_type() {
+                    Some(ty) => rule.coercible_to(ty).then(|| Some((var.clone(), rule.clone()))).ok_or(()),
+                    None => Ok(Some((var.clone(), rule.clone()))),
+                },
+            })
+            // Get ride of any errors because of impossible mappings.
+            .collect::<Result<Vec<Option<(ASTVar, ASTType)>>, ()>>().ok()?
+            // We collect the successful bindings into a vector, we don't care when a constant
+            // mapped with an element of the variant.
+            .into_iter().flatten().collect(),
+        )
+    }
+
+    /// Get a set of rule for a specified variant if it exists.
+    pub fn variant_complies_with_rule<T: Typed>(&self, rule: impl AsRef<str>, variant: &ASTVariant<T>) -> bool {
+        let rules = self.content().1.get(rule.as_ref());
+        rules.map_or(false, |rules| rules.complies(self, variant))
+    }
+
+    /// Create a new context, don't clone as we want to do other things...
+    #[inline]
+    pub fn for_scope(&self) -> Self {
+        self.clone()
+    }
+
+    /// Get the type of a variable by its name.
+    pub fn get(&self, name: &ASTVar) -> ASTType {
+        let (scope, ..) = self.content();
+        scope.get(name.name().as_ref()).unwrap().clone()
+    }
+
+    /// Declare a new variable. Returns an error on redefinition.
+    pub fn declare(&mut self, var: ASTVar, ty: ASTType) {
+        if var.is_joker() {
+            log::debug!("can't declare the joker as a variable at {}", var.span());
+        } else if self.content_mut().0.insert(var.name(), ty).is_some() {
+            panic!()
+        }
+    }
+
+    pub fn has_import(&self, import: impl AsRef<str>) -> bool {
+        self.content().3.iter().any(|scoped| scoped.as_ref() == import.as_ref())
+    }
+
+    /// Get the string cache out of the module pointer stored in the context.
+    #[inline]
+    pub fn strings(&self) -> &ASTStringCacheHandle {
+        &self.content().2
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/typed.rs b/src/Rust/vvs_lang/src/ast/typed.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d2f8b537ae890a37771fc8ac1f6e5f24aa6e1fac
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/typed.rs
@@ -0,0 +1,17 @@
+use crate::ast::*;
+use std::ops::Deref;
+
+/// Trait for objects that are types.
+///
+/// As long a a type can be dereferenced into a [Typed] thing, it is [Typed].
+pub trait Typed {
+    /// Get the type of the object.
+    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType;
+}
+
+impl<S: Typed, T: Deref<Target = S>> Typed for T {
+    #[inline]
+    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType {
+        self.deref().get_type(ctx)
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/types.rs b/src/Rust/vvs_lang/src/ast/types.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cb2315319feb0e68271166e0b2b97fb59a5f31eb
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/types.rs
@@ -0,0 +1,226 @@
+use crate::ast::*;
+
+/// Types. Every object that can be manipulated by the user has a type. We have base types and
+/// collection types and special ASS types.
+///
+/// Some coercion is possible between collection types...
+#[derive(Debug, PartialEq, Eq, Clone, Default)]
+pub enum ASTType {
+    /// Null, unit, nullptr, etc. This is the default type
+    #[default]
+    Nil,
+
+    /// An integer
+    Integer,
+
+    /// A floating point number
+    Floating,
+
+    /// A string.
+    String,
+
+    /// A boolean, true/false.
+    Boolean,
+
+    /// A color
+    Color,
+
+    /// A movement of a syllabe or line.
+    Movement,
+
+    /// A variant, can be a color or a movement.
+    Variant,
+
+    /// A tuple
+    Tuple(Vec<ASTType>),
+
+    /// Special ASS type, a syllabe. A simple syllabe.
+    Syllabe,
+
+    /// Special ASS type, a line. It's a collection of [ASTType::Syllabe] with extra steps, can
+    /// iterate over it.
+    Line,
+
+    /// A table where the content is not really defined. Because we don't know the keys we can't
+    /// iterate over it.
+    AnyTable,
+
+    /// A table where everything inside is defined, a struct. We can't iterate over it but we
+    /// statically know the keys of the table.
+    Table(ASTTable<ASTType>),
+
+    /// A uniform table, where all the values has the same types, like a sequence but which string
+    /// keys.
+    UniformTable(Box<ASTType>),
+
+    /// A sequence where the content is not really defined, like the any table but with sequences.
+    AnySequence,
+
+    /// A sequence where every value has the same type. We can iterate over it, like a uniform
+    /// table, but with integer and continuous keys.
+    Sequence(Box<ASTType>),
+
+    /// A function type, needs the arguments and the return value.
+    Function(Vec<ASTType>, Box<ASTType>),
+
+    /// A type that is not known at compile time, the user must check its type with a switch case.
+    Any,
+}
+
+impl ASTType {
+    /// Try to see if a type can be pattern matched and if it's the case, returns [Some] bindings
+    /// to add them to the type context, otherwise return [None].
+    pub fn try_match(&self, mctx: &ASTTypeContext, to: &[ASTPatternElement]) -> Option<Vec<(ASTVar, ASTType)>> {
+        self.get_variant_rule()
+            .and_then(|rule| mctx.variant_try_map_rule(rule, to))
+    }
+
+    /// Tells wether the type is buildable in a const context or not.
+    #[inline]
+    pub fn is_const_constructible(&self) -> bool {
+        matches!(self, ASTType::Nil | ASTType::Tuple(_) | ASTType::Any)
+            || self.is_numeric()
+            || self.is_table()
+            || self.is_sequence()
+    }
+
+    /// Tells wether the type is numeric or not.
+    #[inline]
+    pub fn is_numeric(&self) -> bool {
+        matches!(self, ASTType::Boolean | ASTType::Integer | ASTType::Floating)
+    }
+
+    /// Tells whether the type is any sort of sequence or not.
+    #[inline]
+    pub fn is_sequence(&self) -> bool {
+        matches!(self, ASTType::Sequence(_) | ASTType::AnySequence)
+    }
+
+    /// Tells whether the type is any sort of table or not.
+    #[inline]
+    pub fn is_table(&self) -> bool {
+        matches!(self, ASTType::UniformTable(_) | ASTType::Table(_) | ASTType::AnyTable)
+    }
+
+    /// Tells whether the type is any sort of variant or not.
+    #[inline]
+    pub fn is_variant(&self) -> bool {
+        matches!(self, ASTType::Variant | ASTType::Color | ASTType::Movement)
+    }
+
+    /// Get the name of the rules to follow for this variant if it's really a variant.
+    #[inline]
+    pub fn get_variant_rule(&self) -> Option<&'static str> {
+        match self {
+            ASTType::Color => Some("color"),
+            ASTType::Movement => Some("movement"),
+            _ => None,
+        }
+    }
+
+    /// Tells whether a type is trivially copiable, i.e. this type won't be managed.
+    #[inline]
+    pub fn is_trivialy_copiable(&self) -> bool {
+        use ASTType::*;
+        matches!(self, Nil | Integer | Floating | Boolean | Tuple(_))
+    }
+
+    pub fn coercible_to(&self, to: &ASTType) -> bool {
+        use ASTType::*;
+        match (self, to) {
+            // Equals...
+            (x, y)
+                if (x == y)
+                    || (x.is_table() && matches!(y, AnyTable))
+                    || (x.is_sequence() && matches!(y, AnySequence))
+                    || (x.is_variant() && y.is_variant()) =>
+            {
+                true
+            }
+
+            // Nil things
+            (_, Nil) | (Nil, Integer | Floating | Boolean) => true,
+            (Nil, to) => to.is_table() || to.is_sequence(),
+
+            // Integer things
+            (Integer, Floating | Boolean) | (Boolean, Integer | Floating) | (Floating, Integer) => true,
+
+            // Sequence / ASS things
+            (String, Sequence(ty)) | (Sequence(ty), String) => matches!(&**ty, String),
+            (Sequence(x), Line) | (Line, Sequence(x)) => matches!(&**x, Syllabe),
+            (Syllabe, Sequence(x)) => matches!(&**x, String),
+
+            // Table / Sequence things
+            (from, AnyTable) => from.is_sequence() || from.is_table() || from.is_variant(),
+            (Sequence(to), UniformTable(from)) | (UniformTable(from), Sequence(to)) => from.coercible_to(to),
+            (Table(table), Sequence(ty)) => {
+                let integer_keys = table.keys().all(|key| key.parse::<i64>().is_ok());
+                let mut uniform_values = table.values().collect::<Vec<_>>();
+                let uniform_values = uniform_values
+                    .pop()
+                    .map(|ty| uniform_values.into_iter().all(|a| ty.eq(a)).then_some(ty));
+                integer_keys && matches!(uniform_values, Some(Some(table_ty)) if table_ty.eq(ty))
+            }
+
+            _ => false,
+        }
+    }
+}
+
+impl Typed for ASTType {
+    #[inline]
+    fn get_type(&self, _: &ASTTypeContext) -> ASTType {
+        self.clone()
+    }
+}
+
+impl std::fmt::Display for ASTType {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            ASTType::Nil => f.write_str("nil"),
+            ASTType::Any => f.write_str("any"),
+
+            ASTType::Integer => f.write_str("integer"),
+            ASTType::Floating => f.write_str("float"),
+            ASTType::String => f.write_str("string"),
+            ASTType::Boolean => f.write_str("boolean"),
+            ASTType::Color => f.write_str("color"),
+            ASTType::Variant => f.write_str("variant"),
+            ASTType::Movement => f.write_str("movement"),
+
+            ASTType::Function(args, ret) => {
+                f.write_str("function (")?;
+                if let Some(ty) = args.iter().next() {
+                    write!(f, " {ty}")?;
+                }
+                for ty in args.iter().skip(1) {
+                    write!(f, ", {ty}")?;
+                }
+                write!(f, " ) -> {ret}")
+            }
+
+            ASTType::Tuple(tuple) => {
+                f.write_str("(")?;
+                if let Some(ty) = tuple.iter().next() {
+                    write!(f, " {ty}")?;
+                }
+                for ty in tuple.iter().skip(1) {
+                    write!(f, ", {ty}")?;
+                }
+                f.write_str(" )")
+            }
+
+            ASTType::Line => f.write_str("line"),
+            ASTType::Syllabe => f.write_str("syllabe"),
+            ASTType::AnySequence => f.write_str("sequence { any }"),
+            ASTType::Sequence(ty) => write!(f, "sequence {{ {ty} }}"),
+
+            ASTType::AnyTable => f.write_str("table { any }"),
+            ASTType::UniformTable(inner) => write!(f, "table {{ {inner} }}"),
+            ASTType::Table(table) => {
+                f.write_str("table ")?;
+                write_ast_table(f, table)
+            }
+        }
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/variable.rs b/src/Rust/vvs_lang/src/ast/variable.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3cb5383396dbc1865d59ea4a0f4f54887ba95a96
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/variable.rs
@@ -0,0 +1,119 @@
+use crate::ast::*;
+use std::sync::atomic::{AtomicU64, Ordering};
+
+/// Variable thing. Have a name, a where-it-is-defined span and optionally a type. Having to no
+/// type means that the type was not already found.
+///
+/// To get the type of a variable, it is either present in the context type hashmap, then we check
+/// the specified type, if all failed we return the [ASTType::Nil] type.
+#[derive(Debug, Clone)]
+pub struct ASTVar(ASTSpan, ASTString, Option<ASTType>);
+
+#[derive(Debug, Clone)]
+pub struct ASTVarBuilder<'a> {
+    span: ASTSpan,
+    cache: &'a ASTStringCacheHandle,
+    name: Option<ASTString>,
+    specified_ty: Option<ASTType>,
+}
+
+impl<'a> ASTVarBuilder<'a> {
+    pub fn build(self) -> ASTVar {
+        let name = self.name.unwrap_or_else(|| {
+            static ANON: AtomicU64 = AtomicU64::new(0);
+            self.cache.get(format!("_{}", ANON.fetch_add(1, Ordering::SeqCst)))
+        });
+        ASTVar(self.span, name, self.specified_ty)
+    }
+
+    pub fn span(mut self, span: impl Into<ASTSpan>) -> Self {
+        self.span = span.into();
+        self
+    }
+
+    pub fn with_type(mut self, ty: ASTType) -> Self {
+        self.specified_ty = Some(ty);
+        self
+    }
+
+    pub fn name_from(mut self, name: impl AsRef<str>) -> Self {
+        self.name = Some(self.cache.get(name.as_ref()));
+        self
+    }
+
+    pub fn name(mut self, name: ASTString) -> Self {
+        self.name = Some(name);
+        self
+    }
+}
+
+impl PartialEq for ASTVar {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.1 == other.1 && self.2 == other.2
+    }
+}
+
+impl ASTVar {
+    #[inline]
+    #[allow(clippy::new_ret_no_self)]
+    pub fn new(cache: &ASTStringCacheHandle) -> ASTVarBuilder {
+        ASTVarBuilder { span: Default::default(), cache, name: None, specified_ty: None }
+    }
+
+    #[inline]
+    pub fn span(&self) -> ASTSpan {
+        self.0
+    }
+
+    /// Get the specified type if any.
+    #[inline]
+    pub fn get_specified_type(&self) -> Option<&ASTType> {
+        self.2.as_ref()
+    }
+
+    /// Get the specified type. If no type is specified then we say that we return [ASTType::Nil].
+    #[inline]
+    pub fn get_specified_type_or_nil(&self) -> ASTType {
+        self.get_specified_type().cloned().unwrap_or_default()
+    }
+
+    /// Set the specified type.
+    #[inline]
+    pub fn set_specified_type(&mut self, ty: ASTType) {
+        self.2 = Some(ty);
+    }
+
+    /// Get the name.
+    #[inline]
+    pub fn name(&self) -> ASTString {
+        self.1.clone()
+    }
+
+    /// Tells wether the variable is the joker or not. We can assign into the joker, in this case
+    /// we yeet the result, but we can never read it.
+    pub fn is_joker(&self) -> bool {
+        self.1.as_ref().eq("_")
+    }
+}
+
+impl From<&ASTVar> for ASTSpan {
+    #[inline]
+    fn from(value: &ASTVar) -> Self {
+        value.span()
+    }
+}
+
+impl std::fmt::Display for ASTVar {
+    #[inline]
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_str(self.1.as_ref())
+    }
+}
+
+impl Typed for ASTVar {
+    #[inline]
+    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType {
+        ctx.get(self)
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/variant.rs b/src/Rust/vvs_lang/src/ast/variant.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d6e6da7f70d69c34a97f56c1bca847f2bc83ee65
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/variant.rs
@@ -0,0 +1,192 @@
+use crate::ast::*;
+
+/// A trait to describes types that are variants. Can be used to handle colors and movements in a
+/// generic way.
+///
+/// Represents a color in the AST. A color can be:
+/// - `#(rgb 0, 0, 0)` for black
+/// - `#(green)` for green
+/// - etc...
+///
+/// Represents a movement in the AST, a movement can be:
+/// - `#[pos 500, 500]`
+/// - `#[cmove 0, 0, 100, 50, 30]`
+/// - etc...
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct ASTVariant<T: Typed> {
+    pub(crate) variant: ASTString,
+    pub(crate) args: Vec<T>,
+}
+
+pub(crate) struct ASTFmtColor<'a, T: Typed>(&'a ASTVariant<T>, &'a ASTTypeContext);
+pub(crate) struct ASTFmtMovement<'a, T: Typed>(&'a ASTVariant<T>, &'a ASTTypeContext);
+
+impl<T: Typed> ASTVariant<T> {
+    #[inline]
+    pub fn variant(&self) -> ASTString {
+        self.variant.clone()
+    }
+
+    #[inline]
+    pub fn args(&self) -> &[T] {
+        &self.args
+    }
+
+    #[inline]
+    pub fn args_mut(&mut self) -> &mut [T] {
+        &mut self.args
+    }
+
+    #[inline]
+    pub fn args_len(&self) -> usize {
+        self.args.len()
+    }
+}
+
+impl ASTVariant<ASTExpr> {
+    #[inline]
+    pub fn is_const_expr(&self) -> bool {
+        self.args.iter().all(|expr| expr.is_const_expr())
+    }
+}
+
+impl ASTVariant<ASTConst> {
+    #[inline]
+    pub fn is_const_expr(&self) -> bool {
+        true
+    }
+}
+
+impl<'a, T: Typed> ASTFmtColor<'a, T> {
+    pub(crate) fn new(variant: &'a ASTVariant<T>, ctx: &'a ASTTypeContext) -> Self {
+        Self(variant, ctx)
+    }
+}
+
+impl<'a, T: Typed> ASTFmtMovement<'a, T> {
+    pub(crate) fn new(variant: &'a ASTVariant<T>, ctx: &'a ASTTypeContext) -> Self {
+        Self(variant, ctx)
+    }
+}
+
+impl<'a, T: Typed> std::fmt::Display for ASTFmtColor<'a, T> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let Self(ASTVariant { variant, args }, ctx) = self;
+        write!(f, "#({variant}")?;
+        if let Some(arg) = args.iter().next() {
+            write!(f, " {}", arg.get_type(ctx))?;
+        }
+        for arg in args.iter().skip(1) {
+            write!(f, ", {}", arg.get_type(ctx))?;
+        }
+        f.write_str(" )")
+    }
+}
+
+impl<'a, T: Typed> std::fmt::Display for ASTFmtMovement<'a, T> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let Self(ASTVariant { variant, args }, ctx) = self;
+        write!(f, "#[{variant}")?;
+        if let Some(arg) = args.iter().next() {
+            write!(f, " {}", arg.get_type(ctx))?;
+        }
+        for arg in args.iter().skip(1) {
+            write!(f, ", {}", arg.get_type(ctx))?;
+        }
+        f.write_str(" ]")
+    }
+}
+
+/// Describes a set of rules for a variant.
+#[derive(Debug, Clone)]
+pub struct ASTVariantRules {
+    family: ASTString,
+    rules: HashMap<ASTString, Vec<ASTType>>,
+}
+
+macro_rules! rule {
+    ($cache: expr, $name: literal) => { ($cache.get($name), vec![]) };
+    ($cache: expr, $name: literal -> [$($arg: ident),*]) => { ($cache.get($name), vec![$(ASTType::$arg,)*]) };
+}
+
+impl ASTVariantRules {
+    /// Default empty ruleset.
+    #[inline]
+    pub fn new(name: ASTString) -> Self {
+        Self { family: name, rules: Default::default() }
+    }
+
+    /// Get the name of the family of variants.
+    #[inline]
+    pub fn name(&self) -> ASTString {
+        self.family.clone()
+    }
+
+    /// Get all the rules of this family.
+    #[inline]
+    pub fn rules(&self) -> impl Iterator<Item = (&ASTString, &Vec<ASTType>)> {
+        self.rules.iter()
+    }
+
+    /// Get a specific rule if present.
+    #[inline]
+    pub fn rule(&self, variant: impl AsRef<str>) -> Option<&[ASTType]> {
+        self.rules.get(variant.as_ref()).map(|vec| vec.as_ref())
+    }
+
+    /// Create a new rule set for colors, the default one.
+    #[inline]
+    pub fn new_colors(cache: ASTStringCacheHandle) -> Self {
+        Self {
+            family: cache.get("color"),
+            rules: HashMap::from_iter([
+                rule!(cache, "rgb"  -> [Integer, Integer, Integer]),
+                rule!(cache, "rgba" -> [Integer, Integer, Integer, Integer]),
+                rule!(cache, "black"),
+                rule!(cache, "white"),
+                rule!(cache, "grey"),
+                rule!(cache, "red"),
+                rule!(cache, "green"),
+                rule!(cache, "blue"),
+            ]),
+        }
+    }
+
+    /// Create a new rule set for movements, the default one.
+    #[inline]
+    pub fn new_movements(cache: ASTStringCacheHandle) -> Self {
+        Self {
+            family: cache.get("movement"),
+            rules: HashMap::from_iter([
+                rule![cache, "implicit"],
+                rule!(cache, "fixed"       -> [Integer, Integer]),
+                rule!(cache, "linear"      -> [Integer, Integer, Integer, Integer]),
+                rule!(cache, "accelerated" -> [Integer, Integer, Integer, Integer, Floating]),
+            ]),
+        }
+    }
+
+    /// Insert a new rule in the ruleset, returns [true] if the rule was inserted successfully,
+    /// [false] otherwise.
+    #[must_use]
+    #[inline]
+    pub fn insert_rule(&mut self, name: ASTString, types: Vec<ASTType>) -> bool {
+        self.rules.insert(name, types).is_none()
+    }
+
+    /// Returns wether a variant complies with the set of allowed one.
+    #[must_use]
+    #[inline]
+    pub fn complies<T: Typed>(&self, ctx: &ASTTypeContext, variant: &ASTVariant<T>) -> bool {
+        match self.rules.get(&variant.variant) {
+            None => false,
+            Some(rule) => {
+                (rule.len() == variant.args.len())
+                    && rule
+                        .iter()
+                        .zip(variant.args.iter().map(|arg| arg.get_type(ctx)))
+                        .all(|(rule, arg)| arg.coercible_to(rule))
+            }
+        }
+    }
+}
diff --git a/src/Rust/vvs_lang/src/ast/visibility.rs b/src/Rust/vvs_lang/src/ast/visibility.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5d5c88f590261feef15dc9d15c1360603ffcb26c
--- /dev/null
+++ b/src/Rust/vvs_lang/src/ast/visibility.rs
@@ -0,0 +1,77 @@
+#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub enum ASTVisibility {
+    #[default]
+    Private,
+    Public,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum ASTVisibilityRule {
+    Only(ASTVisibility),
+    AtLeast(ASTVisibility),
+}
+
+impl ASTVisibilityRule {
+    /// Checks if the rule allows to show an item with the specified visibility [ASTVisibility].
+    /// Used to factorize the functions in [crate::ast::ASTModule] and [crate::ast::ASTProgram].
+    #[inline]
+    pub fn allows(&self, vis: ASTVisibility) -> bool {
+        match self {
+            ASTVisibilityRule::Only(this) => vis.eq(this),
+            ASTVisibilityRule::AtLeast(this) => PartialOrd::le(this, &vis),
+        }
+    }
+
+    /// Allows all the visibilities.
+    #[inline]
+    pub fn any() -> Self {
+        Self::AtLeast(ASTVisibility::Private)
+    }
+}
+
+impl Default for ASTVisibilityRule {
+    fn default() -> Self {
+        Self::Only(ASTVisibility::Private)
+    }
+}
+
+impl ASTVisibility {
+    #[inline]
+    pub fn as_str(&self) -> &str {
+        match self {
+            ASTVisibility::Private => "private",
+            ASTVisibility::Public => "public",
+        }
+    }
+}
+
+impl AsRef<str> for ASTVisibility {
+    #[inline]
+    fn as_ref(&self) -> &str {
+        self.as_str()
+    }
+}
+
+#[test]
+fn test_visibility() {
+    assert!(ASTVisibility::Private < ASTVisibility::Public);
+}
+
+#[test]
+fn test_visibility_rules() {
+    use ASTVisibility::*;
+    use ASTVisibilityRule::*;
+
+    assert!(Only(Private).allows(Private));
+    assert!(!Only(Private).allows(Public));
+    assert!(Only(Public).allows(Public));
+    assert!(!Only(Public).allows(Private));
+
+    assert!(AtLeast(Private).allows(Public));
+    assert!(AtLeast(Private).allows(Private));
+    assert!(AtLeast(Public).allows(Public));
+    assert!(!AtLeast(Public).allows(Private));
+
+    assert!(ASTVisibilityRule::any().allows(Public));
+    assert!(ASTVisibilityRule::any().allows(Private));
+}
diff --git a/src/Rust/vvs_lang/src/lib.rs b/src/Rust/vvs_lang/src/lib.rs
index a310c76d6da8c9fbfc8dd0f2598b6810a43715cd..97947b62a75617da75838c2f0c88eb6507d14a28 100644
--- a/src/Rust/vvs_lang/src/lib.rs
+++ b/src/Rust/vvs_lang/src/lib.rs
@@ -1,2 +1,4 @@
+#![allow(dead_code)]
+
+// Old code, will be purged
 pub mod ast;
-pub mod parser;
diff --git a/src/Rust/vvs_lang/src/parser/error.rs b/src/Rust/vvs_lang/src/parser/error.rs
deleted file mode 100644
index c6a251764d8cd9db1c693f6126f3dd60f9723a17..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/src/parser/error.rs
+++ /dev/null
@@ -1,124 +0,0 @@
-use crate::{ast::ASTSpan, parser::*};
-pub(crate) use nom::error::{ContextError as NomContextError, ParseError as NomParseError};
-use thiserror::Error;
-
-#[macro_export]
-macro_rules! nom_err_error {
-    (vvs: $code: ident $args: tt) => {
-        Err(nom::Err::Error($crate::parser::error::VVError::$code $args))
-    };
-
-    (vvs bare: $code: ident $args: tt) => {
-        nom::Err::Error($crate::parser::error::VVError::$code $args)
-    };
-
-    (nom: $i: expr, $code: ident) => {
-        Err(nom::Err::Error(VVError::from_error_kind(
-            $i,
-            nom::error::ErrorKind::$code,
-        )))
-    };
-
-    (nom bare: $i: expr, $code: ident) => {
-        VVError::from_error_kind($i, nom::error::ErrorKind::$code)
-    };
-}
-pub(crate) use nom_err_error;
-
-#[macro_export]
-macro_rules! nom_err_failure {
-    (vvs: $code: ident $args: tt) => {
-        Err(nom::Err::Failure($crate::parser::error::VVError::$code $args))
-    };
-
-    (vvs bare: $code: ident $args: tt) => {
-        nom::Err::Failure($crate::parser::error::VVError::$code $args)
-    };
-
-    (nom: $i: expr, $code: ident) => {
-        Err(nom::Err::Failure(VVError::from_error_kind(
-            $i,
-            nom::error::ErrorKind::$code,
-        )))
-    };
-
-    (nom bare: $i: expr, $code: ident) => {
-        VVError::from_error_kind($i, nom::error::ErrorKind::$code)
-    };
-}
-pub(crate) use nom_err_failure;
-
-#[derive(Debug, Error, PartialEq, Eq)]
-pub enum VVError {
-    #[error("got an error from nom at {0}: {1:?}")]
-    Nom(ASTSpan, nom::error::ErrorKind),
-
-    #[error("got a nom error needed error at {0}: {1:?}")]
-    NomNeeded(ASTSpan, nom::Needed),
-
-    #[error("got multiple errors:\n{0:?}")]
-    Multiple(Vec<VVError>),
-
-    #[error("failed to parse an integer at {0}: {1}")]
-    ParseIntError(ASTSpan, std::num::ParseIntError),
-
-    #[error("failed to parse a floating number at {0}: {1}")]
-    ParseFloatError(ASTSpan, std::num::ParseFloatError),
-
-    #[error("failed to get tag `{1}` at {0}")]
-    FailedToGetTag(ASTSpan, &'static str),
-
-    #[error("not an identifier at {0}")]
-    NotAnIdentifier(ASTSpan),
-
-    #[error("table index `{1}` redefined at {0}")]
-    TableIndexRedefined(ASTSpan, ASTString),
-
-    #[error("option `{1}.{2}` at line {} redefined, first definition at {0}", .2.span())]
-    OptionRedefined(ASTSpan, ASTString, ASTVar),
-
-    #[error("error at {0}: {1}")]
-    ErrorMsg(ASTSpan, String),
-}
-
-pub type VVParserError<'a, T> = IResult<PSpan<'a>, T, VVError>;
-pub type VVResult<T> = Result<T, VVError>;
-
-impl<'a> NomContextError<PSpan<'a>> for VVError {}
-
-impl<'a> NomParseError<PSpan<'a>> for VVError {
-    fn from_error_kind(input: PSpan, kind: nom::error::ErrorKind) -> Self {
-        Self::Nom(input.into(), kind)
-    }
-
-    fn append(input: PSpan, kind: nom::error::ErrorKind, other: Self) -> Self {
-        VVError::Multiple(match other {
-            VVError::Multiple(mut other) => {
-                other.push(Self::from_error_kind(input, kind));
-                other
-            }
-            other => vec![other, Self::from_error_kind(input, kind)],
-        })
-    }
-}
-
-impl<'a> nom::error::FromExternalError<PSpan<'a>, std::num::ParseIntError> for VVError {
-    fn from_external_error(input: PSpan<'a>, _: nom::error::ErrorKind, e: std::num::ParseIntError) -> Self {
-        Self::ParseIntError(input.into(), e)
-    }
-}
-
-impl<'a> nom::error::FromExternalError<PSpan<'a>, std::num::ParseFloatError> for VVError {
-    fn from_external_error(input: PSpan<'a>, _: nom::error::ErrorKind, e: std::num::ParseFloatError) -> Self {
-        Self::ParseFloatError(input.into(), e)
-    }
-}
-
-impl<'a> nom::error::FromExternalError<PSpan<'a>, nom::Err<VVError>> for VVError {
-    fn from_external_error(i: PSpan, _: nom::error::ErrorKind, e: nom::Err<VVError>) -> Self {
-        match e {
-            nom::Err::Incomplete(e) => Self::NomNeeded(i.into(), e),
-            nom::Err::Error(e) | nom::Err::Failure(e) => e,
-        }
-    }
-}
diff --git a/src/Rust/vvs_lang/src/parser/mod.rs b/src/Rust/vvs_lang/src/parser/mod.rs
deleted file mode 100644
index 89d575c3ab92f9d5095b140a59b928de39f21725..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/src/parser/mod.rs
+++ /dev/null
@@ -1,110 +0,0 @@
-//! Module responsible to parse the user's code, composed of .VVL files where the jobs are defined
-//! and .VVS files where the global workflow is written explicitly. Some parsing functions are
-//! common between the two parser, those things are expressed here.
-
-mod error;
-mod string;
-mod types;
-
-pub mod vvl;
-pub mod vvs;
-
-use crate::ast::*;
-
-pub(crate) use crate::parser::{error::*, string::string, types::types};
-pub(crate) use nom::{
-    branch::alt,
-    bytes::complete::{is_not, tag, take_while, take_while_m_n},
-    character::{
-        complete::{alpha1, alphanumeric1, char, digit1, multispace0, multispace1},
-        is_alphanumeric,
-    },
-    combinator::{cut, map, map_opt, map_res, opt, peek, recognize, value, verify},
-    error::context,
-    multi::{fold_many0, many0, many0_count, separated_list0, separated_list1},
-    sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
-    IResult, Parser as NomParser,
-};
-pub(crate) use nom_locate::LocatedSpan;
-pub(crate) use std::{cell::RefCell, rc::Rc};
-
-/// A parser span. Will be converted into an AST span latter.
-type PSpan<'a> = LocatedSpan<&'a str>;
-
-pub(crate) fn with_span<'a, T>(
-    mut cb: impl NomParser<PSpan<'a>, T, VVError>,
-) -> impl FnMut(PSpan<'a>) -> VVParserError<'a, (PSpan<'a>, T)> {
-    move |input: PSpan<'a>| {
-        let (input, _) = multispace0(input)?;
-        let (i, res) = cb.parse(input)?;
-        Ok((i, (input, res)))
-    }
-}
-
-pub(crate) fn spaced_tag<'a>(str: &'static str) -> impl FnMut(PSpan<'a>) -> VVParserError<'a, ()> {
-    delimited(multispace0, map(tag(str), |_| ()), multispace0)
-}
-
-pub(crate) fn keyword<'a>(kw: &'static str) -> impl FnMut(PSpan<'a>) -> VVParserError<'a, ()> {
-    delimited(multispace0, plain_tag(kw), multispace0)
-}
-
-pub(crate) fn plain_tag<'a>(t: &'static str) -> impl FnMut(PSpan<'a>) -> VVParserError<'a, ()> {
-    move |i| {
-        let (input, remain) = take_while(|x| is_alphanumeric(x as u8))(tag(t)(i)?.0)?;
-        remain
-            .is_empty()
-            .then_some((input, ()))
-            .ok_or_else(|| nom_err_error!(vvs bare: FailedToGetTag (i.into(), t)))
-    }
-}
-
-pub(crate) fn number(i: PSpan) -> VVParserError<ASTInteger> {
-    alt((
-        map_res(preceded(opt(tag("+")), digit1), |digit_str: PSpan| {
-            digit_str.parse::<ASTInteger>()
-        }),
-        map_res(preceded(tag("-"), digit1), |digit_str: PSpan| {
-            digit_str.parse::<ASTInteger>().map(|x| -x)
-        }),
-    ))(i)
-}
-
-pub(crate) fn float(i: PSpan) -> VVParserError<ASTFloating> {
-    map(
-        pair(
-            opt(alt((tag("+"), tag("-")))),
-            map_res(recognize(tuple((digit1, tag("."), digit1))), |f: PSpan| {
-                f.fragment().parse::<f32>()
-            }),
-        ),
-        |(sign, value)| {
-            sign.map(|s| if s.starts_with('-') { -value } else { value })
-                .unwrap_or(value)
-        },
-    )(i)
-}
-
-pub(crate) fn identifier(input: PSpan) -> VVParserError<&str> {
-    let (input, _) = multispace0(input)?;
-    let (i, id) = match recognize(pair(
-        alt((alpha1::<PSpan, VVError>, tag("_"))),
-        many0_count(alt((alphanumeric1, tag("_")))),
-    ))(input)
-    {
-        Ok(ok) => ok,
-        Err(_) => return nom_err_error!(vvs: NotAnIdentifier (input.into())),
-    };
-    Ok((i, *id.fragment()))
-}
-
-#[test]
-fn test_floats_and_numbers() {
-    assert_eq!(number("1".into()).unwrap().1, 1);
-    assert_eq!(number("0".into()).unwrap().1, 0);
-    assert_eq!(number("-1".into()).unwrap().1, -1);
-    assert_eq!(float("1.0".into()).unwrap().1, 1.0);
-    assert_eq!(float("0.0".into()).unwrap().1, 0.0);
-    assert_eq!(float("-1.0".into()).unwrap().1, -1.0);
-    assert!(float("1.".into()).is_err());
-}
diff --git a/src/Rust/vvs_lang/src/parser/string.rs b/src/Rust/vvs_lang/src/parser/string.rs
deleted file mode 100644
index 5adb03fffa4bbf5938b79ca681b80b970fd4e813..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/src/parser/string.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-use super::*;
-
-/// Parse a unicode sequence, of the form u{XXXX}, where XXXX is 1 to 6
-/// hexadecimal numerals. We will combine this later with parse_escaped_char
-/// to parse sequences like \u{00AC}.
-fn parse_unicode(input: PSpan) -> VVParserError<char> {
-    let parse_hex = take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit());
-    let parse_delimited_hex = preceded(char('u'), delimited(char('{'), parse_hex, char('}')));
-    let parse_u32 = map_res(parse_delimited_hex, move |hex: PSpan| {
-        u32::from_str_radix(hex.fragment(), 16)
-    });
-    map_opt(parse_u32, std::char::from_u32)(input)
-}
-
-/// Parse an escaped character: \n, \t, \r, \u{00AC}, etc.
-fn parse_escaped_char(input: PSpan) -> VVParserError<char> {
-    preceded(
-        char('\\'),
-        alt((
-            parse_unicode,
-            value('\n', char('n')),
-            value('\r', char('r')),
-            value('\t', char('t')),
-            value('\u{08}', char('b')),
-            value('\u{0C}', char('f')),
-            value('\\', char('\\')),
-            value('/', char('/')),
-            value('"', char('"')),
-        )),
-    )
-    .parse(input)
-}
-
-/// Parse a backslash, followed by any amount of whitespace. This is used later
-/// to discard any escaped whitespace.
-fn parse_escaped_whitespace(input: PSpan) -> VVParserError<&str> {
-    let (i, str) = preceded(char('\\'), multispace1)(input)?;
-    Ok((i, str.fragment()))
-}
-
-/// Parse a non-empty block of text that doesn't include \ or "
-fn parse_literal(input: PSpan) -> VVParserError<&str> {
-    verify(map(is_not("\"\\"), |str: PSpan| *str.fragment()), |s: &str| {
-        !s.is_empty()
-    })(input)
-}
-
-/// A string fragment contains a fragment of a string being parsed: either
-/// a non-empty Literal (a series of non-escaped characters), a single
-/// parsed escaped character, or a block of escaped whitespace.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-enum StringFragment<'a> {
-    Literal(&'a str),
-    EscapedChar(char),
-    EscapedWS,
-}
-
-/// Combine parse_literal, parse_escaped_whitespace, and parse_escaped_char
-/// into a StringFragment.
-fn parse_fragment(input: PSpan) -> VVParserError<StringFragment> {
-    alt((
-        map(parse_literal, StringFragment::Literal),
-        map(parse_escaped_char, StringFragment::EscapedChar),
-        value(StringFragment::EscapedWS, parse_escaped_whitespace),
-    ))
-    .parse(input)
-}
-
-/// Parse a string. Use a loop of parse_fragment and push all of the fragments
-/// into an output string.
-pub(crate) fn string(input: PSpan) -> VVParserError<String> {
-    let build_string = fold_many0(parse_fragment, String::new, |mut string, fragment| {
-        match fragment {
-            StringFragment::Literal(s) => string.push_str(s),
-            StringFragment::EscapedChar(c) => string.push(c),
-            StringFragment::EscapedWS => {}
-        }
-        string
-    });
-    delimited(char('"'), build_string, char('"')).parse(input)
-}
-
-#[test]
-fn test_parse_string() {
-    use vvs_utils::assert_err;
-    let data = "\"abc\"";
-    let result = string(data.into());
-    assert_eq!(result.unwrap().1, String::from("abc"));
-
-    let data = "\"tab:\\tafter tab, newline:\\nnew line, quote: \\\", emoji: \\u{1F602}, newline:\\nescaped whitespace: \\    abc\"";
-    let result = string(data.into());
-    assert_eq!(
-        result.unwrap().1,
-        String::from("tab:\tafter tab, newline:\nnew line, quote: \", emoji: 😂, newline:\nescaped whitespace: abc")
-    );
-
-    // Don't do single quotes for now.
-    assert_err!(string("\'abc\'".into()));
-}
diff --git a/src/Rust/vvs_lang/src/parser/types.rs b/src/Rust/vvs_lang/src/parser/types.rs
deleted file mode 100644
index dffdfff7ce32b4261f170101dcf00baec59adb78..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/src/parser/types.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-use super::*;
-
-pub(crate) fn types(input: PSpan) -> VVParserError<ASTType> {
-    todo!()
-}
diff --git a/src/Rust/vvs_lang/src/parser/vvl.rs b/src/Rust/vvs_lang/src/parser/vvl.rs
deleted file mode 100644
index 4ca6daba506d71a49f82b880439f23a51e06839e..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/src/parser/vvl.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//! Module responsible to parse .VVL files, the files where the code is defined.
-
-mod expr;
-mod inst;
-mod tabl;
-mod tupl;
-
-use self::{expr::expr, inst::instruction, tabl::table, tupl::any_tuple};
-use crate::{ast::*, parser::*};
diff --git a/src/Rust/vvs_lang/src/parser/vvl/expr.rs b/src/Rust/vvs_lang/src/parser/vvl/expr.rs
deleted file mode 100644
index cd7fbfe72f7d45092329b4a282fb093d9a71d0fa..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/src/parser/vvl/expr.rs
+++ /dev/null
@@ -1,237 +0,0 @@
-use crate::{ast::*, expression, parser::vvl::*};
-use vvs_utils::either;
-
-#[allow(dead_code)]
-pub(crate) fn expr<'a, 'b>(
-    cache: Rc<RefCell<ASTStringCacheHandle<'b>>>,
-) -> impl Fn(PSpan<'a>) -> VVParserError<'a, ASTExpr> + 'b
-where
-    'b: 'a,
-{
-    macro_rules! expr {
-        // No binary expression, parse a unary expression or something else, here we have reached
-        // the leaf of the tree. We are parsing some things, but we still need to handle more things:
-        // - tuples
-        // Stil need to write some tests!
-        () => {
-            |cache: Rc<RefCell<ASTStringCacheHandle<'b>>>| { move |input| -> VVParserError<'a, ASTExpr> {
-                let (input, _) = multispace0(input)?;
-                let (i, (rvalue, indices, method, args)) = context("expr leaf", tuple((
-                    // Final leaf for the expression tree.
-                    alt((
-                        delimited(spaced_tag("("), expr(cache.clone()), spaced_tag(")")),
-                        map(with_span(preceded(tag("$"), number)),                     |(sp, c)| expression! { sp, Const(ASTConst::Color(c)) }),
-                        map(with_span(keyword("true")),                                |(sp, _)| expression! { sp, True  }),
-                        map(with_span(keyword("false")),                               |(sp, _)| expression! { sp, False }),
-                        map(with_span(keyword("nil")),                                 |(sp, _)| expression! { sp, Nil   }),
-                        map(with_span(preceded(keyword("not"),  expr(cache.clone()))), |(sp, e)| expression! { sp, Unop(ASTUnop::LogicNot, Box::new(e)) }),
-                        map(with_span(preceded(spaced_tag("#"), expr(cache.clone()))), |(sp, e)| expression! { sp, Unop(ASTUnop::Len,      Box::new(e)) }),
-                        map(with_span(preceded(spaced_tag("-"), expr(cache.clone()))), |(sp, e)| expression! { sp, Unop(ASTUnop::Neg,      Box::new(e)) }),
-                        map(with_span(preceded(spaced_tag("~"), expr(cache.clone()))), |(sp, e)| expression! { sp, Unop(ASTUnop::BitNot,   Box::new(e)) }),
-                        map(with_span(identifier),                                     |(sp, n)| expression! { sp, Var(ASTVar(sp.into(), cache.borrow_mut().get_or_insert(n), None)) }),
-                        map(with_span(string),                                         |(sp, s)| expression! { sp, Const(ASTConst::String(cache.borrow_mut().get_or_insert(s)))      }),
-                        map(with_span(float),                                          |(sp, f)| expression! { sp, Const(ASTConst::Floating(f)) }),
-                        map(with_span(number),                                         |(sp, i)| expression! { sp, Const(ASTConst::Integer(i))  }),
-                        map(with_span(table(cache.clone())),                           |(sp, t)| expression! { sp, Table(t) }),
-                        map(with_span(any_tuple(cache.clone())),                       |(sp, t)| expression! { sp, Tuple(t) }),
-                    )),
-                    // Do we need to index into the thing?
-                    many0(alt((
-                        map(delimited(spaced_tag("["), expr(cache.clone()), spaced_tag("]")), |expr| ASTField::Expr(expr.span, expr.content)),
-                        map(with_span(preceded(spaced_tag("."), identifier)), |(span, field)| ASTField::Identifier(span.into(), cache.borrow_mut().get_or_insert(field))),
-                    ))),
-                    // Function call and method invoking stuff
-                    opt(preceded(spaced_tag(":"), identifier)),
-                    opt(delimited(spaced_tag("("), separated_list0(spaced_tag(","), expr(cache.clone())), spaced_tag(")"))),
-                )))(input)?;
-                // Build an expression from the rvalue
-                let expr = either!(!indices.is_empty()
-                    => expression! { input, PrefixExpr(Box::new(rvalue), indices) }
-                    ;  rvalue
-                );
-                // Some logic to handle the call function/method thing
-                let expr = match (method, args) {
-                    (Some(func), Some(args)) => expression! { input, MethodInvok(Box::new(expr), cache.borrow_mut().get_or_insert(func), args) },
-                    (None,       Some(args)) => expression! { input, FuncCall(Box::new(expr), args) },
-                    (Some(_),    None) => todo!("a method invokation without arguments, should return the function with the first argument bounded"),
-                    (None,       None) => expr,
-                };
-                Ok((i, expr))
-            }}
-        };
-
-        // We are in a node of a binary expression. The binary operator can be a keyword or a
-        // symbol list, need to handle those two cases differently.
-        ( $(($str: literal, $op: ident)),+
-          $(; $(($strs: literal, $ops: ident)),+)*
-          $(;)?
-        ) => {
-            |cache: Rc<RefCell<ASTStringCacheHandle<'b>>>| { move |i| -> VVParserError<'a, ASTExpr> {
-                let (input, _) = multispace0(i)?;
-                let next_clozure = expr!($($(($strs, $ops)),+);*);
-                let next_clozure = next_clozure(cache.clone());
-                let (i, initial) = next_clozure(input)?;
-                let (i, _) = multispace0(i)?;
-                let (i, remainder) = many0(alt(($(
-                    |i| -> VVParserError<(ASTBinop, ASTExpr)> {
-                        let (i, item) = either! { $str.chars().next().unwrap().is_ascii_alphabetic()
-                            => preceded(keyword($str), preceded(multispace0, next_clozure.clone()))(i)?
-                            ;  preceded(tag($str),     preceded(multispace0, next_clozure.clone()))(i)?
-                        };
-                        Ok((i, (ASTBinop::$op, item)))
-                    }
-                ),+,)))(i)?;
-                Ok((i, remainder.into_iter().fold(initial, |acc, (oper, expr)| expression! {
-                    ASTSpan::merge(acc.span, expr.span),
-                    Binop(Box::new(acc), oper, Box::new(expr))
-                })))
-            }}
-        };
-    }
-
-    let expr = expr! [ /* 12 */ ("|",   BitOr)
-                     ; /* 11 */ ("^",   BitXor)
-                     ; /* 10 */ ("&",   BitAnd)
-                     ; /* 09 */ ("or",  LogicOr)
-                     ; /* 08 */ ("xor", LogicXor)
-                     ; /* 07 */ ("and", LogicAnd)
-                     ; /* 06 */ ("==",  CmpEQ), ("~=", CmpNE), ("!=", CmpNE)
-                     ; /* 05 */ ("<=",  CmpLE), ("<",  CmpLT), (">=", CmpGE), (">", CmpGT)
-                     ; /* 04 */ ("..",  StrCat)
-                     ; /* 03 */ ("<<",  BitShiftLeft), (">>", BitShiftRight)
-                     ; /* 02 */ ("+",   Add), ("-", Sub)
-                     ; /* 01 */ ("*",   Mul), ("/", Div), ("%", Mod), ("mod", Mod)
-                     ; /* 00 */ ("**",  Power)
-    ];
-
-    expr(cache)
-}
-
-#[test]
-fn test_arithmetic() {
-    use crate::{anon_expression, ast::ASTBinop::*};
-    use hashbrown::HashMap;
-    let strings = Rc::<RefCell<HashMap<u64, ASTString>>>::default();
-    let expr = expr(Rc::new(RefCell::new(ASTStringCacheHandle::new(strings.borrow_mut()))));
-    let expr = move |str: &'static str| expr(str.into());
-
-    assert_eq!(
-        expr("1+2*3").unwrap().1,
-        anon_expression!(Binop(
-            Box::new(anon_expression!(Const(ASTConst::Integer(1)))),
-            Add,
-            Box::new(anon_expression!(Binop(
-                Box::new(anon_expression!(Const(ASTConst::Integer(2)))),
-                Mul,
-                Box::new(anon_expression!(Const(ASTConst::Integer(3))))
-            )))
-        ))
-    );
-    assert_eq!(
-        expr("2*3+1").unwrap().1,
-        anon_expression!(Binop(
-            Box::new(anon_expression!(Binop(
-                Box::new(anon_expression!(Const(ASTConst::Integer(2)))),
-                Mul,
-                Box::new(anon_expression!(Const(ASTConst::Integer(3))))
-            ))),
-            Add,
-            Box::new(anon_expression!(Const(ASTConst::Integer(1)))),
-        ))
-    );
-}
-
-#[test]
-fn test_valid_table() {
-    use crate::{anon_expression, ast::*};
-    use hashbrown::HashMap;
-    use vvs_utils::{assert_ok, assert_some};
-    let strings = Rc::<RefCell<HashMap<u64, ASTString>>>::default();
-    let table = expr(Rc::new(RefCell::new(ASTStringCacheHandle::new(strings.borrow_mut()))));
-    let table = move |str: &'static str| table(str.into());
-    let table = assert_ok!(table(
-        r#"{ toto = "tata", foo = 3.14, ["bar"] = 42, titi = {}, oupsy = nil }"#
-    ));
-
-    let table = match table.1.content {
-        ASTExprVariant::Table(table) => table,
-        expr => panic!("should be a table, got {expr:#?}"),
-    };
-
-    assert_eq!(
-        assert_some!(table.get("toto")).content,
-        anon_expression!(Const(ASTConst::String("tata".into()))).content
-    );
-
-    assert_eq!(
-        assert_some!(table.get("foo")).content,
-        anon_expression!(Const(ASTConst::Floating(3.14))).content
-    );
-
-    assert_eq!(
-        assert_some!(table.get("bar")).content,
-        anon_expression!(Const(ASTConst::Integer(42))).content
-    );
-
-    assert_eq!(
-        assert_some!(table.get("titi")).content,
-        anon_expression!(Table(HashMap::default())).content
-    );
-
-    assert_eq!(
-        assert_some!(table.get("oupsy")).content,
-        anon_expression!(Nil).content
-    );
-}
-
-#[test]
-fn test_redefined_key_table() {
-    use crate::ast::*;
-    use hashbrown::HashMap;
-    use vvs_utils::assert_err;
-    let strings = Rc::<RefCell<HashMap<u64, ASTString>>>::default();
-    let table = expr(Rc::new(RefCell::new(ASTStringCacheHandle::new(strings.borrow_mut()))));
-    let table = move |str: &'static str| table(str.into());
-    assert_err!(table(r#"{ toto = "tata", toto = nil }"#));
-}
-
-#[test]
-fn test_tuple_invalid() {
-    use crate::ast::*;
-    use hashbrown::HashMap;
-    use vvs_utils::assert_err;
-    let strings = Rc::<RefCell<HashMap<u64, ASTString>>>::default();
-    let expr = expr(Rc::new(RefCell::new(ASTStringCacheHandle::new(strings.borrow_mut()))));
-    let expr = move |str: &'static str| expr(str.into());
-    match expr(r#""a", "b", "c""#) {
-        Ok((i, expr)) if i.is_empty() => panic!("successfully parsed {expr:#?}"),
-        _ => {}
-    }
-    assert_err!(expr("(1,)"));
-}
-
-#[test]
-fn test_tuple() {
-    use crate::{anon_expression, ast::*};
-    use hashbrown::HashMap;
-    use vvs_utils::assert_ok;
-    let strings = Rc::<RefCell<HashMap<u64, ASTString>>>::default();
-    let expr = expr(Rc::new(RefCell::new(ASTStringCacheHandle::new(strings.borrow_mut()))));
-    let expr = move |str: &'static str| expr(str.into());
-    assert_eq!(
-        assert_ok!(expr("(1, 2, 3, 4)")).1,
-        anon_expression!(Tuple(vec![
-            anon_expression!(Const(ASTConst::Integer(1))),
-            anon_expression!(Const(ASTConst::Integer(2))),
-            anon_expression!(Const(ASTConst::Integer(3))),
-            anon_expression!(Const(ASTConst::Integer(4))),
-        ]))
-    );
-    assert_eq!(
-        assert_ok!(expr("(1, 2,)")).1,
-        anon_expression!(Tuple(vec![
-            anon_expression!(Const(ASTConst::Integer(1))),
-            anon_expression!(Const(ASTConst::Integer(2))),
-        ]))
-    );
-}
diff --git a/src/Rust/vvs_lang/src/parser/vvl/inst.rs b/src/Rust/vvs_lang/src/parser/vvl/inst.rs
deleted file mode 100644
index 4699bcaf2be78b62f998dd1acca2bb509dff1376..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/src/parser/vvl/inst.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-use crate::{ast::*, instruction, parser::vvl::*};
-
-pub(crate) fn do_end_block<'a, 'b>(
-    r#do: &'static str,
-    end: &'static str,
-    cache: Rc<RefCell<ASTStringCacheHandle<'b>>>,
-) -> impl Fn(PSpan<'a>) -> VVParserError<'a, Vec<ASTInstr>> + 'b
-where
-    'b: 'a,
-{
-    move |input| {
-        let (input, _) = multispace0(input)?;
-        delimited(keyword(r#do), many0(instruction(cache.clone())), keyword(end))(input)
-    }
-}
-
-#[allow(dead_code)]
-pub(crate) fn instruction<'a, 'b>(
-    cache: Rc<RefCell<ASTStringCacheHandle<'b>>>,
-) -> impl Fn(PSpan<'a>) -> VVParserError<'a, ASTInstr> + 'b
-where
-    'b: 'a,
-{
-    move |input| {
-        let (input, _) = multispace0(input)?;
-        terminated(
-            alt((
-                // Break/Continue loops
-                map(with_span(keyword("break")), |(sp, _)| instruction!(sp, Break)),
-                map(with_span(keyword("continue")), |(sp, _)| instruction!(sp, Continue)),
-                // Variable assignation. Don't do the destructuring for now.
-                map(
-                    with_span(separated_pair(
-                        expr(cache.clone()),
-                        spaced_tag("="),
-                        expr(cache.clone()),
-                    )),
-                    |(sp, (dest, src))| instruction!(sp, Assign(vec![dest], vec![src])),
-                ),
-                // Variable declaration. Don't do the destructuring for now.
-                map(
-                    with_span(tuple((
-                        keyword("let"),
-                        identifier,
-                        opt(types),
-                        spaced_tag("="),
-                        expr(cache.clone()),
-                    ))),
-                    |(sp, (_, name, ty, _, decl))| {
-                        let var = ASTVar(sp.into(), cache.borrow_mut().get_or_insert(name), ty);
-                        instruction!(sp, Decl(vec![var], vec![decl]))
-                    },
-                ),
-                // A do-end block with a list of instructions inside it.
-                map(with_span(do_end_block("do", "end", cache.clone())), |(sp, body)| {
-                    instruction!(sp, Block(body))
-                }),
-                // While loop.
-                map(
-                    with_span(pair(
-                        preceded(keyword("while"), expr(cache.clone())),
-                        do_end_block("do", "end", cache.clone()),
-                    )),
-                    |(sp, (cond, body))| instruction!(sp, WhileDo(cond, body)),
-                ),
-                // A DoWhile block (or a reapeat until in lua...)
-                map(
-                    with_span(pair(do_end_block("do", "until", cache.clone()), expr(cache.clone()))),
-                    |(sp, (body, cond))| instruction!(sp, RepeatUntil(cond, body)),
-                ),
-            )),
-            // We may terminate with a semicolon
-            opt(spaced_tag(";")),
-        )(input)
-    }
-}
diff --git a/src/Rust/vvs_lang/src/parser/vvl/tabl.rs b/src/Rust/vvs_lang/src/parser/vvl/tabl.rs
deleted file mode 100644
index 25f8d36df88c09b665561a1465f32353f0520cdc..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/src/parser/vvl/tabl.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use super::*;
-use hashbrown::HashMap;
-
-/// Parses the keys in tables or returns an error. Keys can be identifiers or a string between
-/// square braquets: `[`, `]`.
-fn key<'a, 'b>(cache: Rc<RefCell<ASTStringCacheHandle<'b>>>) -> impl Fn(PSpan<'a>) -> VVParserError<'a, ASTString> + 'b
-where
-    'b: 'a,
-{
-    move |input: PSpan| -> VVParserError<ASTString> {
-        let (input, _) = multispace0(input)?;
-        alt((
-            map(delimited(spaced_tag("["), string, spaced_tag("]")), |str| {
-                cache.borrow_mut().get_or_insert(str)
-            }),
-            map(identifier, |str| cache.borrow_mut().get_or_insert(str)),
-        ))(input)
-    }
-}
-
-/// Parses a separator for key value pairs for the table parser. In Lua separators can be `,` or
-/// `;` for some reasons...
-fn separator(input: PSpan) -> VVParserError<()> {
-    alt((spaced_tag(","), spaced_tag(";")))(input)
-}
-
-/// Parses a table or returns an error.
-pub(crate) fn table<'a, 'b>(
-    cache: Rc<RefCell<ASTStringCacheHandle<'b>>>,
-) -> impl Fn(PSpan<'a>) -> VVParserError<'a, ASTTable<ASTExpr>> + 'b
-where
-    'b: 'a,
-{
-    move |input| {
-        let (input, _) = multispace0(input)?;
-        let table_key_value_pair = separated_pair(key(cache.clone()), spaced_tag("="), expr(cache.clone()));
-        let (i, content) = context(
-            "table",
-            delimited(
-                spaced_tag("{"),
-                separated_list0(separator, table_key_value_pair),
-                preceded(opt(separator), spaced_tag("}")),
-            ),
-        )(input)?;
-        let hashmap = HashMap::with_capacity(content.len());
-        let hashmap = content.into_iter().try_fold(hashmap, |mut hashmap, (key, value)| {
-            if hashmap.contains_key(&key) {
-                nom_err_error!(vvs: TableIndexRedefined (value.span, key))
-            } else {
-                hashmap.insert(key, value);
-                Ok(hashmap)
-            }
-        })?;
-        Ok((i, hashmap))
-    }
-}
diff --git a/src/Rust/vvs_lang/src/parser/vvl/tupl.rs b/src/Rust/vvs_lang/src/parser/vvl/tupl.rs
deleted file mode 100644
index 9bd32b635c388e59218812fcd5b78ee5ac5e066e..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/src/parser/vvl/tupl.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-use super::*;
-
-/// Unlike Lua, we require parens (`(` `)`) around tuples.
-pub(crate) fn any_tuple<'a, 'b>(
-    cache: Rc<RefCell<ASTStringCacheHandle<'b>>>,
-) -> impl Fn(PSpan<'a>) -> VVParserError<'a, Vec<ASTExpr>> + 'b
-where
-    'b: 'a,
-{
-    move |input| {
-        let (input, _) = multispace0(input)?;
-        let (i, (head, mut tail)) = delimited(
-            spaced_tag("("),
-            separated_pair(
-                expr(cache.clone()),
-                spaced_tag(","),
-                separated_list1(spaced_tag(","), expr(cache.clone())),
-            ),
-            preceded(opt(spaced_tag(",")), spaced_tag(")")),
-        )(input)?;
-        tail.insert(0, head);
-        Ok((i, tail))
-    }
-}
diff --git a/src/Rust/vvs_lang/src/parser/vvs.rs b/src/Rust/vvs_lang/src/parser/vvs.rs
deleted file mode 100644
index 727017478067eb2dfe2f315de931b7096af3a656..0000000000000000000000000000000000000000
--- a/src/Rust/vvs_lang/src/parser/vvs.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//! Module responsible to parse .VVS files, the files where jobs from .VVS files are composed and
-//! where the global workflow of the script is written by the user.
-
-use std::path::Path;
-
-use crate::{ast::*, parser::*};
-
-/// Parses the content of a file.
-pub fn parse_vvs<'a>(_: impl AsRef<str> + 'a) -> VVParserError<'a, Program> {
-    todo!()
-}
-
-/// Parses a file.
-pub fn parse_vvs_file(_: impl AsRef<Path>) -> VVResult<Program> {
-    todo!()
-}
diff --git a/src/Rust/vvs_lib/Cargo.toml b/src/Rust/vvs_lib/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..0285744a772987a0dd0f8c6c621594ca38e5dab1
--- /dev/null
+++ b/src/Rust/vvs_lib/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name              = "vvs_lib"
+description       = "A C library to expose functionalities to C/C++"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+
+[lib]
+name       = "vivy"
+crate-type = ["staticlib"]
+
+[dependencies]
+log.workspace        = true
+serde.workspace      = true
+hashbrown.workspace  = true
+serde_json.workspace = true
+
+vvs_ass.workspace = true
+
+[build-dependencies]
+cbindgen.workspace = true
diff --git a/src/Rust/vvs_lib/build.rs b/src/Rust/vvs_lib/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..66862fd632de377b606a610b88ebc7d1bf0a13f6
--- /dev/null
+++ b/src/Rust/vvs_lib/build.rs
@@ -0,0 +1,24 @@
+use cbindgen::{Braces, Language, Style};
+
+fn main() {
+    cbindgen::Builder::new()
+        .with_crate(std::env::var("CARGO_MANIFEST_DIR").unwrap())
+        .with_parse_deps(true)
+        .with_parse_include(&["vvs_ass"])
+        .with_documentation(true)
+        .with_header("/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */")
+        .with_language(Language::C)
+        .with_no_includes()
+        .with_sys_include("inttypes.h")
+        .with_include_version(true)
+        .with_line_length(120)
+        .with_style(Style::Both)
+        .with_cpp_compat(true)
+        .with_pragma_once(true)
+        .with_namespaces(&["VVLib", "C"])
+        .with_tab_width(4)
+        .with_braces(Braces::NextLine)
+        .generate()
+        .expect("Failed to generate config")
+        .write_to_file("../VVLib.h");
+}
diff --git a/src/Rust/vvs_lib/src/ass_elements.rs b/src/Rust/vvs_lib/src/ass_elements.rs
new file mode 100644
index 0000000000000000000000000000000000000000..aed629932be583bb28f2b0aa453d45ec4ae563a3
--- /dev/null
+++ b/src/Rust/vvs_lib/src/ass_elements.rs
@@ -0,0 +1,191 @@
+//! Contains wrappers for the container, the line, syllabes, etc...
+#![allow(clippy::missing_safety_doc)]
+
+use crate::{AuxTable, StringSlice};
+use alloc::{boxed::Box, vec::Vec};
+use core::{
+    ffi::{c_char, CStr},
+    mem,
+    ptr::{self, NonNull},
+};
+use vvs_ass::{ass_container_from_file, ASSStyle};
+
+/// Wraps the container that holds all the content of the ASS file / Vivy file.
+pub struct ASSContainer(vvs_ass::ASSContainer<AuxTable>);
+
+/// Wraps a line in an ASS file.
+pub struct ASSLine(vvs_ass::ASSLine<AuxTable>);
+
+/// Wraps syllabes, contained in lines in ASS files.
+pub struct ASSSyllabe(vvs_ass::ASSSyllabe<AuxTable>);
+
+/// Get the number of lines in the container.
+#[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ASSContainerGetLinesCount(this: *const ASSContainer) -> i32 { (*this).0.lines.len() as i32 }
+
+/// Get the number of syllabes in the line.
+#[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ASSLineGetSyllabesCount(this: *const ASSLine) -> i32 { (*this).0.content.len() as i32 }
+
+/// Get a line by its number in the container.
+#[no_mangle]
+pub unsafe extern "C" fn ASSContainerGetLineAt(this: *mut ASSContainer, idx: i32) -> *mut ASSLine {
+    let line = (*this).0.lines.get_mut(idx as usize).map(|l| l as *mut _ as *mut _);
+    line.unwrap_or_else(|| {
+        log::error!("failed to get line n°{idx}");
+        core::ptr::null_mut()
+    })
+}
+
+/// Get a syllabe in a line by its index.
+#[no_mangle]
+pub unsafe extern "C" fn ASSLineGetSyllabeAt(this: *mut ASSLine, idx: i32) -> *mut ASSSyllabe {
+    let syl = (*this).0.content.get_mut(idx as usize).map(|s| s as *mut _ as *mut _);
+    syl.unwrap_or_else(|| {
+        log::error!("failed to get syllabe n°{idx}");
+        core::ptr::null_mut()
+    })
+}
+
+/// Tells whever a line is commented or not.
+#[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ASSLineIsCommented(this: *const ASSLine) -> bool { (*this).0.is_comment }
+
+/// Gets the style of the line, or 'Default' if it was not found/specified.
+#[no_mangle]
+pub unsafe extern "C" fn ASSLineGetStyle<'a>(this: *const ASSLine) -> StringSlice<'a> {
+    match (*this).0.aux.0.get("style") {
+        Some(str) => StringSlice::from(str),
+        _ => StringSlice::from("Default"),
+    }
+}
+
+/// Get the content of a syllabe.
+#[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ASSSyllabeGetContent<'a>(this: *const ASSSyllabe) -> StringSlice<'a> { StringSlice::from(&(*this).0.content) }
+
+/// Get the duration of a syllabe.
+#[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ASSSyllabeGetDuration(this: *const ASSSyllabe) -> i32 { (*this).0.fini.saturating_sub((*this).0.start) }
+
+/// Get the start of a syllabe.
+#[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ASSSyllabeGetStartTime(this: *const ASSSyllabe) -> i32 { (*this).0.start }
+
+/// Get the end time of a syllabe.
+#[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ASSSyllabeGetFiniTime(this: *const ASSSyllabe) -> i32 { (*this).0.fini }
+
+/// Set the duration of a syllabe.
+#[no_mangle]
+pub unsafe extern "C" fn ASSSyllabeSetDuration(this: *mut ASSSyllabe, duration: i32) {
+    (*this).0.fini = (*this).0.start.saturating_add(duration);
+}
+
+/// Set the start of a syllabe.
+#[no_mangle]
+pub unsafe extern "C" fn ASSSyllabeSetStartTime(this: *mut ASSSyllabe, time: i32) {
+    (*this).0.start = time;
+    (*this).0.fini = (*this).0.fini.max(time);
+}
+
+/// Set the end of a syllabe.
+#[no_mangle]
+pub unsafe extern "C" fn ASSSyllabeSetFiniTime(this: *mut ASSSyllabe, time: i32) {
+    (*this).0.fini = time;
+    (*this).0.start = (*this).0.fini.min(time);
+}
+
+/// Load the ASS from a file, returns nullptr if an error was encountred.
+#[no_mangle]
+pub unsafe extern "C" fn ASSContainerFromFile(path: NonNull<c_char>) -> *mut ASSContainer {
+    let container = CStr::from_ptr(path.as_ptr() as *const _).to_str().map(|path| {
+        ass_container_from_file(path)
+            .map(|ass: vvs_ass::ASSContainer<AuxTable>| Box::into_raw(Box::new(ass)) as *mut ASSContainer)
+            .map_err(|err| log::error!("failed to load file: {err}"))
+    });
+    match container.inspect_err(|err| log::error!("invalid utf8 filename: {err}")) {
+        Ok(Ok(container)) => container,
+        _ => ptr::null_mut(),
+    }
+}
+
+/// Get a style out of the container by its name.
+#[no_mangle]
+pub unsafe extern "C" fn ASSContainerGetStyleByName(this: *mut ASSContainer, name: StringSlice) -> *mut ASSStyle {
+    let style = (*this).0.styles.get_mut(name.as_str()).map(|s| s as *mut _);
+    style.unwrap_or_else(|| {
+        log::error!("no sytle `{}` in ass container", name.as_str());
+        core::ptr::null_mut()
+    })
+}
+
+/// Get the name of a style by its position.
+#[no_mangle]
+pub unsafe extern "C" fn ASSContainerGetStyleNameAt<'a>(this: *const ASSContainer, idx: i32) -> StringSlice<'a> {
+    let mut keys: Vec<_> = (*this).0.styles.keys().collect();
+    keys.sort();
+    keys.get(idx as usize)
+        .map(StringSlice::from)
+        .unwrap_or_else(|| StringSlice::from("Default"))
+}
+
+/// Get the number of styles in the container.
+#[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ASSContainerGetStylesCount(this: *const ASSContainer) -> i32 { (*this).0.styles.len() as i32 }
+
+/// Set the start time of the line.
+#[no_mangle]
+pub unsafe extern "C" fn ASSLineSetStartTime(this: *mut ASSLine, time: i32) {
+    (*this).0.start = time;
+    (*this).0.fini = (*this).0.fini.max(time);
+    for syl in &mut (*this).0.content {
+        syl.start = syl.start.max(time);
+        syl.fini = syl.fini.max(time);
+    }
+}
+
+/// Set the end time of a line.
+#[no_mangle]
+pub unsafe extern "C" fn ASSLineSetFiniTime(this: *mut ASSLine, time: i32) {
+    (*this).0.fini = time;
+    (*this).0.start = (*this).0.start.min(time);
+    for syl in &mut (*this).0.content {
+        syl.start = syl.start.min(time);
+        syl.fini = syl.fini.min(time);
+    }
+}
+
+/// Get the duration of a line.
+#[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ASSLineGetDuration(this: *const ASSLine) -> i32 { (*this).0.fini.saturating_sub((*this).0.start) }
+
+/// Set the duration of a line.
+#[no_mangle]
+pub unsafe extern "C" fn ASSLineSetDuration(this: *mut ASSLine, duration: i32) {
+    (*this).0.fini = (*this).0.start.saturating_add(duration);
+}
+
+/// Get the start time of a line.
+#[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ASSLineGetStartTime(this: *const ASSLine) -> i32 { (*this).0.start }
+
+/// Get the end time of a line.
+#[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ASSLineGetFiniTime(this: *const ASSLine) -> i32 { (*this).0.fini }
+
+/// Drop the container. It is file to pass a null pointer to this function.
+#[no_mangle]
+pub unsafe extern "C" fn ASSContainerDrop(this: *mut ASSContainer) {
+    #[allow(dead_code)]
+    const ASSERT_STRUCT_SIZES: () = {
+        macro_rules! assert_sizes {
+            ($ty: ident) => {
+                assert!(
+                    mem::size_of::<$ty>() == mem::size_of::<vvs_ass::$ty<AuxTable>>(),
+                    concat!("invalid sizes for ", stringify!($ty), " wrapper")
+                );
+                assert!(
+                    mem::align_of::<$ty>() == mem::align_of::<vvs_ass::$ty<AuxTable>>(),
+                    concat!("invalid alignements for ", stringify!($ty), " wrapper")
+                );
+            };
+        }
+        assert_sizes!(ASSContainer);
+        assert_sizes!(ASSLine);
+        assert_sizes!(ASSSyllabe);
+    };
+
+    if !this.is_null() {
+        drop(unsafe { Box::from_raw(this) });
+    }
+}
diff --git a/src/Rust/vvs_lib/src/ass_style.rs b/src/Rust/vvs_lib/src/ass_style.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a67fbdbd471b836b45776db56b34beaa5379cdfa
--- /dev/null
+++ b/src/Rust/vvs_lib/src/ass_style.rs
@@ -0,0 +1,13 @@
+//! Contains wrappers for the styles.
+
+use crate::StringSlice;
+use vvs_ass::ASSStyle;
+
+/// Get the name of the style.
+///
+/// # Safety
+/// It is up to the user to ensure that the style is not dropped before the returned pointer.
+#[no_mangle]
+pub extern "C" fn ASSStyleGetName(this: &ASSStyle) -> StringSlice {
+    StringSlice::from(&this.name)
+}
diff --git a/src/Rust/vvs_lib/src/aux_table.rs b/src/Rust/vvs_lib/src/aux_table.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f5f853dcacfb9205460d5d8171a12aaba6e6b1cc
--- /dev/null
+++ b/src/Rust/vvs_lib/src/aux_table.rs
@@ -0,0 +1,10 @@
+use alloc::string::String;
+
+#[derive(Debug, Clone, Default, PartialEq)]
+pub struct AuxTable(pub(crate) hashbrown::HashMap<String, String>);
+
+impl vvs_ass::AuxTable for AuxTable {
+    fn deep_clone(&self) -> Self {
+        Self(self.0.clone())
+    }
+}
diff --git a/src/Rust/vvs_lib/src/lib.rs b/src/Rust/vvs_lib/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e1e35aa4bc624695f3d17915d22802110103e2e5
--- /dev/null
+++ b/src/Rust/vvs_lib/src/lib.rs
@@ -0,0 +1,49 @@
+//! Here we define the things that will be exported to C/C++ code. We use PascalCase as it is not
+//! very common and getters must be of the form `{StructName}{Get,Set}{TheField}` and methods of
+//! the form `{StructName}{FunctionName}`. For free functions we use `{TheCrate}{FunctionName}`.
+
+#![allow(non_snake_case)]
+#![no_std]
+
+extern crate alloc;
+
+pub mod ass_elements;
+pub mod ass_style;
+mod aux_table;
+pub mod vivy;
+
+use crate::aux_table::AuxTable;
+use core::{ffi::c_char, marker, slice, str};
+
+/// Represents a string slice, the user may not modify this slice, never! Note that the string is
+/// not null terminated and may contains null bytes in it, use the len attribute to get the length
+/// of this string and convert it to your linking.
+///
+/// # Safety
+/// Note that you must always put unicode inside a string slice!
+#[repr(C)]
+pub struct StringSlice<'a> {
+    len: usize,
+    str: *const c_char,
+    _data: marker::PhantomData<&'a c_char>,
+}
+
+impl<'a> StringSlice<'a> {
+    /// # Safety
+    /// We expect the content of the string slice to be valid UTF6...
+    #[inline]
+    pub unsafe fn as_str(&self) -> &'a str {
+        str::from_utf8_unchecked(slice::from_raw_parts(self.str as *const _, self.len))
+    }
+}
+
+impl<'a, S> From<S> for StringSlice<'a>
+where
+    S: AsRef<str>,
+{
+    #[inline]
+    fn from(value: S) -> Self {
+        let value = value.as_ref();
+        StringSlice { len: value.len(), str: value.as_ptr() as *const _, _data: marker::PhantomData }
+    }
+}
diff --git a/src/Rust/vvs_lib/src/vivy.rs b/src/Rust/vvs_lib/src/vivy.rs
new file mode 100644
index 0000000000000000000000000000000000000000..42301ab407e663fedfedd84b8beae06707891975
--- /dev/null
+++ b/src/Rust/vvs_lib/src/vivy.rs
@@ -0,0 +1,31 @@
+use alloc::string::String;
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, PartialEq, Eq)]
+pub enum VivyDocumentCapabilities {
+    AudioAble = (1 << 1),
+    VideoAble = (1 << 2),
+    AssAble = (1 << 3),
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "PascalCase")]
+pub struct VivyDocument {
+    #[serde(default = "u64::default")]
+    pub capabilities: u64,
+    pub name: String,
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "PascalCase")]
+#[serde(tag = "DocumentVersion", content = "SubDocuments")]
+pub enum VivySubDocument {
+    Alpha { sub_ass: Option<String>, sub_audio: Option<String>, sub_video: Option<String> },
+}
+
+#[test]
+fn test_deserialize() {
+    if let Err(err) = serde_json::from_str::<VivyDocument>(include_str!("../test/sample.vivy")) {
+        panic!("{err}")
+    }
+}
diff --git a/src/Rust/vvs_lib/test/sample.vivy b/src/Rust/vvs_lib/test/sample.vivy
new file mode 100644
index 0000000000000000000000000000000000000000..16bd90a6d3d88e195f8cc8d76fd6672145dde2fb
--- /dev/null
+++ b/src/Rust/vvs_lib/test/sample.vivy
@@ -0,0 +1,10 @@
+{
+    "Name":             "test",
+    "Capabilities":     12,
+    "DocumentVersion":  "alpha",
+    "SubDocuments": {
+        "SubAss":   "vivy/src/Rust/vvs_ass/utils/empty.ass",
+        "SubVideo": "data/4036f7f60c08bf70741f118eca95dff61facfb66199351e9e40900071cd5322d.mkv"
+    }
+}
+
diff --git a/src/Rust/vvs_llvm/Cargo.toml b/src/Rust/vvs_llvm/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..98bd38c99bcee84a673907c0d280632c9c784205
--- /dev/null
+++ b/src/Rust/vvs_llvm/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name              = "vvs_llvm"
+description       = "Link against and re-export llvm things"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+
+[dependencies]
+anyhow.workspace = true
+log.workspace    = true
+llvm-sys = { version = "181", features = [
+    "strict-versioning",       # Be strict about versions, we do want the lattest thing
+    "no-llvm-linking",         # We do the linking ourself because of problems when using spack: https://github.com/spack/spack/discussions/36192
+    "disable-alltargets-init", # Without linking we must rely on our own inits...
+] }
+
+[features]
+link = []
diff --git a/src/Rust/vvs_llvm/src/init.rs b/src/Rust/vvs_llvm/src/init.rs
new file mode 100644
index 0000000000000000000000000000000000000000..dfff4b9a03a9461cbb29cf99485e5f46a0ff36ad
--- /dev/null
+++ b/src/Rust/vvs_llvm/src/init.rs
@@ -0,0 +1,37 @@
+//! Initialize LLVM targets and such. This module only exports one function:
+//! [self::initialize_llvm]. Depending on the target architecture we select
+//! the correct function...
+
+use anyhow::anyhow;
+use llvm_sys::target_machine::*;
+use std::ffi::CStr;
+
+/// Be sure to init LLVM only once. We use an atomic usize because it is supported on all the
+/// platforms!
+fn call_once() -> bool {
+    use std::sync::atomic::{AtomicUsize, Ordering::*};
+    static INIT_ONCE: AtomicUsize = AtomicUsize::new(0);
+    INIT_ONCE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
+}
+
+fn print_llvm_infos() {
+    let triple = unsafe { CStr::from_ptr(LLVMGetDefaultTargetTriple()) }.to_string_lossy();
+    let cpu = unsafe { CStr::from_ptr(LLVMGetHostCPUName()) }.to_string_lossy();
+    let cpu_features = unsafe { CStr::from_ptr(LLVMGetHostCPUFeatures()) }.to_string_lossy();
+
+    log::debug!("got default triple: `{triple}`");
+    log::debug!("got cpu `{cpu}` with features: {cpu_features}");
+}
+
+#[cfg(target_arch = "x86_64")]
+pub fn initialize_llvm() -> anyhow::Result<()> {
+    call_once()
+        .then(|| unsafe {
+            llvm_sys::target::LLVMInitializeX86Target();
+            print_llvm_infos();
+        })
+        .ok_or_else(|| anyhow!("llvm was already initialized for this executable!"))
+}
+
+#[cfg(not(target_arch = "x86_64"))]
+compile_error!("this target is not supported for now");
diff --git a/src/Rust/vvs_llvm/src/iter.rs b/src/Rust/vvs_llvm/src/iter.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e1fae55f415325ca0488b9da15215ebca8095240
--- /dev/null
+++ b/src/Rust/vvs_llvm/src/iter.rs
@@ -0,0 +1,102 @@
+//! Utility functions and structures to iterate over an LLVM function and in the basic blocks.
+
+use crate::*;
+use std::ptr;
+
+/// Iterate over the basic blocks in a function.
+#[derive(Clone, Copy)]
+pub struct LLVMFunctionIter {
+    curr_bb: LLVMBasicBlockRef,
+    last_bb: LLVMBasicBlockRef,
+    function: LLVMValueRef,
+    index: u32,
+}
+
+#[derive(Clone, Copy)]
+pub struct LLVMBasicBlockIter {
+    curr_instr: LLVMValueRef,
+    last_instr: LLVMValueRef,
+}
+
+impl Iterator for LLVMFunctionIter {
+    type Item = LLVMBasicBlockRef;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        (!self.curr_bb.is_null() && !self.last_bb.is_null())
+            .then(|| match unsafe { LLVMGetNextBasicBlock(self.curr_bb) } {
+                ret if ret.is_null() => None,
+                ret => {
+                    self.curr_bb = if ret == self.last_bb { ptr::null_mut() } else { ret };
+                    self.index += 1;
+                    Some(ret)
+                }
+            })
+            .flatten()
+    }
+
+    fn last(self) -> Option<Self::Item> {
+        (!self.last_bb.is_null()).then_some(self.last_bb)
+    }
+
+    fn count(self) -> usize {
+        unsafe { LLVMFunctionIter::count_bbs(&self) }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let count = unsafe { LLVMFunctionIter::count_bbs(self) };
+        (count, Some(count))
+    }
+}
+
+impl Iterator for LLVMBasicBlockIter {
+    type Item = LLVMValueRef;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        (!self.curr_instr.is_null() && !self.last_instr.is_null())
+            .then(|| match unsafe { LLVMGetNextInstruction(self.curr_instr) } {
+                ret if ret.is_null() => None,
+                ret => {
+                    self.curr_instr = if ret == self.last_instr { ptr::null_mut() } else { ret };
+                    Some(ret)
+                }
+            })
+            .flatten()
+    }
+
+    fn last(self) -> Option<Self::Item> {
+        (!self.last_instr.is_null()).then_some(self.last_instr)
+    }
+}
+
+impl LLVMFunctionIter {
+    /// Create a new iterator over a function. If the passed value is not a function this
+    /// constructor will panic.
+    ///
+    /// # Safety
+    /// The passed value must be a valid pointer to [LLVMValue]. You may not create new basic
+    /// blocks while using this iterator.
+    pub unsafe fn new(function: LLVMValueRef) -> Self {
+        assert!(!LLVMIsAFunction(function).is_null(), "should pass functions...");
+        Self {
+            curr_bb: LLVMGetFirstBasicBlock(function),
+            last_bb: LLVMGetLastBasicBlock(function),
+            index: 0,
+            function,
+        }
+    }
+
+    unsafe fn count_bbs(&self) -> usize {
+        unsafe { LLVMCountBasicBlocks(self.function) }.saturating_sub(self.index) as usize
+    }
+}
+
+impl LLVMBasicBlockIter {
+    /// Create a new iterator over a basic block.
+    ///
+    /// # Safety
+    /// The passed value must be a valid pointer to [LLVMBasicBlock]. You may not insert new values
+    /// into the block while using this iterator.
+    pub unsafe fn new(bb: LLVMBasicBlockRef) -> Self {
+        Self { curr_instr: LLVMGetFirstInstruction(bb), last_instr: LLVMGetBasicBlockTerminator(bb) }
+    }
+}
diff --git a/src/Rust/vvs_llvm/src/lib.rs b/src/Rust/vvs_llvm/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..92320adaf6ae9aba688c554f40bce030471f7220
--- /dev/null
+++ b/src/Rust/vvs_llvm/src/lib.rs
@@ -0,0 +1,80 @@
+//! Re-exports LLVM stuff
+
+#[cfg(feature = "link")]
+pub mod build {
+    //! Utility functions to link against LLVM without relying to [llvm-sys]. The function
+    //! [llvm_link] should be run from the build.rs script of any executable or library depending
+    //! on [vvs_llvm].
+
+    use anyhow::{anyhow, bail, Context};
+    use std::process::{Command, Output};
+
+    /// Run a command with said arguments and returns the stdout of said command.
+    fn run<const N: usize>(cmd: &'static str, args: [&'static str; N]) -> anyhow::Result<Vec<u8>> {
+        match Command::new(cmd).args(args).output()? {
+            Output { status, stdout, .. } if status.success() => Ok(stdout),
+            Output { stderr, .. } => Err(anyhow!(
+                "failed to run `{cmd}`: {}",
+                std::str::from_utf8(&stderr).with_context(|| format!("`{cmd}` failed with non-utf8 stderr"))?
+            )),
+        }
+    }
+
+    /// Prints info for cargo to link against LLVM libraries
+    pub fn llvm_link() -> anyhow::Result<()> {
+        let libdir = std::str::from_utf8(&run("llvm-config", ["--libdir"])?)
+            .with_context(|| "`llvm-config --libdir` failed with non-utf8 stdout")?
+            .trim()
+            .to_string();
+        println!("cargo:rustc-link-search={libdir}");
+
+        let ty = match std::str::from_utf8(&run("llvm-config", ["--shared-mode"])?)?.trim() {
+            // In dynamic mode, we may need to do something about the rpath...
+            "shared" => {
+                println!("cargo:rustc-link-arg=-Wl,-rpath={libdir}"); // rpath for executable
+                println!("cargo:rustc-env=LD_LIBRARY_PATH={libdir}"); // for tests
+                "dylib"
+            }
+
+            // Static mode, just include all the .a files. We also need some system libs...
+            "static" => {
+                println!("cargo:rustc-link-arg=-lstdc++");
+                std::str::from_utf8(&run("llvm-config", ["--system-libs"])?)?
+                    .trim()
+                    .split_ascii_whitespace()
+                    .for_each(|lib| println!("cargo:rustc-link-arg={lib}"));
+                "static"
+            }
+
+            // Err...
+            out => bail!("invalid returned value `{out}`"),
+        };
+
+        std::str::from_utf8(&run("llvm-config", ["--libs"])?)?
+            .trim()
+            .split_ascii_whitespace()
+            .flat_map(|name| name.strip_prefix("-l"))
+            .for_each(|name| println!("cargo:rustc-link-lib={ty}={name}"));
+
+        println!("cargo:rerun-if-changed=build.rs");
+        Ok(())
+    }
+}
+
+pub use llvm_sys::{
+    analysis::*,
+    core::*,
+    error::*,
+    orc2::{ee::*, lljit::*, *},
+    prelude::*,
+    target::*,
+    target_machine::*,
+    transforms::pass_builder::*,
+    *,
+};
+
+mod init;
+mod iter;
+
+pub use init::*;
+pub use iter::*;
diff --git a/src/Rust/vvs_parser/Cargo.toml b/src/Rust/vvs_parser/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..f078adec87c6ec936c8723629e414aec5581d653
--- /dev/null
+++ b/src/Rust/vvs_parser/Cargo.toml
@@ -0,0 +1,39 @@
+[package]
+name        = "vvs_parser"
+license     = "MPL-2.0"
+description = "A lossless Lua parser hacked to parse VVS"
+
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+
+
+[dependencies]
+vvs_parser_derive.workspace = true
+
+bytecount.workspace          = true
+cfg-if.workspace             = true
+derive_more.workspace        = true
+paste.workspace              = true
+serde.workspace              = true
+smol_str.workspace           = true
+hashbrown.workspace          = true
+anyhow.workspace             = true
+log.workspace                = true
+codespan.workspace           = true
+codespan-reporting.workspace = true
+termcolor.workspace          = true
+
+[dev-dependencies]
+criterion.workspace = true
+insta.workspace     = true
+
+[[bench]]
+name = "date"
+path = "../benches/date.rs"
+harness = false
+
+[[bench]]
+name = "t"
+path = "../benches/t.rs"
+harness = false
diff --git a/src/Rust/vvs_parser/LICENSE.md b/src/Rust/vvs_parser/LICENSE.md
new file mode 100644
index 0000000000000000000000000000000000000000..2b8bbd4546a3f2c86fb661e735422cda8d896427
--- /dev/null
+++ b/src/Rust/vvs_parser/LICENSE.md
@@ -0,0 +1,347 @@
+Mozilla Public License Version 2.0
+==================================
+
+### 1. Definitions
+
+**1.1. “Contributor”**
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+**1.2. “Contributor Version”**
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+**1.3. “Contribution”**
+    means Covered Software of a particular Contributor.
+
+**1.4. “Covered Software”**
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+**1.5. “Incompatible With Secondary Licenses”**
+    means
+
+* **(a)** that the initial Contributor has attached the notice described
+    in Exhibit B to the Covered Software; or
+* **(b)** that the Covered Software was made available under the terms of
+    version 1.1 or earlier of the License, but not also under the
+    terms of a Secondary License.
+
+**1.6. “Executable Form”**
+    means any form of the work other than Source Code Form.
+
+**1.7. “Larger Work”**
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+**1.8. “License”**
+    means this document.
+
+**1.9. “Licensable”**
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+**1.10. “Modifications”**
+    means any of the following:
+
+* **(a)** any file in Source Code Form that results from an addition to,
+    deletion from, or modification of the contents of Covered
+    Software; or
+* **(b)** any new file in Source Code Form that contains any Covered
+    Software.
+
+**1.11. “Patent Claims” of a Contributor**
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+**1.12. “Secondary License”**
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+**1.13. “Source Code Form”**
+    means the form of the work preferred for making modifications.
+
+**1.14. “You” (or “Your”)**
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, “You” includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, “control” means **(a)** the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or **(b)** ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+### 2. License Grants and Conditions
+
+#### 2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+* **(a)** under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+* **(b)** under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+#### 2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+#### 2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+* **(a)** for any code that a Contributor has removed from Covered Software;
+    or
+* **(b)** for infringements caused by: **(i)** Your and any other third party's
+    modifications of Covered Software, or **(ii)** the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+* **(c)** under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+#### 2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+#### 2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+#### 2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+#### 2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+### 3. Responsibilities
+
+#### 3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+#### 3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+* **(a)** such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+* **(b)** You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+#### 3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+#### 3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+#### 3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+### 4. Inability to Comply Due to Statute or Regulation
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: **(a)** comply with
+the terms of this License to the maximum extent possible; and **(b)**
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+### 5. Termination
+
+**5.1.** The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated **(a)** provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and **(b)** on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+**5.2.** If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+### 6. Disclaimer of Warranty
+
+> Covered Software is provided under this License on an “as is”
+> basis, without warranty of any kind, either expressed, implied, or
+> statutory, including, without limitation, warranties that the
+> Covered Software is free of defects, merchantable, fit for a
+> particular purpose or non-infringing. The entire risk as to the
+> quality and performance of the Covered Software is with You.
+> Should any Covered Software prove defective in any respect, You
+> (not any Contributor) assume the cost of any necessary servicing,
+> repair, or correction. This disclaimer of warranty constitutes an
+> essential part of this License. No use of any Covered Software is
+> authorized under this License except under this disclaimer.
+
+### 7. Limitation of Liability
+
+> Under no circumstances and under no legal theory, whether tort
+> (including negligence), contract, or otherwise, shall any
+> Contributor, or anyone who distributes Covered Software as
+> permitted above, be liable to You for any direct, indirect,
+> special, incidental, or consequential damages of any character
+> including, without limitation, damages for lost profits, loss of
+> goodwill, work stoppage, computer failure or malfunction, or any
+> and all other commercial damages or losses, even if such party
+> shall have been informed of the possibility of such damages. This
+> limitation of liability shall not apply to liability for death or
+> personal injury resulting from such party's negligence to the
+> extent applicable law prohibits such limitation. Some
+> jurisdictions do not allow the exclusion or limitation of
+> incidental or consequential damages, so this exclusion and
+> limitation may not apply to You.
+
+### 8. Litigation
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+### 9. Miscellaneous
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+### 10. Versions of the License
+
+#### 10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+#### 10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+#### 10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+## Exhibit A - Source Code Form License Notice
+
+    This Source Code Form is subject to the terms of the Mozilla Public
+    License, v. 2.0. If a copy of the MPL was not distributed with this
+    file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+## Exhibit B - “Incompatible With Secondary Licenses” Notice
+
+    This Source Code Form is "Incompatible With Secondary Licenses", as
+    defined by the Mozilla Public License, v. 2.0.
diff --git a/src/Rust/vvs_parser/README.md b/src/Rust/vvs_parser/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..1bc8ed395a96bb7c11a4c80de3f4beb200107ed6
--- /dev/null
+++ b/src/Rust/vvs_parser/README.md
@@ -0,0 +1,10 @@
+A lossless Lua 5.1 / 5.2 / 5.3 / 5.4 / [Luau](https://luau-lang.org/) parser written in Rust.
+
+Full Moon preserves comments, whitespace, style choices, etc. With Full Moon, you're able to convert
+your Lua code into an AST and a syntax tree and convert it back to the original code exactly.
+
+Using Full Moon, you'll be able to modify the AST directly and re-export it back to Lua, all while
+preserving the style in which you write.
+
+Full Moon is heavily inspired by [LPGhatguy's mab](https://github.com/LPGhatguy/mab/) and by the
+possibilities brought on by [benjamn's recast](https://github.com/benjamn/recast).
diff --git a/src/Rust/vvs_parser/samples/options.ini b/src/Rust/vvs_parser/samples/options.ini
new file mode 100644
index 0000000000000000000000000000000000000000..ef6a2af767f4537555f798537090e17b873112dd
--- /dev/null
+++ b/src/Rust/vvs_parser/samples/options.ini
@@ -0,0 +1,8 @@
+[retime]
+before = 900
+after  = 400
+
+[outline]
+-- Let's say we have an outline module...
+border = 4
+color  = color { "rgb", 0, 0, 0 }
diff --git a/src/Rust/vvs_parser/samples/retime.vvs b/src/Rust/vvs_parser/samples/retime.vvs
new file mode 100644
index 0000000000000000000000000000000000000000..94e930203035803f7960b63c5f6d1dfbab361704
--- /dev/null
+++ b/src/Rust/vvs_parser/samples/retime.vvs
@@ -0,0 +1,29 @@
+---[[ Contains utilities to retime lines from an ASS file. ]]
+
+
+option before : number = 900 --- Retime time in millisecond for the aparition of the line.
+option after  : number = 300 --- Retime time in millisecond for the disaparition of the line.
+
+
+-- We want to permit assertions to check for options, etc. They will be run before the main is
+-- executed, when all the configuration is loaded.
+assert(before >= 0, "offset should be positive")
+assert(after  >= 0, "offset should be positive")
+
+
+--- Here we set the begin of the syllabes at the begin of the line, each
+--- syllabes will end when it should in fact begin.
+job start(l: line): line
+    for i,s in l do
+        s.begin = l.start - self.before
+    end
+end
+
+
+--- Here we set the end of the syllabes at the end of the line, each
+--- syllabes will begin when it should in fact end.
+job finish(l: line): line
+    for i,s in l do
+        s.finish = l.finish - self.after
+    end
+end
diff --git a/src/Rust/vvs_parser/samples/tag.vvs b/src/Rust/vvs_parser/samples/tag.vvs
new file mode 100644
index 0000000000000000000000000000000000000000..cf625d30110c8dd22556f43c9d50231127317b17
--- /dev/null
+++ b/src/Rust/vvs_parser/samples/tag.vvs
@@ -0,0 +1,21 @@
+---[[ Contains utilities to tag some lines/syllages to filter sets of elements. ]]
+
+
+--- Returns only syllabes with the specified displacement.
+job syl_modulo(every: number, disp: number, l: line): line
+    for i,s in l do
+        if (i % every) == disp then
+            yield s
+        end
+    end
+end
+
+
+--- Returns only lines with the specified displacement.
+job line_modulo(every: number, ls: lines): line -- Note that jobs may only returns `line` or `syllabe`
+    for i,l in ls do
+        if (i % every) == disp then
+            yield l
+        end
+    end
+end
diff --git a/src/Rust/vvs_parser/samples/test.vvs b/src/Rust/vvs_parser/samples/test.vvs
new file mode 100644
index 0000000000000000000000000000000000000000..1b482111e7836bdbf498e7e4e4bdf76e966a2f96
--- /dev/null
+++ b/src/Rust/vvs_parser/samples/test.vvs
@@ -0,0 +1,20 @@
+import "utils"
+import { "retime", "tag" }
+
+
+-- Set some options.
+retime.before  = 900
+retime.after   = 400
+outline.border = 4
+outline.color  = color "rgb" { 10, 10, 10 }
+
+
+-- What we want to do for this script, and how we name the initial value.
+main "INIT" do
+    "BEFORE"   = retime.start   { "INIT" }
+    "AFTER"    = retime.finish  { "INIT" }
+    "OUTLINED" = utils.outline  { "BEFORE", "INIT", "AFTER" }
+    "TAGGED"   = tag.syl_modulo { every = 3, disp = 1, "OUTLINED" } -- Here we tag some objects...
+
+    return "OUTLINED" -- What we want to write in the file, in order.
+end
diff --git a/src/Rust/vvs_parser/src/ast/mod.rs b/src/Rust/vvs_parser/src/ast/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5ccfe1e9c22f2e7d8cf108395af195eee7d04b8a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/mod.rs
@@ -0,0 +1,3117 @@
+//! Utilities for ASTs (Abstract Syntax Trees).
+
+use crate::{
+    ast::parsers::ParserState,
+    node::Node,
+    tokenizer::{Position, Symbol, Token, TokenReference, TokenType},
+    util::*,
+    ShortString,
+};
+use crate::{traits::DefaultRef, util::display_option};
+use derive_more::{Deref, Display, IsVariant};
+use serde::{Deserialize, Serialize};
+use std::{borrow::Cow, fmt};
+use vvs_parser_derive::{Node, Visit};
+
+pub use crate::ast::{punctuated::*, span::*};
+
+pub(crate) use crate::ast::{
+    options::OptionTable,
+    parsers::{AstResult, OptionTableResult},
+};
+
+mod options;
+mod parsers;
+mod punctuated;
+mod span;
+mod update_positions;
+mod visitors;
+
+/// A block of statements, such as in if/do/etc block
+#[derive(Clone, Debug, Default, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{}{}",
+    display_optional_punctuated_vec(stmts),
+    display_option(last_stmt.as_ref().map(display_optional_punctuated))
+)]
+pub struct Block {
+    stmts: Vec<(Stmt, Option<TokenReference>)>,
+
+    #[serde(skip_serializing_if = "Option::is_none")]
+    last_stmt: Option<(LastStmt, Option<TokenReference>)>,
+}
+
+impl Block {
+    /// Creates an empty block
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    /// An iterator over the statements in the block, such as `local foo = 1`.
+    ///
+    /// Note that this does not contain the final statement which can be
+    /// attained via [`Block::last_stmt`].
+    pub fn stmts(&self) -> impl Iterator<Item = &Stmt> {
+        self.stmts.iter().map(|(stmt, _)| stmt)
+    }
+
+    /// An iterator over the mutable statements in the block, such as `local foo = 1`.
+    ///
+    /// Note that this does not contain the final statement which can be
+    /// attained via [`Block::last_stmt`].
+    #[allow(dead_code)]
+    pub(crate) fn stmts_mut(&mut self) -> impl Iterator<Item = &mut Stmt> {
+        self.stmts.iter_mut().map(|(stmt, _)| stmt)
+    }
+
+    /// An iterator over the statements in the block, including any optional
+    /// semicolon token reference present
+    pub fn stmts_with_semicolon(&self) -> impl Iterator<Item = &(Stmt, Option<TokenReference>)> {
+        self.stmts.iter()
+    }
+
+    /// The last statement of the block if one exists, such as `return foo`
+    pub fn last_stmt(&self) -> Option<&LastStmt> {
+        Some(&self.last_stmt.as_ref()?.0)
+    }
+
+    /// The mutable last statement of the block if one exists, such as `return foo`
+    pub fn last_stmt_mut(&mut self) -> Option<&mut LastStmt> {
+        Some(&mut self.last_stmt.as_mut()?.0)
+    }
+
+    /// The last statement of the block if on exists, including any optional semicolon token reference present
+    pub fn last_stmt_with_semicolon(&self) -> Option<&(LastStmt, Option<TokenReference>)> {
+        self.last_stmt.as_ref()
+    }
+
+    /// Returns a new block with the given statements
+    /// Takes a vector of statements, followed by an optional semicolon token reference
+    pub fn with_stmts(self, stmts: Vec<(Stmt, Option<TokenReference>)>) -> Self {
+        Self { stmts, ..self }
+    }
+
+    /// Returns a new block with the given last statement, if one is given
+    /// Takes an optional last statement, with an optional semicolon
+    pub fn with_last_stmt(self, last_stmt: Option<(LastStmt, Option<TokenReference>)>) -> Self {
+        Self { last_stmt, ..self }
+    }
+
+    pub(crate) fn merge_blocks(&mut self, other: Self) {
+        self.stmts.extend(other.stmts);
+        self.last_stmt = other.last_stmt;
+    }
+}
+
+/// The last statement of a [`Block`]
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum LastStmt {
+    /// A `break` statement
+    Break(TokenReference),
+
+    /// A continue statement
+    Continue(TokenReference),
+
+    /// A `return` statement
+    Return(Return),
+}
+
+/// A `return` statement
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{token}{returns}")]
+pub struct Return {
+    token: TokenReference,
+    returns: Punctuated<Expression>,
+}
+
+impl Return {
+    /// Creates a new empty Return
+    /// Default return token is followed by a single space
+    pub fn new() -> Self {
+        Self { token: TokenReference::basic_symbol("return "), returns: Punctuated::new() }
+    }
+
+    /// The `return` token
+    pub fn token(&self) -> &TokenReference {
+        &self.token
+    }
+
+    /// The values being returned
+    pub fn returns(&self) -> &Punctuated<Expression> {
+        &self.returns
+    }
+
+    /// Returns a new Return with the given `return` token
+    pub fn with_token(self, token: TokenReference) -> Self {
+        Self { token, ..self }
+    }
+
+    /// Returns a new Return with the given punctuated sequence
+    pub fn with_returns(self, returns: Punctuated<Expression>) -> Self {
+        Self { returns, ..self }
+    }
+}
+
+impl Default for Return {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// Fields of a [`TableConstructor`]
+#[derive(Clone, Debug, Display, PartialEq, Node, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum Field {
+    /// A key in the format of `[expression] = value`
+    #[display("{}{key}{}{equal}{value}", brackets.tokens().0, brackets.tokens().1)]
+    ExpressionKey {
+        /// The `[...]` part of `[expression] = value`
+        brackets: ContainedSpan,
+        /// The `expression` part of `[expression] = value`
+        key: Expression,
+        /// The `=` part of `[expression] = value`
+        equal: TokenReference,
+        /// The `value` part of `[expression] = value`
+        value: Expression,
+    },
+
+    /// A key in the format of `name = value`
+    #[display("{key}{equal}{value}")]
+    NameKey {
+        /// The `name` part of `name = value`
+        key: TokenReference,
+        /// The `=` part of `name = value`
+        equal: TokenReference,
+        /// The `value` part of `name = value`
+        value: Expression,
+    },
+
+    /// A field with no key, just a value (such as `"a"` in `{ "a" }`)
+    #[display("{_0}")]
+    NoKey(Expression),
+}
+
+/// A table being constructed, such as `{ 1, 2, 3 }` or `{ a = 1 }`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{}{fields}{}", braces.tokens().0, braces.tokens().1)]
+pub struct TableConstructor {
+    #[node(full_range)]
+    #[visit(contains = "fields")]
+    braces: ContainedSpan,
+    fields: Punctuated<Field>,
+}
+
+impl TableConstructor {
+    /// Creates a new empty TableConstructor
+    /// Brace tokens are followed by spaces, such that { `fields` }
+    pub fn new() -> Self {
+        Self {
+            braces: ContainedSpan::new(TokenReference::basic_symbol("{ "), TokenReference::basic_symbol(" }")),
+            fields: Punctuated::new(),
+        }
+    }
+
+    /// The braces of the constructor
+    pub fn braces(&self) -> &ContainedSpan {
+        &self.braces
+    }
+
+    /// Returns the [`Punctuated`] sequence of the fields used to create the table
+    pub fn fields(&self) -> &Punctuated<Field> {
+        &self.fields
+    }
+
+    /// Get the number of fields in the table construct
+    pub fn fields_len(&self) -> usize {
+        self.fields().len()
+    }
+
+    /// Returns a new TableConstructor with the given braces
+    pub fn with_braces(self, braces: ContainedSpan) -> Self {
+        Self { braces, ..self }
+    }
+
+    /// Returns a new TableConstructor with the given fields
+    pub fn with_fields(self, fields: Punctuated<Field>) -> Self {
+        Self { fields, ..self }
+    }
+}
+
+impl Default for TableConstructor {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// An expression, mostly useful for getting values
+#[derive(Clone, Debug, Display, PartialEq, Node, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum Expression {
+    /// A binary operation, such as `1 + 3`
+    #[display("{lhs}{binop}{rhs}")]
+    BinaryOperator {
+        /// The left hand side of the binary operation, the `1` part of `1 + 3`
+        lhs: Box<Expression>,
+        /// The binary operation used, the `+` part of `1 + 3`
+        binop: BinOp,
+        /// The right hand side of the binary operation, the `3` part of `1 + 3`
+        rhs: Box<Expression>,
+    },
+
+    /// A statement in parentheses, such as `(#list)`
+    #[display("{}{expression}{}", contained.tokens().0, contained.tokens().1)]
+    Parentheses {
+        /// The parentheses of the expression
+        #[node(full_range)]
+        contained: ContainedSpan,
+        /// The expression inside the parentheses
+        expression: Box<Expression>,
+    },
+
+    /// A unary operation, such as `#list`
+    #[display("{unop}{expression}")]
+    UnaryOperator {
+        /// The unary operation, the `#` part of `#list`
+        unop: UnOp,
+        /// The expression the operation is being done on, the `list` part of `#list`
+        expression: Box<Expression>,
+    },
+
+    /// An anonymous function, such as `function() end)`
+    #[display("{}{}", _0.0, _0.1)]
+    Function(Box<(TokenReference, FunctionBody)>),
+
+    /// A call of a function, such as `call()`
+    #[display("{_0}")]
+    FunctionCall(FunctionCall),
+
+    /// An if expression, such as `if foo then true else false`.
+    #[display("{_0}")]
+    IfExpression(IfExpression),
+
+    /// A table constructor, such as `{ 1, 2, 3 }`
+    #[display("{_0}")]
+    TableConstructor(TableConstructor),
+
+    /// A number token, such as `3.3`
+    #[display("{_0}")]
+    Number(TokenReference),
+
+    /// A string token, such as `"hello"`
+    #[display("{_0}")]
+    String(TokenReference),
+
+    /// A symbol, such as `true`
+    #[display("{_0}")]
+    Symbol(TokenReference),
+
+    /// A value that has been asserted for a particular type, for use in Luau.
+    #[display("{expression}{type_assertion}")]
+    TypeAssertion {
+        /// The expression being asserted
+        expression: Box<Expression>,
+
+        /// The type assertion
+        type_assertion: TypeAssertion,
+    },
+
+    /// A more complex value, such as `call().x`
+    #[display("{_0}")]
+    Var(Var),
+}
+
+/// A statement that stands alone
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum Stmt {
+    /// An assignment, such as `x = 1`
+    #[display("{_0}")]
+    Assignment(Assignment),
+
+    /// A do block, `do end`
+    #[display("{_0}")]
+    Do(Do),
+
+    /// A function call on its own, such as `call()`
+    #[display("{_0}")]
+    FunctionCall(FunctionCall),
+
+    /// A function declaration, such as `function x() end`
+    #[display("{_0}")]
+    FunctionDeclaration(FunctionDeclaration),
+
+    /// A job declaration, such as `job x(l: lines): lines return l end`
+    #[display("{_0}")]
+    JobDeclaration(FunctionDeclaration),
+
+    /// A generic for loop, such as `for index, value in pairs(list) do end`
+    #[display("{_0}")]
+    GenericFor(GenericFor),
+
+    /// An if statement
+    #[display("{_0}")]
+    If(If),
+
+    /// A local assignment, such as `local x = 1`
+    #[display("{_0}")]
+    LocalAssignment(LocalAssignment),
+
+    /// A local function declaration, such as `local function x() end`
+    #[display("{_0}")]
+    LocalFunction(LocalFunction),
+
+    /// An import statement, such as `import "math"`
+    #[display("{_0}")]
+    Import(Import),
+
+    /// A numeric for loop, such as `for index = 1, 10 do end`
+    #[display("{_0}")]
+    NumericFor(NumericFor),
+
+    /// A repeat loop
+    #[display("{_0}")]
+    Repeat(Repeat),
+
+    /// A while loop
+    #[display("{_0}")]
+    While(While),
+
+    /// The `option` directive, to declare an option
+    #[display("{_0}")]
+    OptionDecl(OptionDecl),
+
+    /// The `write` directive, to write variables to the final file.
+    ///
+    /// Can be used like `write "init"` or `write { "init", "last", "etc" }`
+    #[display("{_0}")]
+    Write(Write),
+
+    /// The `main` directive. See [Main] for more informations.
+    #[display("{_0}")]
+    Main(Main),
+
+    /// The `yield` statement for jobs to be able to build automatically things in a job
+    #[display("{_0}")]
+    Yield(Yield),
+
+    /// A compound assignment, such as `+=`
+    #[display("{_0}")]
+    CompoundAssignment(CompoundAssignment),
+
+    /// A type declaration, such as `type Meters = number`
+    TypeDeclaration(TypeDeclaration),
+}
+
+/// A `yield` statement
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{token}{yielded}")]
+pub struct Yield {
+    token: TokenReference,
+    yielded: Punctuated<Expression>,
+}
+
+impl Yield {
+    /// Creates a new empty Yield
+    /// Default yield token is followed by a single space
+    pub fn new() -> Self {
+        Self { token: TokenReference::basic_symbol("yield "), yielded: Punctuated::new() }
+    }
+
+    /// The `yield` token
+    pub fn token(&self) -> &TokenReference {
+        &self.token
+    }
+
+    /// The values being returned
+    pub fn yields(&self) -> &Punctuated<Expression> {
+        &self.yielded
+    }
+
+    /// Returns a new Return with the given `yield` token
+    pub fn with_token(self, token: TokenReference) -> Self {
+        Self { token, ..self }
+    }
+
+    /// Returns a new Yield with the given punctuated sequence
+    pub fn with_yields(self, yielded: Punctuated<Expression>) -> Self {
+        Self { yielded, ..self }
+    }
+}
+
+impl Default for Yield {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// A node used before another in cases such as function calling
+/// The `("foo")` part of `("foo"):upper()`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum Prefix {
+    #[display("{_0}")]
+    /// A complicated expression, such as `("foo")`
+    Expression(Box<Expression>),
+
+    #[display("{_0}")]
+    /// Just a name, such as `foo`
+    Name(TokenReference),
+}
+
+/// The indexing of something, such as `x.y` or `x["y"]`
+/// Values of variants are the keys, such as `"y"`
+#[derive(Clone, Debug, Display, PartialEq, Node, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum Index {
+    /// Indexing in the form of `x["y"]`
+    #[display("{}{expression}{}", brackets.tokens().0, brackets.tokens().1)]
+    Brackets {
+        /// The `[...]` part of `["y"]`
+        brackets: ContainedSpan,
+        /// The `"y"` part of `["y"]`
+        expression: Expression,
+    },
+
+    /// Indexing in the form of `x.y`
+    #[display("{dot}{name}")]
+    Dot {
+        /// The `.` part of `.y`
+        dot: TokenReference,
+        /// The `y` part of `.y`
+        name: TokenReference,
+    },
+}
+
+/// Arguments used for a function
+#[derive(Clone, Debug, Display, PartialEq, Node, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum FunctionArgs {
+    /// Used when a function is called in the form of `call(1, 2, 3)`
+    #[display("{}{arguments}{}", parentheses.tokens().0, parentheses.tokens().1)]
+    Parentheses {
+        /// The `(...) part of (1, 2, 3)`
+        #[node(full_range)]
+        parentheses: ContainedSpan,
+        /// The `1, 2, 3` part of `1, 2, 3`
+        arguments: Punctuated<Expression>,
+    },
+    /// Used when a function is called in the form of `call "foobar"`
+    #[display("{_0}")]
+    String(TokenReference),
+    /// Used when a function is called in the form of `call { 1, 2, 3 }`
+    #[display("{_0}")]
+    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, Display, Node, Deserialize, Serialize)]
+#[display("{for_token}{index_variable}{}{equal_token}{start}{start_end_comma}{end}{}{}{do_token}{block}{end_token}",
+    display_option(self.type_specifier()),
+    display_option(self.end_step_comma()),
+    display_option(self.step()),
+)]
+pub struct NumericFor {
+    for_token: TokenReference,
+    index_variable: TokenReference,
+    equal_token: TokenReference,
+    start: Expression,
+    start_end_comma: TokenReference,
+    end: Expression,
+    end_step_comma: Option<TokenReference>,
+    step: Option<Expression>,
+    do_token: TokenReference,
+    block: Block,
+    end_token: TokenReference,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    type_specifier: Option<TypeSpecifier>,
+}
+
+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::basic_symbol("for "),
+            index_variable,
+            equal_token: TokenReference::basic_symbol(" = "),
+            start,
+            start_end_comma: TokenReference::basic_symbol(", "),
+            end,
+            end_step_comma: None,
+            step: None,
+            do_token: TokenReference::basic_symbol(" do\n"),
+            block: Block::new(),
+            end_token: TokenReference::basic_symbol("\nend"),
+            type_specifier: None,
+        }
+    }
+
+    /// The `for` token
+    pub fn for_token(&self) -> &TokenReference {
+        &self.for_token
+    }
+
+    /// The index identity, `index` in the initial example
+    pub fn index_variable(&self) -> &TokenReference {
+        &self.index_variable
+    }
+
+    /// The `=` token
+    pub fn equal_token(&self) -> &TokenReference {
+        &self.equal_token
+    }
+
+    /// The starting point, `1` in the initial example
+    pub fn start(&self) -> &Expression {
+        &self.start
+    }
+
+    /// The comma in between the starting point and end point
+    /// for _ = 1, 10 do
+    ///          ^
+    pub fn start_end_comma(&self) -> &TokenReference {
+        &self.start_end_comma
+    }
+
+    /// The ending point, `10` in the initial example
+    pub fn end(&self) -> &Expression {
+        &self.end
+    }
+
+    /// The comma in between the ending point and limit, if one exists
+    /// for _ = 0, 10, 2 do
+    ///              ^
+    pub fn end_step_comma(&self) -> Option<&TokenReference> {
+        self.end_step_comma.as_ref()
+    }
+
+    /// The step if one exists, `2` in `for index = 0, 10, 2 do end`
+    pub fn step(&self) -> Option<&Expression> {
+        self.step.as_ref()
+    }
+
+    /// The `do` token
+    pub fn do_token(&self) -> &TokenReference {
+        &self.do_token
+    }
+
+    /// The code inside the for loop
+    pub fn block(&self) -> &Block {
+        &self.block
+    }
+
+    /// The `end` token
+    pub fn end_token(&self) -> &TokenReference {
+        &self.end_token
+    }
+
+    /// The type specifiers of the index variable
+    /// `for i: number = 1, 10 do` returns:
+    /// `Some(TypeSpecifier(number))`
+    pub fn type_specifier(&self) -> Option<&TypeSpecifier> {
+        self.type_specifier.as_ref()
+    }
+
+    /// Returns a new NumericFor with the given for token
+    pub fn with_for_token(self, for_token: TokenReference) -> Self {
+        Self { for_token, ..self }
+    }
+
+    /// Returns a new NumericFor with the given index variable
+    pub fn with_index_variable(self, index_variable: TokenReference) -> Self {
+        Self { index_variable, ..self }
+    }
+
+    /// Returns a new NumericFor with the given `=` token
+    pub fn with_equal_token(self, equal_token: TokenReference) -> Self {
+        Self { equal_token, ..self }
+    }
+
+    /// Returns a new NumericFor with the given start expression
+    pub fn with_start(self, start: Expression) -> Self {
+        Self { start, ..self }
+    }
+
+    /// Returns a new NumericFor with the given comma between the start and end expressions
+    pub fn with_start_end_comma(self, start_end_comma: TokenReference) -> Self {
+        Self { start_end_comma, ..self }
+    }
+
+    /// Returns a new NumericFor with the given end expression
+    pub fn with_end(self, end: Expression) -> Self {
+        Self { end, ..self }
+    }
+
+    /// Returns a new NumericFor with the given comma between the end and the step expressions
+    pub fn with_end_step_comma(self, end_step_comma: Option<TokenReference>) -> Self {
+        Self { end_step_comma, ..self }
+    }
+
+    /// Returns a new NumericFor with the given step expression
+    pub fn with_step(self, step: Option<Expression>) -> Self {
+        Self { step, ..self }
+    }
+
+    /// Returns a new NumericFor with the given `do` token
+    pub fn with_do_token(self, do_token: TokenReference) -> Self {
+        Self { do_token, ..self }
+    }
+
+    /// Returns a new NumericFor with the given block
+    pub fn with_block(self, block: Block) -> Self {
+        Self { block, ..self }
+    }
+
+    /// Returns a new NumericFor with the given `end` token
+    pub fn with_end_token(self, end_token: TokenReference) -> Self {
+        Self { end_token, ..self }
+    }
+
+    /// Returns a new NumericFor with the given type specifiers
+    pub fn with_type_specifier(self, type_specifier: Option<TypeSpecifier>) -> Self {
+        Self { type_specifier, ..self }
+    }
+}
+
+/// A generic for loop, such as `for index, value in pairs(list) do end`
+#[derive(Clone, Debug, PartialEq, Display, Node, Deserialize, Serialize)]
+#[display("{for_token}{}{in_token}{expr_list}{do_token}{block}{end_token}",
+    join_type_specifiers(&self.names, self.type_specifiers()),
+)]
+pub struct GenericFor {
+    for_token: TokenReference,
+    names: Punctuated<TokenReference>,
+    in_token: TokenReference,
+    expr_list: Punctuated<Expression>,
+    do_token: TokenReference,
+    block: Block,
+    end_token: TokenReference,
+    type_specifiers: Vec<Option<TypeSpecifier>>,
+}
+
+impl GenericFor {
+    /// Creates a new GenericFor from the given names and expressions
+    pub fn new(names: Punctuated<TokenReference>, expr_list: Punctuated<Expression>) -> Self {
+        Self {
+            for_token: TokenReference::basic_symbol("for "),
+            names,
+            in_token: TokenReference::basic_symbol(" in "),
+            expr_list,
+            do_token: TokenReference::basic_symbol(" do\n"),
+            block: Block::new(),
+            end_token: TokenReference::basic_symbol("\nend"),
+            type_specifiers: Vec::new(),
+        }
+    }
+
+    /// The `for` token
+    pub fn for_token(&self) -> &TokenReference {
+        &self.for_token
+    }
+
+    /// Returns the punctuated sequence of names
+    /// In `for index, value in pairs(list) do`, iterates over `index` and `value`
+    pub fn names(&self) -> &Punctuated<TokenReference> {
+        &self.names
+    }
+
+    /// The `in` token
+    pub fn in_token(&self) -> &TokenReference {
+        &self.in_token
+    }
+
+    /// Returns the punctuated sequence of the expressions looped over
+    /// In `for index, value in pairs(list) do`, iterates over `pairs(list)`
+    pub fn expressions(&self) -> &Punctuated<Expression> {
+        &self.expr_list
+    }
+
+    /// The `do` token
+    pub fn do_token(&self) -> &TokenReference {
+        &self.do_token
+    }
+
+    /// The code inside the for loop
+    pub fn block(&self) -> &Block {
+        &self.block
+    }
+
+    /// The `end` token
+    pub fn end_token(&self) -> &TokenReference {
+        &self.end_token
+    }
+
+    /// 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))`
+    pub fn type_specifiers(&self) -> impl Iterator<Item = Option<&TypeSpecifier>> {
+        self.type_specifiers.iter().map(Option::as_ref)
+    }
+
+    /// Returns a new GenericFor with the given `for` token
+    pub fn with_for_token(self, for_token: TokenReference) -> Self {
+        Self { for_token, ..self }
+    }
+
+    /// Returns a new GenericFor with the given names
+    pub fn with_names(self, names: Punctuated<TokenReference>) -> Self {
+        Self { names, ..self }
+    }
+
+    /// Returns a new GenericFor with the given `in` token
+    pub fn with_in_token(self, in_token: TokenReference) -> Self {
+        Self { in_token, ..self }
+    }
+
+    /// Returns a new GenericFor with the given expression list
+    pub fn with_expressions(self, expr_list: Punctuated<Expression>) -> Self {
+        Self { expr_list, ..self }
+    }
+
+    /// Returns a new GenericFor with the given `do` token
+    pub fn with_do_token(self, do_token: TokenReference) -> Self {
+        Self { do_token, ..self }
+    }
+
+    /// Returns a new GenericFor with the given block
+    pub fn with_block(self, block: Block) -> Self {
+        Self { block, ..self }
+    }
+
+    /// Returns a new GenericFor with the given `end` token
+    pub fn with_end_token(self, end_token: TokenReference) -> Self {
+        Self { end_token, ..self }
+    }
+
+    /// Returns a new GenericFor with the given type specifiers
+    pub fn with_type_specifiers(self, type_specifiers: Vec<Option<TypeSpecifier>>) -> Self {
+        Self { type_specifiers, ..self }
+    }
+}
+
+/// An if statement
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{if_token}{condition}{then_token}{block}{}{}{}{end_token}",
+    display_option(else_if.as_ref().map(join_vec)),
+    display_option(else_token),
+    display_option(r#else),
+)]
+pub struct If {
+    if_token: TokenReference,
+    condition: Expression,
+    then_token: TokenReference,
+    block: Block,
+    else_if: Option<Vec<ElseIf>>,
+    else_token: Option<TokenReference>,
+
+    #[serde(rename = "else")]
+    r#else: Option<Block>,
+    end_token: TokenReference,
+}
+
+impl If {
+    /// Creates a new If from the given condition
+    pub fn new(condition: Expression) -> Self {
+        Self {
+            if_token: TokenReference::basic_symbol("if "),
+            condition,
+            then_token: TokenReference::basic_symbol(" then"),
+            block: Block::new(),
+            else_if: None,
+            else_token: None,
+            r#else: None,
+            end_token: TokenReference::basic_symbol("\nend"),
+        }
+    }
+
+    /// The `if` token
+    pub fn if_token(&self) -> &TokenReference {
+        &self.if_token
+    }
+
+    /// The condition of the if statement, `condition` in `if condition then`
+    pub fn condition(&self) -> &Expression {
+        &self.condition
+    }
+
+    /// The `then` token
+    pub fn then_token(&self) -> &TokenReference {
+        &self.then_token
+    }
+
+    /// The block inside the initial if statement
+    pub fn block(&self) -> &Block {
+        &self.block
+    }
+
+    /// The `else` token if one exists
+    pub fn else_token(&self) -> Option<&TokenReference> {
+        self.else_token.as_ref()
+    }
+
+    /// If there are `elseif` conditions, returns a vector of them
+    /// Expression is the condition, block is the code if the condition is true
+    // TODO: Make this return an iterator, and remove Option part entirely?
+    pub fn else_if(&self) -> Option<&Vec<ElseIf>> {
+        self.else_if.as_ref()
+    }
+
+    /// The code inside an `else` block if one exists
+    pub fn else_block(&self) -> Option<&Block> {
+        self.r#else.as_ref()
+    }
+
+    /// The `end` token
+    pub fn end_token(&self) -> &TokenReference {
+        &self.end_token
+    }
+
+    /// Returns a new If with the given `if` token
+    pub fn with_if_token(self, if_token: TokenReference) -> Self {
+        Self { if_token, ..self }
+    }
+
+    /// Returns a new If with the given condition
+    pub fn with_condition(self, condition: Expression) -> Self {
+        Self { condition, ..self }
+    }
+
+    /// Returns a new If with the given `then` token
+    pub fn with_then_token(self, then_token: TokenReference) -> Self {
+        Self { then_token, ..self }
+    }
+
+    /// Returns a new If with the given block
+    pub fn with_block(self, block: Block) -> Self {
+        Self { block, ..self }
+    }
+
+    /// Returns a new If with the given list of `elseif` blocks
+    pub fn with_else_if(self, else_if: Option<Vec<ElseIf>>) -> Self {
+        Self { else_if, ..self }
+    }
+
+    /// Returns a new If with the given `else` token
+    pub fn with_else_token(self, else_token: Option<TokenReference>) -> Self {
+        Self { else_token, ..self }
+    }
+
+    /// Returns a new If with the given `else` body
+    pub fn with_else(self, r#else: Option<Block>) -> Self {
+        Self { r#else, ..self }
+    }
+
+    /// Returns a new If with the given `end` token
+    pub fn with_end_token(self, end_token: TokenReference) -> Self {
+        Self { end_token, ..self }
+    }
+}
+
+/// An elseif block in a bigger [`If`] statement
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{else_if_token}{condition}{then_token}{block}")]
+pub struct ElseIf {
+    else_if_token: TokenReference,
+    condition: Expression,
+    then_token: TokenReference,
+    block: Block,
+}
+
+impl ElseIf {
+    /// Creates a new ElseIf from the given condition
+    pub fn new(condition: Expression) -> Self {
+        Self {
+            else_if_token: TokenReference::basic_symbol("elseif "),
+            condition,
+            then_token: TokenReference::basic_symbol(" then\n"),
+            block: Block::new(),
+        }
+    }
+
+    /// The `elseif` token
+    pub fn else_if_token(&self) -> &TokenReference {
+        &self.else_if_token
+    }
+
+    /// The condition of the `elseif`, `condition` in `elseif condition then`
+    pub fn condition(&self) -> &Expression {
+        &self.condition
+    }
+
+    /// The `then` token
+    pub fn then_token(&self) -> &TokenReference {
+        &self.then_token
+    }
+
+    /// The body of the `elseif`
+    pub fn block(&self) -> &Block {
+        &self.block
+    }
+
+    /// Returns a new ElseIf with the given `elseif` token
+    pub fn with_else_if_token(self, else_if_token: TokenReference) -> Self {
+        Self { else_if_token, ..self }
+    }
+
+    /// Returns a new ElseIf with the given condition
+    pub fn with_condition(self, condition: Expression) -> Self {
+        Self { condition, ..self }
+    }
+
+    /// Returns a new ElseIf with the given `then` token
+    pub fn with_then_token(self, then_token: TokenReference) -> Self {
+        Self { then_token, ..self }
+    }
+
+    /// Returns a new ElseIf with the given block
+    pub fn with_block(self, block: Block) -> Self {
+        Self { block, ..self }
+    }
+}
+
+/// A while loop
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{while_token}{condition}{do_token}{block}{end_token}")]
+pub struct While {
+    while_token: TokenReference,
+    condition: Expression,
+    do_token: TokenReference,
+    block: Block,
+    end_token: TokenReference,
+}
+
+impl While {
+    /// Creates a new While from the given condition
+    pub fn new(condition: Expression) -> Self {
+        Self {
+            while_token: TokenReference::basic_symbol("while "),
+            condition,
+            do_token: TokenReference::basic_symbol(" do\n"),
+            block: Block::new(),
+            end_token: TokenReference::basic_symbol("end\n"),
+        }
+    }
+
+    /// The `while` token
+    pub fn while_token(&self) -> &TokenReference {
+        &self.while_token
+    }
+
+    /// The `condition` part of `while condition do`
+    pub fn condition(&self) -> &Expression {
+        &self.condition
+    }
+
+    /// The `do` token
+    pub fn do_token(&self) -> &TokenReference {
+        &self.do_token
+    }
+
+    /// The code inside the while loop
+    pub fn block(&self) -> &Block {
+        &self.block
+    }
+
+    /// The `end` token
+    pub fn end_token(&self) -> &TokenReference {
+        &self.end_token
+    }
+
+    /// Returns a new While with the given `while` token
+    pub fn with_while_token(self, while_token: TokenReference) -> Self {
+        Self { while_token, ..self }
+    }
+
+    /// Returns a new While with the given condition
+    pub fn with_condition(self, condition: Expression) -> Self {
+        Self { condition, ..self }
+    }
+
+    /// Returns a new While with the given `do` token
+    pub fn with_do_token(self, do_token: TokenReference) -> Self {
+        Self { do_token, ..self }
+    }
+
+    /// Returns a new While with the given block
+    pub fn with_block(self, block: Block) -> Self {
+        Self { block, ..self }
+    }
+
+    /// Returns a new While with the given `end` token
+    pub fn with_end_token(self, end_token: TokenReference) -> Self {
+        Self { end_token, ..self }
+    }
+}
+
+/// A repeat loop
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{repeat_token}{block}{until_token}{until}")]
+pub struct Repeat {
+    repeat_token: TokenReference,
+    block: Block,
+    until_token: TokenReference,
+    until: Expression,
+}
+
+impl Repeat {
+    /// Creates a new Repeat from the given expression to repeat until
+    pub fn new(until: Expression) -> Self {
+        Self {
+            repeat_token: TokenReference::basic_symbol("repeat\n"),
+            block: Block::new(),
+            until_token: TokenReference::basic_symbol("\nuntil "),
+            until,
+        }
+    }
+
+    /// The `repeat` token
+    pub fn repeat_token(&self) -> &TokenReference {
+        &self.repeat_token
+    }
+
+    /// The code inside the `repeat` block
+    pub fn block(&self) -> &Block {
+        &self.block
+    }
+
+    /// The `until` token
+    pub fn until_token(&self) -> &TokenReference {
+        &self.until_token
+    }
+
+    /// The condition for the `until` part
+    pub fn until(&self) -> &Expression {
+        &self.until
+    }
+
+    /// Returns a new Repeat with the given `repeat` token
+    pub fn with_repeat_token(self, repeat_token: TokenReference) -> Self {
+        Self { repeat_token, ..self }
+    }
+
+    /// Returns a new Repeat with the given block
+    pub fn with_block(self, block: Block) -> Self {
+        Self { block, ..self }
+    }
+
+    /// Returns a new Repeat with the given `until` token
+    pub fn with_until_token(self, until_token: TokenReference) -> Self {
+        Self { until_token, ..self }
+    }
+
+    /// Returns a new Repeat with the given `until` block
+    pub fn with_until(self, until: Expression) -> Self {
+        Self { until, ..self }
+    }
+}
+
+/// An attribute on a local variable, `<const>` in `local x <const>`
+#[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit, Deserialize, Serialize)]
+#[display("{}{name}{}", brackets.tokens().0, brackets.tokens().1)]
+pub struct Attribute {
+    #[node(full_range)]
+    #[visit(contains = "name")]
+    pub(crate) brackets: ContainedSpan,
+    pub(crate) name: TokenReference,
+}
+
+impl Attribute {
+    /// Creates a new Label with the given name
+    pub fn new(name: TokenReference) -> Self {
+        Self {
+            brackets: ContainedSpan::new(TokenReference::symbol("<").unwrap(), TokenReference::symbol(">").unwrap()),
+            name,
+        }
+    }
+
+    /// The name used for the attribute, the `const` part of `<const>`
+    pub fn name(&self) -> &TokenReference {
+        &self.name
+    }
+
+    /// The angle brackets (`<` and `>`) surrounding the attribute
+    pub fn brackets(&self) -> &ContainedSpan {
+        &self.brackets
+    }
+
+    /// Returns a new Attribute with the given attribute name
+    pub fn with_name(self, name: TokenReference) -> Self {
+        Self { name, ..self }
+    }
+
+    /// Returns a new Attribute with the given angle brackets
+    pub fn with_brackets(self, brackets: ContainedSpan) -> Self {
+        Self { brackets, ..self }
+    }
+}
+
+/// A method call, such as `x:y()`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{colon_token}{name}{args}")]
+pub struct MethodCall {
+    colon_token: TokenReference,
+    name: TokenReference,
+    args: FunctionArgs,
+}
+
+impl MethodCall {
+    /// Returns a new MethodCall from the given name and args
+    pub fn new(name: TokenReference, args: FunctionArgs) -> Self {
+        Self { colon_token: TokenReference::basic_symbol(":"), name, args }
+    }
+
+    /// The `:` in `x:y()`
+    pub fn colon_token(&self) -> &TokenReference {
+        &self.colon_token
+    }
+
+    /// The arguments of a method call, the `x, y, z` part of `method:call(x, y, z)`
+    pub fn args(&self) -> &FunctionArgs {
+        &self.args
+    }
+
+    /// The method being called, the `call` part of `method:call()`
+    pub fn name(&self) -> &TokenReference {
+        &self.name
+    }
+
+    /// Returns a new MethodCall with the given `:` token
+    pub fn with_colon_token(self, colon_token: TokenReference) -> Self {
+        Self { colon_token, ..self }
+    }
+
+    /// Returns a new MethodCall with the given name
+    pub fn with_name(self, name: TokenReference) -> Self {
+        Self { name, ..self }
+    }
+
+    /// Returns a new MethodCall with the given args
+    pub fn with_args(self, args: FunctionArgs) -> Self {
+        Self { args, ..self }
+    }
+}
+
+/// Something being called
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum Call {
+    #[display("{_0}")]
+    /// A function being called directly, such as `x(1)`
+    AnonymousCall(FunctionArgs),
+
+    #[display("{_0}")]
+    /// A method call, such as `x:y()`
+    MethodCall(MethodCall),
+}
+
+/// A function body, everything except `function x` in `function x(a, b, c) call() end`
+#[derive(Clone, Debug, PartialEq, Display, Node, Deserialize, Serialize)]
+#[display("{}{}{}{}{block}{end_token}",
+    parameters_parentheses.tokens().0,
+    join_type_specifiers(parameters, self.type_specifiers()),
+    parameters_parentheses.tokens().1,
+    display_option(return_type.as_ref()),
+)]
+pub struct FunctionBody {
+    parameters_parentheses: ContainedSpan,
+    parameters: Punctuated<Parameter>,
+
+    type_specifiers: Vec<Option<TypeSpecifier>>,
+
+    #[serde(skip_serializing_if = "Option::is_none")]
+    return_type: Option<TypeSpecifier>,
+
+    block: Block,
+    end_token: TokenReference,
+}
+
+impl FunctionBody {
+    /// Returns a new empty FunctionBody
+    pub fn new() -> Self {
+        Self {
+            parameters_parentheses: ContainedSpan::new(
+                TokenReference::basic_symbol("("),
+                TokenReference::basic_symbol(")"),
+            ),
+            parameters: Punctuated::new(),
+            type_specifiers: Vec::new(),
+            return_type: None,
+            block: Block::new(),
+            end_token: TokenReference::basic_symbol("\nend"),
+        }
+    }
+
+    /// The parentheses of the parameters
+    pub fn parameters_parentheses(&self) -> &ContainedSpan {
+        &self.parameters_parentheses
+    }
+
+    /// Returns the [`Punctuated`] sequence of the parameters for the function declaration
+    pub fn parameters(&self) -> &Punctuated<Parameter> {
+        &self.parameters
+    }
+
+    /// The code of a function body
+    pub fn block(&self) -> &Block {
+        &self.block
+    }
+
+    /// The mutable code of a function body
+    pub fn block_mut(&mut self) -> &mut Block {
+        &mut self.block
+    }
+
+    /// The `end` token
+    pub fn end_token(&self) -> &TokenReference {
+        &self.end_token
+    }
+
+    /// 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))`
+    pub fn type_specifiers(&self) -> impl Iterator<Item = Option<&TypeSpecifier>> {
+        self.type_specifiers.iter().map(Option::as_ref)
+    }
+
+    /// The return type of the function, if one exists.
+    pub fn return_type(&self) -> Option<&TypeSpecifier> {
+        self.return_type.as_ref()
+    }
+
+    /// Returns a new FunctionBody with the given parentheses for the parameters
+    pub fn with_parameters_parentheses(self, parameters_parentheses: ContainedSpan) -> Self {
+        Self { parameters_parentheses, ..self }
+    }
+
+    /// Returns a new FunctionBody with the given parameters
+    pub fn with_parameters(self, parameters: Punctuated<Parameter>) -> Self {
+        Self { parameters, ..self }
+    }
+
+    /// Returns a new FunctionBody with the given type specifiers
+    pub fn with_type_specifiers(self, type_specifiers: Vec<Option<TypeSpecifier>>) -> Self {
+        Self { type_specifiers, ..self }
+    }
+
+    /// Returns a new FunctionBody with the given return type
+    pub fn with_return_type(self, return_type: Option<TypeSpecifier>) -> Self {
+        Self { return_type, ..self }
+    }
+
+    /// Returns a new FunctionBody with the given block
+    pub fn with_block(self, block: Block) -> Self {
+        Self { block, ..self }
+    }
+
+    /// Returns a new FunctionBody with the given `end` token
+    pub fn with_end_token(self, end_token: TokenReference) -> Self {
+        Self { end_token, ..self }
+    }
+}
+
+impl Default for FunctionBody {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// A name parameter in a function declaration, such as `function x(a, b, c)`
+#[derive(Clone, Debug, Display, Deref, PartialEq, Eq, Node, Visit, Deserialize, Serialize)]
+#[display("{name}")]
+pub struct Parameter {
+    name: TokenReference,
+}
+
+/// A suffix in certain cases, such as `:y()` in `x:y()`
+/// Can be stacked on top of each other, such as in `x()()()`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum Suffix {
+    #[display("{_0}")]
+    /// A call, including method calls and direct calls
+    Call(Call),
+
+    #[display("{_0}")]
+    /// An index, such as `x.y`
+    Index(Index),
+}
+
+/// A complex expression used by [`Var`], consisting of both a prefix and suffixes
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{prefix}{}", join_vec(suffixes))]
+pub struct VarExpression {
+    prefix: Prefix,
+    suffixes: Vec<Suffix>,
+}
+
+impl VarExpression {
+    /// Returns a new VarExpression from the given prefix
+    pub fn new(prefix: Prefix) -> Self {
+        Self { prefix, suffixes: Vec::new() }
+    }
+
+    /// The prefix of the expression, such as a name
+    pub fn prefix(&self) -> &Prefix {
+        &self.prefix
+    }
+
+    /// An iter over the suffixes, such as indexing or calling
+    pub fn suffixes(&self) -> impl Iterator<Item = &Suffix> {
+        self.suffixes.iter()
+    }
+
+    /// Returns a new VarExpression with the given prefix
+    pub fn with_prefix(self, prefix: Prefix) -> Self {
+        Self { prefix, ..self }
+    }
+
+    /// Returns a new VarExpression with the given suffixes
+    pub fn with_suffixes(self, suffixes: Vec<Suffix>) -> Self {
+        Self { suffixes, ..self }
+    }
+}
+
+/// Used in [`Assignment`s](Assignment) and [`Value`s](Value)
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum Var {
+    /// An expression, such as `x.y.z` or `x()`
+    #[display("{_0}")]
+    Expression(Box<VarExpression>),
+
+    /// A literal identifier, such as `x`
+    #[display("{_0}")]
+    Name(TokenReference),
+}
+
+/// An assignment, such as `x = y`. Not used for [`LocalAssignment`s](LocalAssignment)
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{var_list}{equal_token}{expr_list}")]
+pub struct Assignment {
+    var_list: Punctuated<Var>,
+    equal_token: TokenReference,
+    expr_list: Punctuated<Expression>,
+}
+
+impl Assignment {
+    /// Returns a new Assignment from the given variable and expression list
+    pub fn new(var_list: Punctuated<Var>, expr_list: Punctuated<Expression>) -> Self {
+        Self { var_list, equal_token: TokenReference::basic_symbol(" = "), expr_list }
+    }
+
+    /// Returns the punctuated sequence over the expressions being assigned.
+    /// This is the the `1, 2` part of `x, y["a"] = 1, 2`
+    pub fn expressions(&self) -> &Punctuated<Expression> {
+        &self.expr_list
+    }
+
+    /// The `=` token in between `x = y`
+    pub fn equal_token(&self) -> &TokenReference {
+        &self.equal_token
+    }
+
+    /// Returns the punctuated sequence over the variables being assigned to.
+    /// This is the `x, y["a"]` part of `x, y["a"] = 1, 2`
+    pub fn variables(&self) -> &Punctuated<Var> {
+        &self.var_list
+    }
+
+    /// Returns a new Assignment with the given variables
+    pub fn with_variables(self, var_list: Punctuated<Var>) -> Self {
+        Self { var_list, ..self }
+    }
+
+    /// Returns a new Assignment with the given `=` token
+    pub fn with_equal_token(self, equal_token: TokenReference) -> Self {
+        Self { equal_token, ..self }
+    }
+
+    /// Returns a new Assignment with the given expressions
+    pub fn with_expressions(self, expr_list: Punctuated<Expression>) -> Self {
+        Self { expr_list, ..self }
+    }
+}
+
+/// An import directive, such as `import "math"`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{import_token}{name}")]
+pub struct Import {
+    import_token: TokenReference,
+    name: TokenReference,
+}
+
+impl Import {
+    /// Returns a new LocalFunction from the given name
+    pub fn new(name: TokenReference) -> Self {
+        Import { import_token: TokenReference::basic_symbol("import "), name }
+    }
+
+    /// The `import` token
+    pub fn import_token(&self) -> &TokenReference {
+        &self.import_token
+    }
+
+    /// The name of the module to import, the `x` part of `import "x"`
+    pub fn name(&self) -> &TokenReference {
+        &self.name
+    }
+
+    /// Returns a new Import with the given `import` token
+    pub fn with_import_token(self, import_token: TokenReference) -> Self {
+        Self { import_token, ..self }
+    }
+
+    /// Returns a new Import with the given name
+    pub fn with_name(self, name: TokenReference) -> Self {
+        Self { name, ..self }
+    }
+}
+
+/// A declaration of a local function, such as `local function x() end`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{local_token}{function_token}{name}{body}")]
+pub struct LocalFunction {
+    local_token: TokenReference,
+    function_token: TokenReference,
+    name: TokenReference,
+    body: FunctionBody,
+}
+
+impl LocalFunction {
+    /// Returns a new LocalFunction from the given name
+    pub fn new(name: TokenReference) -> Self {
+        LocalFunction {
+            local_token: TokenReference::basic_symbol("local "),
+            function_token: TokenReference::basic_symbol("function "),
+            name,
+            body: FunctionBody::new(),
+        }
+    }
+
+    /// The `local` token
+    pub fn local_token(&self) -> &TokenReference {
+        &self.local_token
+    }
+
+    /// The `function` token
+    pub fn function_token(&self) -> &TokenReference {
+        &self.function_token
+    }
+
+    /// The function body, everything except `local function x` in `local function x(a, b, c) call() end`
+    pub fn body(&self) -> &FunctionBody {
+        &self.body
+    }
+
+    /// The name of the function, the `x` part of `local function x() end`
+    pub fn name(&self) -> &TokenReference {
+        &self.name
+    }
+
+    /// Returns a new LocalFunction with the given `local` token
+    pub fn with_local_token(self, local_token: TokenReference) -> Self {
+        Self { local_token, ..self }
+    }
+
+    /// Returns a new LocalFunction with the given `function` token
+    pub fn with_function_token(self, function_token: TokenReference) -> Self {
+        Self { function_token, ..self }
+    }
+
+    /// Returns a new LocalFunction with the given name
+    pub fn with_name(self, name: TokenReference) -> Self {
+        Self { name, ..self }
+    }
+
+    /// Returns a new LocalFunction with the given function body
+    pub fn with_body(self, body: FunctionBody) -> Self {
+        Self { body, ..self }
+    }
+}
+
+/// An assignment to a local variable, such as `local x = 1`
+#[derive(Clone, Debug, PartialEq, Display, Node, Deserialize, Serialize)]
+#[display("{local_token}{}{}{expr_list}",
+    join_iterators(name_list,
+        self.attributes().chain(std::iter::repeat(None)),
+        self.type_specifiers().chain(std::iter::repeat(None))
+    ),
+    display_option(equal_token),
+)]
+pub struct LocalAssignment {
+    local_token: TokenReference,
+
+    #[serde(skip_serializing_if = "empty_optional_vector")]
+    type_specifiers: Vec<Option<TypeSpecifier>>,
+    name_list: Punctuated<TokenReference>,
+
+    #[serde(skip_serializing_if = "empty_optional_vector")]
+    attributes: Vec<Option<Attribute>>,
+    equal_token: Option<TokenReference>,
+    expr_list: Punctuated<Expression>,
+}
+
+impl LocalAssignment {
+    /// Returns a new LocalAssignment from the given name list
+    pub fn new(name_list: Punctuated<TokenReference>) -> Self {
+        Self {
+            local_token: TokenReference::basic_symbol("local "),
+            type_specifiers: Vec::new(),
+            name_list,
+            attributes: Vec::new(),
+            equal_token: None,
+            expr_list: Punctuated::new(),
+        }
+    }
+
+    /// The `local` token
+    pub fn local_token(&self) -> &TokenReference {
+        &self.local_token
+    }
+
+    /// The `=` token in between `local x = y`, if one exists
+    pub fn equal_token(&self) -> Option<&TokenReference> {
+        self.equal_token.as_ref()
+    }
+
+    /// Returns the punctuated sequence of the expressions being assigned.
+    /// This is the `1, 2` part of `local x, y = 1, 2`
+    pub fn expressions(&self) -> &Punctuated<Expression> {
+        &self.expr_list
+    }
+
+    /// Returns the punctuated sequence of names being assigned to.
+    /// This is the `x, y` part of `local x, y = 1, 2`
+    pub fn names(&self) -> &Punctuated<TokenReference> {
+        &self.name_list
+    }
+
+    /// 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))`
+    pub fn type_specifiers(&self) -> impl Iterator<Item = Option<&TypeSpecifier>> {
+        self.type_specifiers.iter().map(Option::as_ref)
+    }
+
+    /// The attributes specified for the variables, in the order that they were assigned.
+    /// `local foo <const>, bar, baz <close>` returns an iterator containing:
+    /// `Some(Attribute("const")), None, Some(Attribute("close"))`
+    pub fn attributes(&self) -> impl Iterator<Item = Option<&Attribute>> {
+        self.attributes.iter().map(Option::as_ref)
+    }
+
+    /// Returns a new LocalAssignment with the given `local` token
+    pub fn with_local_token(self, local_token: TokenReference) -> Self {
+        Self { local_token, ..self }
+    }
+
+    /// Returns a new LocalAssignment with the given type specifiers
+    pub fn with_type_specifiers(self, type_specifiers: Vec<Option<TypeSpecifier>>) -> Self {
+        Self { type_specifiers, ..self }
+    }
+
+    /// Returns a new LocalAssignment with the given attributes
+    pub fn with_attributes(self, attributes: Vec<Option<Attribute>>) -> Self {
+        Self { attributes, ..self }
+    }
+
+    /// Returns a new LocalAssignment with the given name list
+    pub fn with_names(self, name_list: Punctuated<TokenReference>) -> Self {
+        Self { name_list, ..self }
+    }
+
+    /// Returns a new LocalAssignment with the given `=` token
+    pub fn with_equal_token(self, equal_token: Option<TokenReference>) -> Self {
+        Self { equal_token, ..self }
+    }
+
+    /// Returns a new LocalAssignment with the given expression list
+    pub fn with_expressions(self, expr_list: Punctuated<Expression>) -> Self {
+        Self { expr_list, ..self }
+    }
+}
+
+/// A `do` block, such as `do ... end`
+/// This is not used for things like `while true do end`, only those on their own
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{do_token}{block}{end_token}")]
+pub struct Do {
+    do_token: TokenReference,
+    block: Block,
+    end_token: TokenReference,
+}
+
+impl Do {
+    /// Creates an empty Do
+    pub fn new() -> Self {
+        Self {
+            do_token: TokenReference::basic_symbol("do\n"),
+            block: Block::new(),
+            end_token: TokenReference::basic_symbol("\nend"),
+        }
+    }
+
+    /// The `do` token
+    pub fn do_token(&self) -> &TokenReference {
+        &self.do_token
+    }
+
+    /// The code inside the `do ... end`
+    pub fn block(&self) -> &Block {
+        &self.block
+    }
+
+    /// The `end` token
+    pub fn end_token(&self) -> &TokenReference {
+        &self.end_token
+    }
+
+    /// Returns a new Do with the given `do` token
+    pub fn with_do_token(self, do_token: TokenReference) -> Self {
+        Self { do_token, ..self }
+    }
+
+    /// Returns a new Do with the given block
+    pub fn with_block(self, block: Block) -> Self {
+        Self { block, ..self }
+    }
+
+    /// Returns a new Do with the given `end` token
+    pub fn with_end_token(self, end_token: TokenReference) -> Self {
+        Self { end_token, ..self }
+    }
+}
+
+impl Default for Do {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+/// A function being called, such as `call()`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{prefix}{}", join_vec(suffixes))]
+pub struct FunctionCall {
+    prefix: Prefix,
+    suffixes: Vec<Suffix>,
+}
+
+impl FunctionCall {
+    /// Creates a new FunctionCall from the given prefix
+    /// Sets the suffixes such that the return is `prefixes()`
+    pub fn new(prefix: Prefix) -> Self {
+        FunctionCall {
+            prefix,
+            suffixes: vec![Suffix::Call(Call::AnonymousCall(FunctionArgs::Parentheses {
+                arguments: Punctuated::new(),
+                parentheses: ContainedSpan::new(TokenReference::basic_symbol("("), TokenReference::basic_symbol(")")),
+            }))],
+        }
+    }
+
+    /// The prefix of a function call, the `call` part of `call()`
+    pub fn prefix(&self) -> &Prefix {
+        &self.prefix
+    }
+
+    /// The suffix of a function call, the `()` part of `call()`
+    pub fn suffixes(&self) -> impl Iterator<Item = &Suffix> {
+        self.suffixes.iter()
+    }
+
+    /// Returns a new FunctionCall with the given prefix
+    pub fn with_prefix(self, prefix: Prefix) -> Self {
+        Self { prefix, ..self }
+    }
+
+    /// Returns a new FunctionCall with the given suffixes
+    pub fn with_suffixes(self, suffixes: Vec<Suffix>) -> Self {
+        Self { suffixes, ..self }
+    }
+}
+
+/// A function name when being declared as [`FunctionDeclaration`]
+#[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit, Deserialize, Serialize)]
+#[display("{names}{}{}",
+    display_option(self.method_colon()),
+    display_option(self.method_name())
+)]
+pub struct FunctionName {
+    names: Punctuated<TokenReference>,
+    colon_name: Option<(TokenReference, TokenReference)>,
+}
+
+impl FunctionName {
+    /// Creates a new FunctionName from the given list of names
+    pub fn new(names: Punctuated<TokenReference>) -> Self {
+        Self { names, colon_name: None }
+    }
+
+    /// The colon between the name and the method, the `:` part of `function x:y() end`
+    pub fn method_colon(&self) -> Option<&TokenReference> {
+        Some(&self.colon_name.as_ref()?.0)
+    }
+
+    /// A method name if one exists, the `y` part of `function x:y() end`
+    pub fn method_name(&self) -> Option<&TokenReference> {
+        Some(&self.colon_name.as_ref()?.1)
+    }
+
+    /// Returns the punctuated sequence over the names used when defining the function.
+    /// This is the `x.y.z` part of `function x.y.z() end`
+    pub fn names(&self) -> &Punctuated<TokenReference> {
+        &self.names
+    }
+
+    /// Returns a new FunctionName with the given names
+    pub fn with_names(self, names: Punctuated<TokenReference>) -> Self {
+        Self { names, ..self }
+    }
+
+    /// Returns a new FunctionName with the given method name
+    /// The first token is the colon, and the second token is the method name itself
+    pub fn with_method(self, method: Option<(TokenReference, TokenReference)>) -> Self {
+        Self { colon_name: method, ..self }
+    }
+}
+
+/// A normal function declaration, supports simple declarations like `function x() end`
+/// as well as complicated declarations such as `function x.y.z:a() end`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{function_token}{name}{body}")]
+pub struct FunctionDeclaration {
+    function_token: TokenReference,
+    name: FunctionName,
+    body: FunctionBody,
+}
+
+impl FunctionDeclaration {
+    /// Creates a new FunctionDeclaration from the given name
+    pub fn new(name: FunctionName) -> Self {
+        Self { function_token: TokenReference::basic_symbol("function "), name, body: FunctionBody::new() }
+    }
+
+    /// The `function` token
+    pub fn function_token(&self) -> &TokenReference {
+        &self.function_token
+    }
+
+    /// The body of the function
+    pub fn body(&self) -> &FunctionBody {
+        &self.body
+    }
+
+    /// The name of the function
+    pub fn name(&self) -> &FunctionName {
+        &self.name
+    }
+
+    /// Returns a new FunctionDeclaration with the given `function` token
+    pub fn with_function_token(self, function_token: TokenReference) -> Self {
+        Self { function_token, ..self }
+    }
+
+    /// Returns a new FunctionDeclaration with the given function name
+    pub fn with_name(self, name: FunctionName) -> Self {
+        Self { name, ..self }
+    }
+
+    /// Returns a new FunctionDeclaration with the given function body
+    pub fn with_body(self, body: FunctionBody) -> Self {
+        Self { body, ..self }
+    }
+}
+
+/// An option declaration, such as `option x : number = 1`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{option_token}{}{equal_token}{expr_list}",
+    join_type_specifiers(&self.name_list, self.type_specifiers())
+)]
+pub struct OptionDecl {
+    option_token: TokenReference,
+
+    name_list: Punctuated<TokenReference>,
+
+    #[serde(skip_serializing_if = "empty_optional_vector")]
+    type_specifiers: Vec<Option<TypeSpecifier>>,
+
+    equal_token: TokenReference,
+    expr_list: Punctuated<Expression>,
+}
+
+impl OptionDecl {
+    /// Get the declarations of this option declaration statement.
+    pub fn declarations(&self) -> impl Iterator<Item = (&TokenReference, Option<&TypeSpecifier>, &Expression)> {
+        self.name_list
+            .iter()
+            .zip(&self.type_specifiers)
+            .zip(&self.expr_list)
+            .map(|((name, type_specifier), expression)| (name, type_specifier.as_ref(), expression))
+    }
+}
+
+/// A call list item. We need a call list to know how to a job from the...
+#[derive(Clone, Debug, PartialEq, Display, Node, Visit, Deserialize, Serialize)]
+pub enum CallListItem {
+    /// A reference to a variable, e.g. `"init"`
+    #[display("{_0}")]
+    Variable(TokenReference),
+
+    /// Setting of a parameter for the job, e.g. `pre_line = 900`
+    #[display("{parameter}{equal_token}{expression}")]
+    SetParameter {
+        /// The name of the parameter to set for a given job, must be an argument of said job
+        parameter: TokenReference,
+
+        /// The `=` token of the assignation
+        equal_token: TokenReference,
+
+        /// The value to set for the given parameter in the given job.
+        expression: Expression,
+    },
+}
+
+impl CallListItem {
+    /// Returns the last token, for any variant of this enum.
+    pub fn first_token(&self) -> &TokenReference {
+        match self {
+            CallListItem::SetParameter { parameter: first, .. } | CallListItem::Variable(first) => first,
+        }
+    }
+}
+
+/// The call list for a job, e.g. `{ param = 1, "init" }`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize, Default)]
+#[display("{}{items}{}", display_option(begin_token), display_option(end_token))]
+pub struct CallList {
+    begin_token: Option<TokenReference>,
+    items: Punctuated<CallListItem>,
+    end_token: Option<TokenReference>,
+}
+
+impl CallList {
+    /// Create a new empty call list
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// Set the `{` token for the call list
+    pub fn with_begin_token(self, begin_token: Option<TokenReference>) -> Self {
+        Self { begin_token, ..self }
+    }
+
+    /// Set the `}` token for the call list
+    pub fn with_end_token(self, end_token: Option<TokenReference>) -> Self {
+        Self { end_token, ..self }
+    }
+
+    /// Set the items in this list
+    pub fn with_items(self, items: Punctuated<CallListItem>) -> Self {
+        Self { items, ..self }
+    }
+
+    /// Get the items out of the call list.
+    pub fn items(&self) -> &Punctuated<CallListItem> {
+        &self.items
+    }
+}
+
+/// The main assignement statement, only inside the `main` statement.
+///
+/// ```vivy
+/// "OUTLINED" = utils:outline { "BEFORE", "INIT", "AFTER" }
+/// "TAGGED"   = tag:syl_modulo { every = 3, disp = 1, "OUTLINED" }
+/// ```
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{variable}{assign_token}{module_name}{dot_token}{job_name}{call_list}")]
+pub struct MainAssignement {
+    variable: TokenReference,
+    assign_token: TokenReference,
+
+    module_name: TokenReference,
+    dot_token: TokenReference,
+    job_name: TokenReference,
+
+    call_list: CallList,
+}
+
+impl MainAssignement {
+    /// Create a new assign statement, only inside the `main` statement.
+    pub fn new(
+        assign_token: TokenReference,
+        variable: TokenReference,
+        module_name: TokenReference,
+        dot_token: TokenReference,
+        job_name: TokenReference,
+    ) -> Self {
+        Self { assign_token, variable, module_name, dot_token, job_name, call_list: Default::default() }
+    }
+
+    /// Set the call-list for this invocation of a job.
+    pub fn with_call_list(self, call_list: CallList) -> Self {
+        Self { call_list, ..self }
+    }
+
+    /// Get the called job out of the assignation
+    pub fn called_job(&self) -> (&TokenReference, &TokenReference) {
+        (&self.module_name, &self.job_name)
+    }
+
+    /// Get the called job out of the assignation as identifiers, otherwise panic. If the program
+    /// is correct and the parser is Ok, this should never panic
+    pub fn called_job_identifiers(&self) -> (&ShortString, &ShortString) {
+        let (module, job) = self.called_job();
+        match (module.token_type(), job.token_type()) {
+            (TokenType::Identifier { identifier: m }, TokenType::Identifier { identifier: j }) => (m, j),
+            _ => unreachable!("module and job names should be identifiers"),
+        }
+    }
+
+    /// Get the call list to know how to call the job.
+    pub fn call_list(&self) -> &CallList {
+        &self.call_list
+    }
+
+    /// Get the items of the call list to know how to call the job.
+    pub fn call_list_items(&self) -> impl Iterator<Item = &CallListItem> {
+        self.call_list.items().into_iter()
+    }
+
+    /// Get the name of the written variable
+    pub fn destination(&self) -> &TokenReference {
+        &self.variable
+    }
+}
+
+/// The main statement: `main "INIT" { ... }`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display(
+    "{main_token}{initial_variable}{begin_token}{}{}{end_token}",
+    join_vec(assignements),
+    display_option(write_stmt)
+)]
+pub struct Main {
+    main_token: TokenReference,
+    initial_variable: TokenReference,
+    begin_token: TokenReference,
+    assignements: Vec<MainAssignement>,
+    write_stmt: Option<Write>,
+    end_token: TokenReference,
+}
+
+impl Main {
+    /// Create a new empty main statement.
+    pub fn new(
+        main_token: TokenReference,
+        initial_variable: TokenReference,
+        begin_token: TokenReference,
+        end_token: TokenReference,
+    ) -> Self {
+        Self { main_token, begin_token, end_token, initial_variable, assignements: Vec::new(), write_stmt: None }
+    }
+
+    /// Get the `main` token.
+    pub fn main_token(&self) -> &TokenReference {
+        &self.main_token
+    }
+
+    /// Get the `do` token in `main do ... end`.
+    pub fn begin_list_token(&self) -> &TokenReference {
+        &self.begin_token
+    }
+
+    /// Get the `end` token in `main do ... end`.
+    pub fn end_list_token(&self) -> &TokenReference {
+        &self.end_token
+    }
+
+    /// Set the `return` variables to write, the token here
+    pub fn with_returns(self, write_stmt: Option<Write>) -> Self {
+        Self { write_stmt, ..self }
+    }
+
+    /// Set the assignements for the 'main' statement.
+    pub fn with_assignements(self, assignements: Vec<MainAssignement>) -> Self {
+        Self { assignements, ..self }
+    }
+
+    /// Get the assignations, i.e. the compute steps
+    pub fn assignements(&self) -> &[MainAssignement] {
+        &self.assignements
+    }
+
+    /// Get the written variables
+    pub fn returns(&self) -> Option<&Write> {
+        self.write_stmt.as_ref()
+    }
+
+    /// Get the name of the initial variable
+    pub fn initial_variable(&self) -> &TokenReference {
+        &self.initial_variable
+    }
+}
+
+/// The write directive, with the variables to write into the final file: `write "INIT"`.
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{write_token}{}{variable_list}{}",
+    display_option(self.begin_list_token()),
+    display_option(self.end_list_token())
+)]
+pub struct Write {
+    write_token: TokenReference,
+    begin_token: Option<TokenReference>,
+    variable_list: Punctuated<TokenReference>,
+    end_token: Option<TokenReference>,
+}
+
+impl Write {
+    /// Create a new empty write statement.
+    pub fn new(write_token: TokenReference) -> Self {
+        Self { write_token, begin_token: None, variable_list: Punctuated::new(), end_token: None }
+    }
+
+    /// Get the `write` token for this statement.
+    pub fn write_token(&self) -> &TokenReference {
+        &self.write_token
+    }
+
+    /// Get the list of variables to write
+    pub fn variables(&self) -> &Punctuated<TokenReference> {
+        &self.variable_list
+    }
+
+    /// Get the '{' token if present in the write statement.
+    pub fn begin_list_token(&self) -> Option<&TokenReference> {
+        self.begin_token.as_ref()
+    }
+
+    /// Get the '}' token if present in the write statement.
+    pub fn end_list_token(&self) -> Option<&TokenReference> {
+        self.end_token.as_ref()
+    }
+
+    /// Set the `}` token.
+    pub fn with_end_list_token(self, end_token: Option<TokenReference>) -> Self {
+        Self { end_token, ..self }
+    }
+
+    /// Set the `{` token.
+    pub fn with_begin_list_token(self, begin_token: Option<TokenReference>) -> Self {
+        Self { begin_token, ..self }
+    }
+
+    /// Set the list of variables to write.
+    pub fn with_variables(self, variable_list: Punctuated<TokenReference>) -> Self {
+        Self { variable_list, ..self }
+    }
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! make_bin_op {
+    ($(#[$outer:meta])* { $(
+        $operator:ident = $precedence:expr,
+    )+ }) => {
+        paste::paste! {
+            #[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit, Deserialize, Serialize)]
+            #[non_exhaustive]
+            $(#[$outer])*
+            pub enum BinOp {
+                $(#[display("{_0}")] #[allow(missing_docs)] $operator(TokenReference),)+
+            }
+
+            impl BinOp {
+                /// The precedence of non-unary operator. The larger the number, the higher the precedence.
+                /// Shares the same precedence table as unary operators.
+                pub fn precedence_of_token(token: &TokenReference) -> Option<u8> {
+                    match token.token_type() {
+                        TokenType::Symbol { symbol } => match symbol {
+                            $(Symbol::$operator => Some($precedence),)+ _ => None,
+                        },
+                        _ => None
+                    }
+                }
+
+                /// The token associated with this operator
+                pub fn token(&self) -> &TokenReference {
+                    match self {
+                        $(BinOp::$operator(token) => token,)+
+                    }
+                }
+
+                pub(crate) fn consume(state: &mut ParserState) -> Option<Self> {
+                    match state.current().unwrap().token_type() {
+                        TokenType::Symbol { symbol } => match symbol {
+                            $(Symbol::$operator => { 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)]
+    {
+        Caret = 12,
+
+        // At the 11° position we have the unary operations.
+
+        Percent = 10,
+        Slash = 10,
+        Star = 10,
+        DoubleSlash = 10,
+
+        Minus = 9,
+        Plus = 9,
+
+        TwoDots = 8,
+
+        DoubleGreaterThan = 7,
+        DoubleLesserThan = 7,
+
+        Ampersand = 6,
+
+        Tilde = 5,
+
+        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. The larger the number, the higher the precedence.
+    /// See more at <http://www.lua.org/manual/5.1/manual.html#2.5.6>
+    pub fn precedence(&self) -> u8 {
+        BinOp::precedence_of_token(self.token()).expect("invalid token")
+    }
+
+    /// Whether the operator is right associative. If not, it is left associative.
+    /// See more at <https://www.lua.org/pil/3.5.html>
+    pub fn is_right_associative(&self) -> bool {
+        matches!(*self, BinOp::Caret(_) | BinOp::TwoDots(_))
+    }
+
+    /// 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 }
+        )
+    }
+}
+
+/// Operators that require just one operand, such as #X
+#[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit, Deserialize, Serialize)]
+#[allow(missing_docs)]
+#[non_exhaustive]
+pub enum UnOp {
+    Minus(TokenReference),
+    Not(TokenReference),
+    Hash(TokenReference),
+    Tilde(TokenReference),
+}
+
+impl UnOp {
+    /// The token associated with the operator
+    pub fn token(&self) -> &TokenReference {
+        match self {
+            UnOp::Minus(token) | UnOp::Not(token) | UnOp::Hash(token) => token,
+            UnOp::Tilde(token) => token,
+        }
+    }
+
+    /// The precedence of unary operator. The larger the number, the higher the precedence.
+    /// Shares the same precedence table as binary operators.
+    pub fn precedence() -> u8 {
+        11
+    }
+}
+
+impl OptionDecl {
+    /// Returns a new OptionSet from the given name list
+    pub fn new(name_list: Punctuated<TokenReference>) -> Self {
+        Self {
+            option_token: TokenReference::basic_symbol("option "),
+            type_specifiers: Vec::new(),
+            name_list,
+            equal_token: TokenReference::basic_symbol("= "),
+            expr_list: Punctuated::new(),
+        }
+    }
+
+    /// Get the `option` token
+    pub fn option_token(&self) -> &TokenReference {
+        &self.option_token
+    }
+
+    /// Get the `=` token
+    pub fn equal_token(&self) -> &TokenReference {
+        &self.equal_token
+    }
+
+    /// Get the expressions
+    pub fn expressions(&self) -> &Punctuated<Expression> {
+        &self.expr_list
+    }
+
+    /// Get the names of the options to set
+    pub fn names(&self) -> &Punctuated<TokenReference> {
+        &self.name_list
+    }
+
+    /// Get the type specifiers
+    pub fn type_specifiers(&self) -> impl Iterator<Item = Option<&TypeSpecifier>> {
+        self.type_specifiers.iter().map(Option::as_ref)
+    }
+
+    /// Set the type specifiers
+    pub fn with_type_specifiers(self, type_specifiers: Vec<Option<TypeSpecifier>>) -> Self {
+        Self { type_specifiers, ..self }
+    }
+
+    /// Set the `option` token
+    pub fn with_option_token(self, option_token: TokenReference) -> Self {
+        Self { option_token, ..self }
+    }
+
+    /// Set the `=` token
+    pub fn with_equal_token(self, equal_token: TokenReference) -> Self {
+        Self { equal_token, ..self }
+    }
+
+    /// Set the expressions
+    pub fn with_expressions(self, expr_list: Punctuated<Expression>) -> Self {
+        Self { expr_list, ..self }
+    }
+}
+
+/// An error that occurs when creating the AST.
+#[derive(Clone, Debug, PartialEq, Eq, Display, Deserialize, Serialize)]
+#[display(
+    "unexpected token `{token}`. (starting from line {}, character {} and ending on line {}, character {})\nadditional information: {additional}",
+    self.range().0.line(),
+    self.range().0.character(),
+    self.range().1.line(),
+    self.range().1.character(),
+)]
+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 the token that caused the error
+    pub fn token(&self) -> &Token {
+        &self.token
+    }
+
+    /// 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()
+    }
+
+    /// Create an error from its parts, not really something we want to expose, but errors may come
+    /// from the passes and not the parse stage...
+    pub(crate) fn from_parts(token_reference: TokenReference, error: impl Into<Cow<'static, str>>) -> Self {
+        Self { token: token_reference.token().clone(), additional: error.into(), range: token_reference.range() }
+    }
+}
+
+impl std::error::Error for AstError {}
+
+/// An abstract syntax tree, contains all the nodes used in the code
+#[derive(Clone, Debug, Display, Deserialize, Serialize)]
+#[display("{nodes}{eof}")]
+pub struct Ast {
+    pub(crate) nodes: Block,
+    pub(crate) eof: TokenReference,
+}
+
+impl Ast {
+    /// Returns a new Ast with the given nodes
+    pub fn with_nodes(self, nodes: Block) -> Self {
+        Self { nodes, ..self }
+    }
+
+    /// Returns a new Ast with the given EOF token
+    pub fn with_eof(self, eof: TokenReference) -> Self {
+        Self { eof, ..self }
+    }
+
+    /// The entire code of the function
+    pub fn nodes(&self) -> &Block {
+        &self.nodes
+    }
+
+    /// The entire code of the function, but mutable
+    pub fn nodes_mut(&mut self) -> &mut Block {
+        &mut self.nodes
+    }
+
+    /// The EOF token at the end of every Ast
+    pub fn eof(&self) -> &TokenReference {
+        &self.eof
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::{prelude::parser::parse_lua_tree, visitors::VisitorMut};
+
+    #[test]
+    fn test_with_eof_safety() {
+        print!("{}", {
+            let ast = parse_lua_tree("local foo = 1").unwrap();
+            let eof = ast.eof().clone();
+            ast.with_eof(eof)
+        });
+    }
+
+    #[test]
+    fn test_with_nodes_safety() {
+        print!("{}", {
+            let ast = parse_lua_tree("local foo = 1").unwrap();
+            let nodes = ast.nodes().clone();
+            ast.with_nodes(nodes)
+        });
+    }
+
+    #[test]
+    fn test_with_visitor_safety() {
+        print!("{}", {
+            let ast = parse_lua_tree("local foo = 1").unwrap();
+            struct SyntaxRewriter;
+            impl VisitorMut for SyntaxRewriter {
+                fn visit_token(&mut self, token: Token) -> Token {
+                    token
+                }
+            }
+            SyntaxRewriter.visit_ast(ast)
+        });
+    }
+
+    // Tests AST nodes with new methods that call unwrap
+    #[test]
+    fn test_new_validity() {
+        let token: TokenReference =
+            TokenReference::new(Vec::new(), Token::new(TokenType::Identifier { identifier: "foo".into() }), Vec::new());
+
+        let expression = Expression::Var(Var::Name(token.clone()));
+
+        Assignment::new(Punctuated::new(), Punctuated::new());
+        Do::new();
+        ElseIf::new(expression.clone());
+        FunctionBody::new();
+        FunctionCall::new(Prefix::Name(token.clone()));
+        FunctionDeclaration::new(FunctionName::new(Punctuated::new()));
+        GenericFor::new(Punctuated::new(), Punctuated::new());
+        If::new(expression.clone());
+        LocalAssignment::new(Punctuated::new());
+        LocalFunction::new(token.clone());
+        MethodCall::new(
+            token.clone(),
+            FunctionArgs::Parentheses {
+                arguments: Punctuated::new(),
+                parentheses: ContainedSpan::new(token.clone(), token.clone()),
+            },
+        );
+        NumericFor::new(token, expression.clone(), expression.clone());
+        Repeat::new(expression.clone());
+        Return::new();
+        TableConstructor::new();
+        While::new(expression);
+    }
+
+    #[test]
+    fn test_local_assignment_print() {
+        let block = Block::new().with_stmts(vec![(
+            Stmt::LocalAssignment(
+                LocalAssignment::new(
+                    std::iter::once(Pair::End(TokenReference::new(
+                        vec![],
+                        Token::new(TokenType::Identifier { identifier: "variable".into() }),
+                        vec![],
+                    )))
+                    .collect(),
+                )
+                .with_equal_token(Some(TokenReference::symbol(" = ").unwrap()))
+                .with_expressions(
+                    std::iter::once(Pair::End(Expression::Number(TokenReference::new(
+                        vec![],
+                        Token::new(TokenType::Number { text: "1".into() }),
+                        vec![],
+                    ))))
+                    .collect(),
+                ),
+            ),
+            None,
+        )]);
+
+        let ast = parse_lua_tree("").unwrap().with_nodes(block);
+        assert_eq!(format!("{ast}"), "local variable = 1");
+    }
+}
+
+/// Any type, such as `string`, `boolean?`, etc.
+#[derive(Clone, Debug, Display, IsVariant, PartialEq, Node, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum TypeInfo {
+    /// A shorthand type annotating the structure of an array: { number }
+    #[display("{}{type_info}{}", braces.tokens().0, braces.tokens().1)]
+    Array {
+        /// The braces (`{}`) containing the type info.
+        braces: ContainedSpan,
+
+        /// The type info for the values in the Array
+        type_info: Box<TypeInfo>,
+    },
+
+    /// A standalone type, such as `string` or `Foo`.
+    #[display("{_0}")]
+    Basic(TokenReference),
+
+    /// A callback type, such as `(string, number) => boolean`.
+    #[display("{}{arguments}{}{arrow}{return_type}", parentheses.tokens().0, parentheses.tokens().1)]
+    Callback {
+        /// The parentheses for the arguments.
+        parentheses: ContainedSpan,
+
+        /// The argument types: `(string, number)`.
+        arguments: Punctuated<TypeArgument>,
+
+        /// The "thin arrow" (`->`) in between the arguments and the return type.
+        arrow: TokenReference,
+
+        /// The return type: `boolean`.
+        return_type: Box<TypeInfo>,
+    },
+
+    /// An optional type, such as `string?`.
+    #[display("{base}{question_mark}")]
+    Optional {
+        /// The type that is optional: `string`.
+        base: Box<TypeInfo>,
+
+        /// The question mark: `?`.
+        question_mark: TokenReference,
+    },
+
+    /// A type annotating the structure of a table: { foo: number, bar: string }
+    #[display("{}{fields}{}", braces.tokens().0, braces.tokens().1)]
+    Table {
+        /// The braces (`{}`) containing the fields.
+        braces: ContainedSpan,
+
+        /// The fields: `foo: number, bar: string`.
+        fields: Punctuated<TypeField>,
+    },
+
+    /// A type in the form of `typeof(foo)`.
+    #[display("{typeof_token}{}{inner}{}", parentheses.tokens().0, parentheses.tokens().1)]
+    Typeof {
+        /// The token `typeof`.
+        typeof_token: TokenReference,
+
+        /// The parentheses used to contain the expression.
+        parentheses: ContainedSpan,
+
+        /// The inner expression: `foo`.
+        inner: Box<Expression>,
+    },
+
+    /// A tuple expression: `(string, number)`.
+    #[display("{}{types}{}", parentheses.tokens().0, parentheses.tokens().1)]
+    Tuple {
+        /// The parentheses used to contain the types
+        parentheses: ContainedSpan,
+
+        /// The types: `(string, number)`.
+        types: Punctuated<TypeInfo>,
+    },
+}
+
+macro_rules! basic_type_info {
+    ($type: ident, $($types: ident),+ $(,)?) => {
+        basic_type_info! { $type }
+        basic_type_info! { $($types),+ }
+    };
+
+    ($type: ident) => {
+        #[doc = concat!("Get the type for '", stringify!($type), "'")]
+        pub fn $type() -> &'static Self {
+            const _: () = assert!(stringify!($type).len() <= 23, "the type name can't be inline");
+            static TYPE_INFO: TypeInfo = TypeInfo::Basic(TokenReference::new(
+                vec![],
+                Token::new(TokenType::Identifier { identifier: ShortString::new_inline(stringify!($type)) }),
+                vec![])
+            );
+            &TYPE_INFO
+        }
+    };
+}
+
+impl TypeInfo {
+    basic_type_info! {
+        string, number, char, nil, table, aux, any,
+        line, lines, syllabe, syllabes,
+    }
+}
+
+impl Default for TypeInfo {
+    fn default() -> Self {
+        TypeInfo::nil().clone()
+    }
+}
+
+impl DefaultRef for TypeInfo {
+    fn default_ref() -> &'static Self {
+        TypeInfo::nil()
+    }
+}
+
+/// A type field used within table types.
+/// The `foo: number` in `{ foo: number }`.
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{key}{colon}{value}")]
+pub struct TypeField {
+    pub(crate) key: TypeFieldKey,
+    pub(crate) colon: TokenReference,
+    pub(crate) value: TypeInfo,
+}
+
+impl TypeField {
+    /// Creates a new TypeField from the given key and value
+    pub fn new(key: TypeFieldKey, value: TypeInfo) -> Self {
+        Self { key, colon: TokenReference::symbol(": ").unwrap(), value }
+    }
+
+    /// The key of the field, `foo` in `foo: number`.
+    pub fn key(&self) -> &TypeFieldKey {
+        &self.key
+    }
+
+    /// The colon in between the key name and the value type.
+    pub fn colon_token(&self) -> &TokenReference {
+        &self.colon
+    }
+
+    /// The type for the field, `number` in `foo: number`.
+    pub fn value(&self) -> &TypeInfo {
+        &self.value
+    }
+
+    /// Returns a new TypeField with the given key
+    pub fn with_key(self, key: TypeFieldKey) -> Self {
+        Self { key, ..self }
+    }
+
+    /// Returns a new TypeField with the `:` token
+    pub fn with_colon_token(self, colon_token: TokenReference) -> Self {
+        Self { colon: colon_token, ..self }
+    }
+
+    /// Returns a new TypeField with the `:` token
+    pub fn with_value(self, value: TypeInfo) -> Self {
+        Self { value, ..self }
+    }
+}
+
+/// A key in a [`TypeField`]. Can either be a name or an index signature.
+#[derive(Clone, Debug, Display, PartialEq, Node, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum TypeFieldKey {
+    /// A name, such as `foo`.
+    #[display("{_0}")]
+    Name(TokenReference),
+
+    /// An index signature, such as `[number]`.
+    #[display("{}{inner}{}", brackets.tokens().0, brackets.tokens().1)]
+    IndexSignature {
+        /// The brackets (`[]`) used to contain the type.
+        brackets: ContainedSpan,
+
+        /// The type for the index signature, `number` in `[number]`.
+        inner: TypeInfo,
+    },
+}
+
+/// A type assertion using `::`, such as `:: number`.
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{assertion_op}{cast_to}")]
+pub struct TypeAssertion {
+    pub(crate) assertion_op: TokenReference,
+    pub(crate) cast_to: TypeInfo,
+}
+
+impl TypeAssertion {
+    /// Creates a new TypeAssertion from the given cast to TypeInfo
+    pub fn new(cast_to: TypeInfo) -> Self {
+        Self { assertion_op: TokenReference::symbol("::").unwrap(), cast_to }
+    }
+
+    /// The token `::`.
+    pub fn assertion_op(&self) -> &TokenReference {
+        &self.assertion_op
+    }
+
+    /// The type to cast the expression into, `number` in `:: number`.
+    pub fn cast_to(&self) -> &TypeInfo {
+        &self.cast_to
+    }
+
+    /// Returns a new TypeAssertion with the given `::` token
+    pub fn with_assertion_op(self, assertion_op: TokenReference) -> Self {
+        Self { assertion_op, ..self }
+    }
+
+    /// Returns a new TypeAssertion with the given TypeInfo to cast to
+    pub fn with_cast_to(self, cast_to: TypeInfo) -> Self {
+        Self { cast_to, ..self }
+    }
+}
+
+/// A type declaration, such as `type Meters = number`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{type_token}{base}{equal_token}{declare_as}")]
+pub struct TypeDeclaration {
+    pub(crate) type_token: TokenReference,
+    pub(crate) base: TokenReference,
+    pub(crate) equal_token: TokenReference,
+    pub(crate) declare_as: TypeInfo,
+}
+
+impl TypeDeclaration {
+    /// Creates a new TypeDeclaration from the given type name and type declaration
+    pub fn new(type_name: TokenReference, type_definition: TypeInfo) -> Self {
+        Self {
+            type_token: TokenReference::new(
+                Vec::new(),
+                Token::new(TokenType::Identifier { identifier: "type".into() }),
+                vec![Token::new(TokenType::spaces(1))],
+            ),
+            base: type_name,
+            equal_token: TokenReference::symbol(" = ").unwrap(),
+            declare_as: type_definition,
+        }
+    }
+
+    /// The token `type`.
+    pub fn type_token(&self) -> &TokenReference {
+        &self.type_token
+    }
+
+    /// The name of the type, `Meters` in `type Meters = number`.
+    pub fn type_name(&self) -> &TokenReference {
+        &self.base
+    }
+
+    /// The `=` token in between the type name and the definition.
+    pub fn equal_token(&self) -> &TokenReference {
+        &self.equal_token
+    }
+
+    /// The definition of the type, `number` in `type Meters = number`.
+    pub fn type_definition(&self) -> &TypeInfo {
+        &self.declare_as
+    }
+
+    /// Returns a new TypeDeclaration with the given `type` token
+    pub fn with_type_token(self, type_token: TokenReference) -> Self {
+        Self { type_token, ..self }
+    }
+
+    /// Returns a new TypeDeclaration with the given type name
+    pub fn with_type_name(self, type_name: TokenReference) -> Self {
+        Self { base: type_name, ..self }
+    }
+
+    /// Returns a new TypeDeclaration with the given generics of the type
+    pub fn with_equal_token(self, equal_token: TokenReference) -> Self {
+        Self { equal_token, ..self }
+    }
+
+    /// Returns a new TypeDeclaration with the given generics of the type
+    pub fn with_type_definition(self, type_definition: TypeInfo) -> Self {
+        Self { declare_as: type_definition, ..self }
+    }
+}
+
+/// A type specifier, the `: number` in `local foo: number`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{punctuation}{type_info}")]
+pub struct TypeSpecifier {
+    pub(crate) punctuation: TokenReference,
+    pub(crate) type_info: TypeInfo,
+}
+
+impl TypeSpecifier {
+    /// Creates a new TypeSpecifier with the given type info
+    pub fn new(type_info: TypeInfo) -> Self {
+        Self { punctuation: TokenReference::symbol(": ").unwrap(), type_info }
+    }
+
+    /// The punctuation being used.
+    /// `:` for `local foo: number`.
+    pub fn punctuation(&self) -> &TokenReference {
+        &self.punctuation
+    }
+
+    /// The type being specified: `number` in `local foo: number`.
+    pub fn type_info(&self) -> &TypeInfo {
+        &self.type_info
+    }
+
+    /// Returns a new TypeSpecifier with the given punctuation
+    pub fn with_punctuation(self, punctuation: TokenReference) -> Self {
+        Self { punctuation, ..self }
+    }
+
+    /// Returns a new TypeSpecifier with the given type being specified
+    pub fn with_type_info(self, type_info: TypeInfo) -> Self {
+        Self { type_info, ..self }
+    }
+}
+
+/// A type argument specified in a callback type, the `count: number` in `(count: number) -> ()`
+#[derive(Clone, Debug, PartialEq, Node, Visit, Deserialize, Serialize)]
+pub struct TypeArgument {
+    pub(crate) name: Option<(TokenReference, TokenReference)>,
+    pub(crate) type_info: TypeInfo,
+}
+
+impl TypeArgument {
+    /// Creates a new TypeArgument with the given type info
+    pub fn new(type_info: TypeInfo) -> Self {
+        Self { name: None, type_info }
+    }
+
+    /// The name of the argument split into identifier and punctuation: `count:` in `count: number`.
+    pub fn name(&self) -> Option<&(TokenReference, TokenReference)> {
+        self.name.as_ref()
+    }
+
+    /// The type info for the argument: `number` in `count: number`.
+    pub fn type_info(&self) -> &TypeInfo {
+        &self.type_info
+    }
+
+    /// Returns a new TypeArgument with the given punctuation
+    pub fn with_name(self, name: Option<(TokenReference, TokenReference)>) -> Self {
+        Self { name, ..self }
+    }
+
+    /// Returns a new TypeArgument with the given type info
+    pub fn with_type_info(self, type_info: TypeInfo) -> Self {
+        Self { type_info, ..self }
+    }
+}
+
+impl fmt::Display for TypeArgument {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        if let Some((identifier, punctuation)) = self.name() {
+            write!(formatter, "{}{}{}", identifier, punctuation, self.type_info)
+        } else {
+            write!(formatter, "{}", self.type_info)
+        }
+    }
+}
+
+/// Compound operators, such as X += Y or X -= Y
+#[derive(Clone, Debug, Display, PartialEq, Eq, Node, Visit, Deserialize, Serialize)]
+#[non_exhaustive]
+#[allow(missing_docs)]
+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
+    pub fn token(&self) -> &TokenReference {
+        match self {
+            Self::PlusEqual(token)
+            | Self::MinusEqual(token)
+            | Self::StarEqual(token)
+            | Self::SlashEqual(token)
+            | Self::DoubleSlashEqual(token)
+            | Self::PercentEqual(token)
+            | Self::CaretEqual(token)
+            | 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`
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{lhs}{compound_operator}{rhs}")]
+pub struct CompoundAssignment {
+    pub(crate) lhs: Var,
+    pub(crate) compound_operator: CompoundOp,
+    pub(crate) rhs: Expression,
+}
+
+impl CompoundAssignment {
+    /// Creates a new CompoundAssignment from the left and right hand side
+    pub fn new(lhs: Var, compound_operator: CompoundOp, rhs: Expression) -> Self {
+        Self { lhs, compound_operator, rhs }
+    }
+
+    /// The variable assigned to, the `x` part of `x += 1`
+    pub fn lhs(&self) -> &Var {
+        &self.lhs
+    }
+
+    /// The operator used, the `+=` part of `x += 1`
+    pub fn compound_operator(&self) -> &CompoundOp {
+        &self.compound_operator
+    }
+
+    /// The value being assigned, the `1` part of `x += 1`
+    pub fn rhs(&self) -> &Expression {
+        &self.rhs
+    }
+
+    /// Returns a new CompoundAssignment with the given variable being assigned to
+    pub fn with_lhs(self, lhs: Var) -> Self {
+        Self { lhs, ..self }
+    }
+
+    /// Returns a new CompoundAssignment with the given operator used
+    pub fn with_compound_operator(self, compound_operator: CompoundOp) -> Self {
+        Self { compound_operator, ..self }
+    }
+
+    /// Returns a new CompoundAssignment with the given value being assigned
+    pub fn with_rhs(self, rhs: Expression) -> Self {
+        Self { rhs, ..self }
+    }
+}
+
+/// An if statement
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{if_token}{condition}{then_token}{if_expression}{}{else_token}{else_expression}",
+    display_option(else_if_expressions.as_ref().map(join_vec)),
+)]
+pub struct IfExpression {
+    pub(crate) if_token: TokenReference,
+    pub(crate) condition: Box<Expression>,
+    pub(crate) then_token: TokenReference,
+    pub(crate) if_expression: Box<Expression>,
+    pub(crate) else_if_expressions: Option<Vec<ElseIfExpression>>,
+    pub(crate) else_token: TokenReference,
+    pub(crate) else_expression: Box<Expression>,
+}
+
+impl IfExpression {
+    /// Creates a new If from the given condition
+    pub fn new(condition: Expression, if_expression: Expression, else_expression: Expression) -> Self {
+        Self {
+            if_token: TokenReference::symbol("if ").unwrap(),
+            condition: Box::new(condition),
+            then_token: TokenReference::symbol(" then").unwrap(),
+            if_expression: Box::new(if_expression),
+            else_if_expressions: None,
+            else_token: TokenReference::symbol(" else ").unwrap(),
+            else_expression: Box::new(else_expression),
+        }
+    }
+
+    /// The `if` token
+    pub fn if_token(&self) -> &TokenReference {
+        &self.if_token
+    }
+
+    /// The condition of the if expression, `condition` in `if condition then`
+    pub fn condition(&self) -> &Expression {
+        &self.condition
+    }
+
+    /// The `then` token
+    pub fn then_token(&self) -> &TokenReference {
+        &self.then_token
+    }
+
+    /// The expression evaluated if the initial if condition holds
+    pub fn if_expression(&self) -> &Expression {
+        &self.if_expression
+    }
+
+    /// The `else` token
+    pub fn else_token(&self) -> &TokenReference {
+        &self.else_token
+    }
+
+    /// If there are `elseif` conditions, returns a vector of them
+    pub fn else_if_expressions(&self) -> impl Iterator<Item = &ElseIfExpression> {
+        self.else_if_expressions.as_ref().into_iter().flatten()
+    }
+
+    /// The else expression if all other conditions do not hold
+    pub fn else_expression(&self) -> &Expression {
+        &self.else_expression
+    }
+
+    /// Returns a new IfExpression with the given `if` token
+    pub fn with_if_token(self, if_token: TokenReference) -> Self {
+        Self { if_token, ..self }
+    }
+
+    /// Returns a new IfExpression with the given condition
+    pub fn with_condition(self, condition: Expression) -> Self {
+        Self { condition: Box::new(condition), ..self }
+    }
+
+    /// Returns a new IfExpression with the given `then` token
+    pub fn with_then_token(self, then_token: TokenReference) -> Self {
+        Self { then_token, ..self }
+    }
+
+    /// Returns a new IfExpression with the given if expression
+    pub fn with_if_expression(self, if_expression: Expression) -> Self {
+        Self { if_expression: Box::new(if_expression), ..self }
+    }
+
+    /// Returns a new If with the given list of `elseif` expressions
+    pub fn with_else_if(self, else_if_expressions: Option<Vec<ElseIfExpression>>) -> Self {
+        Self { else_if_expressions, ..self }
+    }
+
+    /// Returns a new IfExpression with the given `else` token
+    pub fn with_else_token(self, else_token: TokenReference) -> Self {
+        Self { else_token, ..self }
+    }
+
+    /// Returns a new IfExpression with the given `else` expression
+    pub fn with_else(self, else_expression: Expression) -> Self {
+        Self { else_expression: Box::new(else_expression), ..self }
+    }
+}
+
+/// An elseif expression in a bigger [`IfExpression`] expression
+#[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
+#[display("{else_if_token}{condition}{then_token}{expression}")]
+pub struct ElseIfExpression {
+    pub(crate) else_if_token: TokenReference,
+    pub(crate) condition: Expression,
+    pub(crate) then_token: TokenReference,
+    pub(crate) expression: Expression,
+}
+
+impl ElseIfExpression {
+    /// Creates a new ElseIf from the given condition
+    pub fn new(condition: Expression, expression: Expression) -> Self {
+        Self {
+            else_if_token: TokenReference::symbol(" elseif ").unwrap(),
+            condition,
+            then_token: TokenReference::symbol(" then ").unwrap(),
+            expression,
+        }
+    }
+
+    /// The `elseif` token
+    pub fn else_if_token(&self) -> &TokenReference {
+        &self.else_if_token
+    }
+
+    /// The condition of the `elseif`, `condition` in `elseif condition then`
+    pub fn condition(&self) -> &Expression {
+        &self.condition
+    }
+
+    /// The `then` token
+    pub fn then_token(&self) -> &TokenReference {
+        &self.then_token
+    }
+
+    /// The evaluated expression of the `elseif` when condition is true
+    pub fn expression(&self) -> &Expression {
+        &self.expression
+    }
+
+    /// Returns a new ElseIfExpression with the given `elseif` token
+    pub fn with_else_if_token(self, else_if_token: TokenReference) -> Self {
+        Self { else_if_token, ..self }
+    }
+
+    /// Returns a new ElseIfExpression with the given condition
+    pub fn with_condition(self, condition: Expression) -> Self {
+        Self { condition, ..self }
+    }
+
+    /// Returns a new ElseIfExpression with the given `then` token
+    pub fn with_then_token(self, then_token: TokenReference) -> Self {
+        Self { then_token, ..self }
+    }
+
+    /// Returns a new ElseIfExpression with the given expression
+    pub fn with_block(self, expression: Expression) -> Self {
+        Self { expression, ..self }
+    }
+}
diff --git a/src/Rust/vvs_parser/src/ast/options.rs b/src/Rust/vvs_parser/src/ast/options.rs
new file mode 100644
index 0000000000000000000000000000000000000000..228af95da682bb3fb9b4a104542735e5e8761c93
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/options.rs
@@ -0,0 +1,108 @@
+//! Option table passed to the Vivy program at runtime.
+
+use crate::{ast::Expression, ShortString};
+use serde::{Deserialize, Serialize};
+
+/// Options for a program, represent the thing that is red from a file.
+///
+/// The syntax was a bit modified:
+/// ```ini
+/// [module]
+/// option = some Lua/VivyScript expression
+/// ```
+#[derive(Default, Serialize, Deserialize)]
+pub struct OptionTable {
+    modules: Vec<(ShortString, Vec<(ShortString, Expression)>)>,
+}
+
+pub(crate) struct OptionTableSectionMut<'a> {
+    options: &'a mut Vec<(ShortString, Expression)>,
+}
+
+impl OptionTable {
+    /// Create a new empty default option table.
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    /// Get the number of options in the table
+    pub fn len(&self) -> usize {
+        self.modules.iter().map(|(_, section)| section.len()).sum()
+    }
+
+    /// Tells whever we have options in the table or not.
+    pub fn is_empty(&self) -> bool {
+        self.modules.iter().all(|(_, section)| section.is_empty())
+    }
+
+    /// Get the asked option if it exists in this table.
+    pub fn get(&self, module: impl AsRef<str>, option: impl AsRef<str>) -> Option<&Expression> {
+        self.modules
+            .iter()
+            .find_map(|(name, section)| (name.as_str() == module.as_ref()).then_some(section))?
+            .iter()
+            .find_map(|(name, value)| (name.as_str() == option.as_ref()).then_some(value))
+    }
+
+    /// Tells whether we have a said section or not in the option table.
+    pub(crate) fn has_section(&self, section: impl AsRef<str>) -> bool {
+        self.modules.iter().any(|(m, _)| m.as_str() == section.as_ref())
+    }
+
+    /// Get a section of the table in mutable access. If the section doesn't exist it will be
+    /// created and will be empty.
+    pub(crate) fn section_mut(&mut self, section: impl Into<ShortString>) -> OptionTableSectionMut<'_> {
+        let section = section.into();
+        let mut sections = self.modules.iter().enumerate();
+        let idx = sections
+            .find_map(|(idx, (module, _))| (*module == section).then_some(idx))
+            .unwrap_or_else(|| {
+                self.modules.push((section, vec![]));
+                self.modules.len() - 1
+            });
+        OptionTableSectionMut::new(&mut self.modules[idx].1)
+    }
+}
+
+impl<'a> OptionTableSectionMut<'a> {
+    fn new(options: &'a mut Vec<(ShortString, Expression)>) -> Self {
+        Self { options }
+    }
+}
+
+impl<'a> Iterator for OptionTableSectionMut<'a> {
+    type Item = (ShortString, Expression);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.options.pop()
+    }
+}
+
+impl<'a> Extend<(ShortString, Expression)> for OptionTableSectionMut<'a> {
+    fn extend<T: IntoIterator<Item = (ShortString, Expression)>>(&mut self, iter: T) {
+        self.options.extend(iter)
+    }
+}
+
+impl Iterator for OptionTable {
+    type Item = (ShortString, ShortString, Expression);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let (module, mut section) = self
+            .modules
+            .iter_mut()
+            .find(|(_, opts)| !opts.is_empty())
+            .map(|(module, section)| (module, OptionTableSectionMut::new(section)))?;
+        let (option, expression) = section.next().unwrap();
+        Some((module.clone(), option, expression))
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let count = self.len();
+        (count, Some(count))
+    }
+
+    fn count(self) -> usize {
+        self.len()
+    }
+}
diff --git a/src/Rust/vvs_parser/src/ast/parsers/mod.rs b/src/Rust/vvs_parser/src/ast/parsers/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1e79a07d0b6b716f454d737ebf48aa74787697b7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/parsers/mod.rs
@@ -0,0 +1,2172 @@
+//! Contains things for the parsers. Parse the vvs/vvl files and the option file.
+
+mod structs;
+mod util;
+
+use crate::{
+    ast::{
+        self,
+        punctuated::{Pair, Punctuated},
+        span::ContainedSpan,
+        CallList, Expression, FunctionBody, Parameter,
+    },
+    node::Node,
+    tokenizer::{Symbol, Token, TokenKind, TokenReference, TokenType},
+    try_parser,
+};
+
+pub use crate::ast::parsers::structs::*;
+
+pub fn parse_option_table(state: &mut ParserState) -> ParserResult<ast::OptionTable> {
+    let mut table = ast::OptionTable::default();
+
+    while let ParserResult::Value(left_bracket) = state.consume() {
+        let section = match left_bracket.token_type() {
+            TokenType::MultiLineComment { .. } | TokenType::SingleLineComment { .. } => continue,
+            TokenType::Eof => break,
+            TokenType::Symbol { symbol: Symbol::LeftBracket } => expect_option_table_section(state, left_bracket),
+            _ => todo!("error"),
+        };
+
+        let (identifier, options) = match section {
+            ParserResult::NotFound => break,
+            ParserResult::Value((
+                TokenReference { token: Token { token_type: TokenType::Identifier { identifier, .. }, .. }, .. },
+                options,
+            )) => (identifier, options),
+            _ => return ParserResult::LexerMoved,
+        };
+
+        table
+            .section_mut(identifier)
+            .extend(options.into_iter().flat_map(|(option, value)| match option {
+                TokenReference {
+                    token: Token { token_type: TokenType::Identifier { identifier, .. }, .. }, ..
+                } => Some((identifier, value)),
+                _ => None,
+            }));
+    }
+
+    ParserResult::Value(table)
+}
+
+fn expect_option_table_section(
+    state: &mut ParserState,
+    left_bracket: TokenReference,
+) -> ParserResult<(TokenReference, Vec<(TokenReference, Expression)>)> {
+    let section = match parse_identifier(state) {
+        ParserResult::Value(section) => section,
+        _ => {
+            state.token_error(left_bracket, "expected an identifier as the option section name");
+            return ParserResult::LexerMoved;
+        }
+    };
+
+    if state.consume_if(Symbol::RightBracket).is_none() {
+        state.token_error(section, "expected a ']' to close after the section name declaration");
+        return ParserResult::LexerMoved;
+    }
+
+    let mut options = Vec::new();
+    while let Ok(current) = state.current() {
+        match current.token_type() {
+            TokenType::Eof | TokenType::Symbol { symbol: Symbol::LeftBracket } => break,
+            TokenType::Identifier { .. } => {}
+            _ => {
+                state.token_error(current.clone(), "expected the name of an option");
+                return ParserResult::LexerMoved;
+            }
+        }
+        let option = state.consume().unwrap();
+
+        let separator = match state.consume_ifs(&[Symbol::Equal, Symbol::Colon]) {
+            Some(separator) => separator,
+            None => {
+                state.token_error(option, "expected a ':' or a '=' to assign the option");
+                return ParserResult::LexerMoved;
+            }
+        };
+
+        let expression = match parse_expression(state) {
+            ParserResult::Value(expression) => expression,
+            ParserResult::LexerMoved | ParserResult::NotFound => {
+                state.token_error(separator, "expected an expression as the option value");
+                return ParserResult::LexerMoved;
+            }
+        };
+
+        options.push((option, expression));
+    }
+
+    ParserResult::Value((section, options))
+}
+
+pub fn parse_block(state: &mut ParserState) -> ParserResult<ast::Block> {
+    let mut stmts = Vec::new();
+
+    loop {
+        match parse_stmt(state) {
+            ParserResult::Value(StmtVariant::Stmt(stmt)) => {
+                stmts.push((stmt, state.consume_if(Symbol::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 });
+            }
+            ParserResult::NotFound => break,
+            ParserResult::LexerMoved if stmts.is_empty() => return ParserResult::LexerMoved,
+            ParserResult::LexerMoved => break,
+        }
+    }
+
+    let last_stmt = parse_last_stmt(state).ok();
+    ParserResult::Value(ast::Block { stmts, last_stmt })
+}
+
+// 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(()),
+    };
+
+    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 {
+        (start_for_errors, start_for_errors)
+    };
+
+    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")));
+    };
+
+    Ok((block, end_token))
+}
+
+enum StmtVariant {
+    Stmt(ast::Stmt),
+
+    // Used for things like Luau's `continue`, but nothing constructs it in Lua 5.1 alone.
+    #[allow(unused)]
+    LastStmt(ast::LastStmt),
+}
+
+fn parse_stmt(state: &mut ParserState) -> ParserResult<StmtVariant> {
+    let Ok(current_token) = state.current() else {
+        return ParserResult::NotFound;
+    };
+
+    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,
+            };
+
+            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 callable_token = state.consume().unwrap();
+                    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 function name");
+                            return ParserResult::LexerMoved;
+                        }
+                        Err(()) => return ParserResult::LexerMoved,
+                    };
+
+                    let body = match parse_function_body(state) {
+                        ParserResult::Value(function_body) => function_body,
+                        ParserResult::NotFound => {
+                            state.token_error(callable_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: callable_token,
+                        name,
+                        body,
+                    })))
+                }
+
+                _ => {
+                    state.token_error(next_token.clone(), "expected either a variable name or `function`");
+                    ParserResult::LexerMoved
+                }
+            }
+        }
+
+        TokenType::Symbol { symbol: Symbol::For } => {
+            let for_token = state.consume().unwrap();
+            ParserResult::Value(StmtVariant::Stmt(match expect_for_stmt(state, for_token) {
+                Ok(for_stmt) => for_stmt,
+                Err(()) => return ParserResult::LexerMoved,
+            }))
+        }
+
+        TokenType::Symbol { symbol: Symbol::Option } => {
+            let option_token = state.consume().unwrap();
+            ParserResult::Value(StmtVariant::Stmt(ast::Stmt::OptionDecl(
+                match expect_option_decl(state, option_token) {
+                    Ok(option_decl_stmt) => option_decl_stmt,
+                    Err(()) => return ParserResult::LexerMoved,
+                },
+            )))
+        }
+
+        TokenType::Symbol { symbol: Symbol::Yield } => {
+            let yield_token = state.consume().unwrap();
+            ParserResult::Value(StmtVariant::Stmt(ast::Stmt::Yield(match expect_yield(state, yield_token) {
+                Ok(yield_stmt) => yield_stmt,
+                Err(()) => return ParserResult::LexerMoved,
+            })))
+        }
+
+        TokenType::Symbol { symbol: Symbol::Main } => {
+            let main_token = state.consume().unwrap();
+            ParserResult::Value(StmtVariant::Stmt(ast::Stmt::Main(match expect_main(state, main_token) {
+                Ok(main_stmt) => main_stmt,
+                Err(()) => return ParserResult::LexerMoved,
+            })))
+        }
+
+        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,
+            };
+            ParserResult::Value(StmtVariant::Stmt(ast::Stmt::Do(ast::Do { do_token, block, end_token })))
+        }
+
+        TokenType::Symbol { symbol: Symbol::If } => {
+            let if_token = state.consume().unwrap();
+            ParserResult::Value(StmtVariant::Stmt(ast::Stmt::If(match expect_if_stmt(state, if_token) {
+                Ok(if_stmt) => if_stmt,
+                Err(()) => return ParserResult::LexerMoved,
+            })))
+        }
+
+        TokenType::Symbol { symbol: Symbol::Import } => {
+            let import_token = state.consume().unwrap();
+            let name = match state.current() {
+                Ok(token) if token.token_kind() == TokenKind::StringLiteral => state.consume().unwrap(),
+                Ok(token) => {
+                    state.token_error(token.clone(), "expected a string as the module name");
+                    return ParserResult::LexerMoved;
+                }
+                Err(()) => return ParserResult::LexerMoved,
+            };
+            ParserResult::Value(StmtVariant::Stmt(ast::Stmt::Import(ast::Import { import_token, name })))
+        }
+
+        TokenType::Symbol { symbol: callable @ Symbol::Function | callable @ Symbol::Job } => {
+            let callable = *callable;
+            let token = state.consume().unwrap();
+            let declaration = match expect_function_declaration(state, token) {
+                Ok(declaration) => declaration,
+                Err(()) => return ParserResult::LexerMoved,
+            };
+            let job_name_is_invalid = {
+                let name = declaration.name();
+                name.names().len() != 1 || name.method_colon().is_some() || name.method_name().is_some()
+            };
+            match callable {
+                Symbol::Job if job_name_is_invalid => {
+                    state.token_error(
+                        declaration.function_token().clone(),
+                        "invalid name for a job, can't be ponctuated or have columns",
+                    );
+                    ParserResult::LexerMoved
+                }
+                Symbol::Job => ParserResult::Value(StmtVariant::Stmt(ast::Stmt::JobDeclaration(declaration))),
+                Symbol::Function => ParserResult::Value(StmtVariant::Stmt(ast::Stmt::FunctionDeclaration(declaration))),
+                _ => unreachable!(),
+            }
+        }
+
+        TokenType::Symbol { symbol: Symbol::Repeat } => {
+            let repeat_token = state.consume().unwrap();
+            ParserResult::Value(StmtVariant::Stmt(match expect_repeat_stmt(state, repeat_token) {
+                Ok(repeat_stmt) => repeat_stmt,
+                Err(()) => return ParserResult::LexerMoved,
+            }))
+        }
+
+        TokenType::Symbol { symbol: Symbol::While } => {
+            let while_token = state.consume().unwrap();
+            ParserResult::Value(StmtVariant::Stmt(ast::Stmt::While(match expect_while_stmt(state, while_token) {
+                Ok(while_stmt) => while_stmt,
+                Err(()) => return ParserResult::LexerMoved,
+            })))
+        }
+
+        TokenType::Symbol { symbol: Symbol::LeftParen } | TokenType::Identifier { .. } => {
+            let (prefix, suffixes) =
+                try_parser!(parse_prefix_and_suffixes(state)).expect("we should always be starting on the right path");
+            let var = match suffixes.last() {
+                Some(ast::Suffix::Call(_)) => {
+                    return ParserResult::Value(StmtVariant::Stmt(ast::Stmt::FunctionCall(ast::FunctionCall {
+                        prefix,
+                        suffixes,
+                    })));
+                }
+                Some(ast::Suffix::Index(_)) => ast::Var::Expression(Box::new(ast::VarExpression { prefix, suffixes })),
+                None => match prefix {
+                    ast::Prefix::Name(name) => ast::Var::Name(name),
+                    // I think this only happens in error cases
+                    prefix @ ast::Prefix::Expression(_) => {
+                        ast::Var::Expression(Box::new(ast::VarExpression { prefix, suffixes }))
+                    }
+                },
+            };
+
+            match state.current() {
+                // Compound Assignment
+                Ok(token)
+                    if token.in_symbols(&[
+                        Symbol::PlusEqual,
+                        Symbol::MinusEqual,
+                        Symbol::StarEqual,
+                        Symbol::SlashEqual,
+                        Symbol::DoubleSlashEqual,
+                        Symbol::PercentEqual,
+                        Symbol::CaretEqual,
+                        Symbol::TwoDotsEqual,
+                    ]) =>
+                {
+                    let compound_operator = state.consume().unwrap();
+                    let ParserResult::Value(expr) = parse_expression(state) else {
+                        state.token_error(compound_operator, "expected expression to set to");
+                        return ParserResult::LexerMoved;
+                    };
+                    return ParserResult::Value(StmtVariant::Stmt(ast::Stmt::CompoundAssignment(
+                        ast::CompoundAssignment {
+                            lhs: var,
+                            compound_operator: ast::CompoundOp::from_token(compound_operator),
+                            rhs: expr,
+                        },
+                    )));
+                }
+
+                Ok(token) if token.in_symbols(&[Symbol::Comma, Symbol::Equal]) => {}
+
+                Ok(token) => {
+                    // Check if the consumed token is a potential context-sensitive keyword
+                    if let ast::Var::Name(token) = var {
+                        match token.token_type() {
+                            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,
+                                )));
+                            }
+                            _ => (),
+                        }
+                    }
+
+                    state.token_error(token.clone(), "unexpected expression when looking for a statement");
+                    return ParserResult::LexerMoved;
+                }
+
+                Err(()) => return ParserResult::LexerMoved,
+            };
+
+            let mut var_list = Punctuated::new();
+            var_list.push(Pair::End(var));
+
+            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 (next_prefix, next_suffixes) = match parse_prefix_and_suffixes(state) {
+                    ParserResult::Value((prefix, suffixes)) => (prefix, suffixes),
+                    ParserResult::LexerMoved => break,
+                    ParserResult::NotFound => {
+                        state.token_error(next_comma, "expected another variable");
+                        break;
+                    }
+                };
+
+                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;
+                    }
+
+                    Some(ast::Suffix::Index(_)) => var_list.push_punctuated(
+                        ast::Var::Expression(Box::new(ast::VarExpression {
+                            prefix: next_prefix,
+                            suffixes: next_suffixes,
+                        })),
+                        next_comma,
+                    ),
+
+                    None => match next_prefix {
+                        ast::Prefix::Name(name) => var_list.push_punctuated(ast::Var::Name(name), next_comma),
+                        prefix @ ast::Prefix::Expression(_) => var_list.push_punctuated(
+                            ast::Var::Expression(Box::new(ast::VarExpression { prefix, suffixes: next_suffixes })),
+                            next_comma,
+                        ),
+                    },
+                }
+            }
+
+            let Some(equal_token) = state.require(Symbol::Equal, "expected `=` after name") else {
+                return ParserResult::LexerMoved;
+            };
+
+            let expr_list = match parse_expression_list(state) {
+                ParserResult::Value(expr_list) => expr_list,
+                ParserResult::NotFound => {
+                    state.token_error(equal_token.clone(), "expected values to set to");
+                    Punctuated::new()
+                }
+                ParserResult::LexerMoved => Punctuated::new(),
+            };
+
+            ParserResult::Value(StmtVariant::Stmt(ast::Stmt::Assignment(ast::Assignment {
+                var_list,
+                equal_token,
+                expr_list,
+            })))
+        }
+
+        _ => ParserResult::NotFound,
+    }
+}
+
+fn parse_last_stmt(state: &mut ParserState) -> ParserResult<(ast::LastStmt, Option<TokenReference>)> {
+    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 })
+        }
+
+        Ok(token) if token.is_symbol(Symbol::Break) => {
+            let break_token = state.consume().unwrap();
+            ast::LastStmt::Break(break_token)
+        }
+
+        _ => return ParserResult::NotFound,
+    };
+
+    let semicolon = state.consume_if(Symbol::Semicolon);
+    ParserResult::Value((last_stmt, semicolon))
+}
+
+fn expect_function_name(state: &mut ParserState) -> ParserResult<ast::FunctionName> {
+    let mut names = Punctuated::new();
+    let name = match state.current() {
+        Ok(token) if matches!(token.token_type(), TokenType::Identifier { .. }) => state.consume().unwrap(),
+        Ok(token) => {
+            state.token_error(token.clone(), "expected function name");
+            return ParserResult::NotFound;
+        }
+        Err(()) => return ParserResult::NotFound,
+    };
+
+    names.push(Pair::End(name));
+
+    loop {
+        let middle_token = match state.current() {
+            Ok(token) if token.in_symbols(&[Symbol::Colon, Symbol::Dot]) => state.consume().unwrap(),
+            Ok(_) => break,
+            Err(()) => return ParserResult::LexerMoved,
+        };
+
+        let name = match state.current() {
+            Ok(token) if matches!(token.token_type(), TokenType::Identifier { .. }) => state.consume().unwrap(),
+            Ok(token) => {
+                state.token_error(token.clone(), format!("expected name after `{}`", middle_token.token()));
+                return ParserResult::NotFound;
+            }
+            Err(()) => return ParserResult::LexerMoved,
+        };
+
+        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!();
+        }
+    }
+
+    ParserResult::Value(ast::FunctionName { names, colon_name: None })
+}
+
+fn expect_function_declaration(
+    state: &mut ParserState,
+    function_token: TokenReference,
+) -> Result<ast::FunctionDeclaration, ()> {
+    let function_name = expect_function_name(state).ok_or(())?;
+    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()
+        }
+    };
+    Ok(ast::FunctionDeclaration { function_token, name: function_name, body: function_body })
+}
+
+fn expect_for_stmt(state: &mut ParserState, for_token: TokenReference) -> Result<ast::Stmt, ()> {
+    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 = state.current()?;
+    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,
+            for_token,
+            name_list.into_iter().next().unwrap(),
+        )?));
+    }
+
+    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 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(()),
+    };
+
+    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(),
+            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"),
+        }));
+    };
+
+    let (block, end) = match expect_block_with_end(state, "for loop", &do_token) {
+        Ok(block) => block,
+        Err(()) => (ast::Block::new(), TokenReference::basic_symbol("end")),
+    };
+
+    Ok(ast::Stmt::GenericFor(ast::GenericFor {
+        for_token,
+        names: name_list
+            .clone()
+            .into_pairs()
+            .map(|pair| pair.map(|name| name.name))
+            .collect(),
+        type_specifiers: name_list.into_iter().map(|name| name.type_specifier).collect(),
+        in_token,
+        expr_list: expressions,
+        do_token,
+        block,
+        end_token: end,
+    }))
+}
+
+fn expect_numeric_for_stmt(
+    state: &mut ParserState,
+    for_token: TokenReference,
+    index_variable: Name,
+) -> Result<ast::NumericFor, ()> {
+    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 start_end_comma = state
+        .require(Symbol::Comma, "expected `,` after start expression")
+        .ok_or(())?;
+
+    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(()),
+    };
+
+    // 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(()),
+        },
+
+        None => (None, None),
+    };
+
+    let do_token = state
+        .require(Symbol::Do, "expected `do` after step expression")
+        .ok_or(())?;
+
+    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,
+        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<ast::If, ()> {
+    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(()),
+    };
+
+    let then_token = state
+        .require(Symbol::Then, "expected `then` after condition")
+        .ok_or(())?;
+
+    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)),
+    };
+
+    let mut else_if = Vec::new();
+
+    let else_if_optional = |else_if: Vec<ast::ElseIf>| (!else_if.is_empty()).then_some(else_if);
+    let unfinished_if = |condition, else_if| Ok(ast::If::new(condition).with_else_if(else_if_optional(else_if)));
+
+    loop {
+        let else_if_token = match state.current() {
+            Ok(else_if_token) if else_if_token.in_symbols(&[Symbol::ElseIf, Symbol::ElIf]) => state.consume().unwrap(),
+            Ok(_) => break,
+            Err(()) => return unfinished_if(condition, else_if),
+        };
+
+        let condition = match parse_expression(state) {
+            ParserResult::Value(condition) => condition,
+            ParserResult::NotFound => {
+                state.token_error(else_if_token, "expected condition after `elseif` or `elif`");
+                return unfinished_if(condition, else_if);
+            }
+            ParserResult::LexerMoved => return unfinished_if(condition, else_if),
+        };
+
+        let Some(then_token) = state.require(Symbol::Then, "expected `then` after condition") else {
+            return unfinished_if(condition, else_if);
+        };
+
+        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),
+        };
+
+        else_if.push(ast::ElseIf { else_if_token, condition, then_token, block: then_block });
+    }
+
+    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)),
+        },
+        None => (None, None),
+    };
+
+    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")
+        }
+        Err(()) => TokenReference::basic_symbol("end"),
+    };
+
+    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,
+    })
+}
+
+fn expect_yield(state: &mut ParserState, yield_token: TokenReference) -> Result<ast::Yield, ()> {
+    match parse_expression_list(state) {
+        ParserResult::Value(expr_list) => Ok(ast::Yield::new().with_token(yield_token).with_yields(expr_list)),
+        ParserResult::LexerMoved | ParserResult::NotFound => {
+            state.token_error(yield_token, "expected an expression to yield");
+            Err(())
+        }
+    }
+}
+
+fn expect_main(state: &mut ParserState, main_token: TokenReference) -> Result<ast::Main, ()> {
+    let initial_variable = state.consume_kind(TokenKind::StringLiteral).ok_or(())?;
+
+    let begin_token = state
+        .require(Symbol::Do, "need to specify the instructions in a list")
+        .ok_or(())?;
+
+    let mut assignements = Vec::new();
+    let (end_token, write_stmt) = loop {
+        if let Some(end_token) = state.consume_if(Symbol::End) {
+            break (end_token, None);
+        } else if let Some(return_token) = state.consume_if(Symbol::Return) {
+            let write_stmt = expect_write_variable(state, return_token)?;
+            break state
+                .require(Symbol::End, "expected no more assignations after the return token")
+                .map(|end_token| (end_token, Some(write_stmt)))
+                .ok_or(())?;
+        }
+        assignements.push(expect_main_assign(state)?);
+    };
+
+    Ok(ast::Main::new(main_token, initial_variable, begin_token, end_token)
+        .with_assignements(assignements)
+        .with_returns(write_stmt))
+}
+
+fn expect_main_assign(state: &mut ParserState) -> Result<ast::MainAssignement, ()> {
+    let dest_token = state.consume_kind(TokenKind::StringLiteral).ok_or(())?;
+    let assign_token = state
+        .require(Symbol::Equal, "expected `=` to assign variable")
+        .ok_or(())?;
+
+    let module = state.consume_kind(TokenKind::Identifier).ok_or(())?;
+    let dot_token = state
+        .require(Symbol::Dot, "expected a dot `.` to get which job from the module to call")
+        .ok_or(())?;
+    let the_job = state.consume_kind(TokenKind::Identifier).ok_or(())?;
+
+    let call_list = expect_call_list(state)
+        .map_err(|()| state.token_error(the_job.clone(), "expected a call list to know how to call the job"))?;
+
+    Ok(ast::MainAssignement::new(assign_token, dest_token, module, dot_token, the_job).with_call_list(call_list))
+}
+
+fn expect_call_list(state: &mut ParserState) -> Result<ast::CallList, ()> {
+    let current = state.current()?;
+
+    let mut items = Punctuated::new();
+    let (mut start_list_token, mut end_list_token) = (None, None);
+    match current.token_type() {
+        TokenType::StringLiteral { .. } => items.push(Pair::End(ast::CallListItem::Variable(state.consume().unwrap()))),
+
+        TokenType::Symbol { symbol: Symbol::LeftBrace } => {
+            start_list_token = state.consume().ok();
+            while let Ok(token) = state.current() {
+                let next_item = match token.token_type() {
+                    TokenType::StringLiteral { .. } => ast::CallListItem::Variable(state.consume().unwrap()),
+
+                    TokenType::Identifier { .. } => {
+                        let parameter = state.consume().unwrap();
+                        let equal_token = state.consume_if(Symbol::Equal).ok_or_else(|| {
+                            state.token_error(parameter.clone(), "expected an assignation with `=` for this parameter")
+                        })?;
+                        let expression = parse_expression(state).ok_or(())?;
+                        ast::CallListItem::SetParameter { parameter, equal_token, expression }
+                    }
+
+                    _ => {
+                        state.token_error(
+                            token.clone(),
+                            "expected a string literal to name a parameter or an assignation",
+                        );
+                        return Err(());
+                    }
+                };
+
+                if let Some(comma_token) = state.consume_if(Symbol::Comma) {
+                    items.push(Pair::Punctuated(next_item, comma_token));
+                    continue;
+                } else if let Some(end_token) = state.consume_if(Symbol::RightBrace) {
+                    items.push(Pair::End(next_item));
+                    end_list_token = Some(end_token);
+                    break;
+                }
+
+                let error_token = state.consume().unwrap_or_else(|| next_item.first_token().clone());
+                state.token_error(
+                    error_token,
+                    "expected symbol '}' or ',' after the variable name or a parameter assignation",
+                );
+                return Err(());
+            }
+        }
+        _ => {
+            state.token_error(current.clone(), "expected a call list for the job");
+            return Err(());
+        }
+    }
+
+    Ok(CallList::new()
+        .with_begin_token(start_list_token)
+        .with_end_token(end_list_token)
+        .with_items(items))
+}
+
+fn expect_write_variable(state: &mut ParserState, write_token: TokenReference) -> Result<ast::Write, ()> {
+    let Ok(current) = state.current() else {
+        state.token_error(write_token, "expected something to write");
+        return Err(());
+    };
+
+    let mut variables = Punctuated::new();
+    let (mut start_list_token, mut end_list_token) = (None, None);
+    match current.token_type() {
+        TokenType::StringLiteral { .. } => variables.push(Pair::End(state.consume().unwrap())),
+
+        TokenType::Symbol { symbol: Symbol::LeftBrace } => {
+            start_list_token = state.consume().ok();
+            while let Ok(token) = state.current() {
+                let next_variable = match token.token_kind() {
+                    TokenKind::StringLiteral => state.consume().unwrap(),
+                    _ => {
+                        state.token_error(token.clone(), "expected a string literal to name a variable");
+                        return Err(());
+                    }
+                };
+
+                if let Some(comma_token) = state.consume_if(Symbol::Comma) {
+                    variables.push(Pair::Punctuated(next_variable, comma_token));
+                    continue;
+                } else if let Some(end_token) = state.consume_if(Symbol::RightBrace) {
+                    variables.push(Pair::End(next_variable));
+                    end_list_token = Some(end_token);
+                    break;
+                }
+
+                let error_token = state.consume().unwrap_or(next_variable);
+                state.token_error(error_token, "expected '}' or ',' after the variable name");
+                return Err(());
+            }
+        }
+
+        _ => {
+            state.token_error(current.clone(), "expected a variable name or a list of variable name");
+            return Err(());
+        }
+    }
+
+    Ok(ast::Write::new(write_token)
+        .with_variables(variables)
+        .with_begin_list_token(start_list_token)
+        .with_end_list_token(end_list_token))
+}
+
+fn expect_option_decl(state: &mut ParserState, option_token: TokenReference) -> Result<ast::OptionDecl, ()> {
+    let mut name_list = Punctuated::<TokenReference>::new();
+    let mut type_specifiers = Vec::<Option<ast::TypeSpecifier>>::new();
+
+    let equal_token = loop {
+        let name = match parse_identifier(state) {
+            ParserResult::Value(name) => name,
+            _ => {
+                state.token_error(state.current()?.clone(), "expected an identifier");
+                return Err(());
+            }
+        };
+
+        type_specifiers.push(match state.consume_if(Symbol::Colon) {
+            Some(colon) => Some(expect_type_specifier(state, colon)?),
+            None => None,
+        });
+
+        if let Some(comma) = state.consume_if(Symbol::Comma) {
+            name_list.push_punctuated(name, comma);
+            continue;
+        } else if let Some(equal) = state.consume_if(Symbol::Equal) {
+            name_list.push(Pair::End(name));
+            break equal;
+        }
+
+        state.token_error(option_token, "invalid option specifier statement");
+        state.token_error(
+            state.current().cloned()?,
+            "expected ',' to continue option list or '=' to assign default values to the list",
+        );
+        return Err(());
+    };
+
+    debug_assert_eq!(name_list.len(), type_specifiers.len());
+
+    let expr_list = match parse_expression_list(state) {
+        ParserResult::Value(expr_list) if name_list.len() != expr_list.len() => {
+            state.token_error(option_token, "expected to assign all declared options");
+            return Err(());
+        }
+        ParserResult::NotFound => {
+            state.token_error(equal_token.clone(), "expected an expression");
+            return Err(());
+        }
+        ParserResult::LexerMoved => return Err(()),
+        ParserResult::Value(expr_list) => expr_list,
+    };
+
+    Ok(ast::OptionDecl { option_token, name_list, type_specifiers, equal_token, expr_list })
+}
+
+fn expect_local_assignment(state: &mut ParserState, local_token: TokenReference) -> Result<ast::LocalAssignment, ()> {
+    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(()),
+    };
+
+    let mut name_list = Punctuated::new();
+    let mut type_specifiers = Vec::new();
+    let mut attributes = Vec::new();
+
+    for name in names.into_pairs() {
+        let (name, punctuation) = name.into_tuple();
+        attributes.push(name.attribute);
+        type_specifiers.push(name.type_specifier);
+        name_list.push(match punctuation {
+            Some(punctuation) => Pair::Punctuated(name.name, punctuation),
+            None => Pair::End(name.name),
+        });
+    }
+
+    let mut local_assignment = ast::LocalAssignment {
+        local_token,
+        name_list,
+        type_specifiers,
+        equal_token: None,
+        expr_list: Punctuated::new(),
+        attributes,
+    };
+
+    local_assignment.equal_token = match state.consume_if(Symbol::Equal) {
+        Some(equal_token) => Some(equal_token),
+        None => return Ok(local_assignment),
+    };
+
+    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")
+        }
+        ParserResult::LexerMoved => {}
+    };
+
+    Ok(local_assignment)
+}
+
+fn expect_expression_key(state: &mut ParserState, left_bracket: TokenReference) -> Result<ast::Field, ()> {
+    let expression = match parse_expression(state) {
+        ParserResult::Value(expression) => expression,
+        ParserResult::NotFound => {
+            state.token_error(left_bracket, "expected an expression after `[`");
+            return Err(());
+        }
+        ParserResult::LexerMoved => return Err(()),
+    };
+
+    let right_bracket = state
+        .require_with_reference_range_callback(Symbol::RightBracket, "expected `]` after expression", || {
+            (left_bracket.clone(), expression.tokens().last().unwrap().clone())
+        })
+        .ok_or(())?;
+
+    // rewrite todo: we can realistically construct a field in error recovery
+    // rewrite todo: this should also be range
+    let equal_token = state
+        .require_with_reference_range(Symbol::Equal, "expected `=` after expression", &left_bracket, &right_bracket)
+        .ok_or(())?;
+
+    let value = match parse_expression(state) {
+        ParserResult::Value(expression) => expression,
+        ParserResult::NotFound => {
+            state.token_error(equal_token, "expected an expression after `=`");
+            return Err(());
+        }
+        ParserResult::LexerMoved => return Err(()),
+    };
+
+    Ok(ast::Field::ExpressionKey {
+        brackets: ContainedSpan::new(left_bracket, right_bracket),
+        key: expression,
+        equal: equal_token,
+        value,
+    })
+}
+
+fn force_table_constructor(state: &mut ParserState, left_brace: TokenReference) -> ast::TableConstructor {
+    let mut fields = Punctuated::new();
+    let unfinished_table = |left_brace: TokenReference, fields: Punctuated<ast::Field>| ast::TableConstructor {
+        braces: ContainedSpan::new(left_brace, TokenReference::basic_symbol("}")),
+        fields,
+    };
+
+    loop {
+        let Ok(current_token) = state.current() else {
+            return unfinished_table(left_brace, fields);
+        };
+
+        let field = match current_token.token_type() {
+            TokenType::Symbol { symbol: Symbol::RightBrace } => {
+                return ast::TableConstructor {
+                    braces: ContainedSpan::new(left_brace, state.consume().unwrap()),
+                    fields,
+                }
+            }
+
+            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),
+                }
+            }
+
+            TokenType::Identifier { .. } if matches!(state.peek(), Ok(peek_token) if peek_token.is_symbol(Symbol::Equal)) =>
+            {
+                let key = state.consume().unwrap();
+                let equal_token = state.consume().unwrap();
+                let value = match parse_expression(state) {
+                    ParserResult::Value(expression) => expression,
+                    ParserResult::NotFound => {
+                        state.token_error(equal_token, "expected an expression after `=`");
+                        return unfinished_table(left_brace, fields);
+                    }
+                    ParserResult::LexerMoved => return unfinished_table(left_brace, fields),
+                };
+                ast::Field::NameKey { key, equal: equal_token, value }
+            }
+
+            _ => ast::Field::NoKey(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),
+            }),
+        };
+
+        match state.current() {
+            Ok(token) => {
+                if token.in_symbols(&[Symbol::Comma, 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<ast::Stmt, ()> {
+    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<ast::While, ()> {
+    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 })
+}
+
+fn expect_type_declaration(state: &mut ParserState, type_token: TokenReference) -> Result<ast::TypeDeclaration, ()> {
+    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 equal_token = state
+        .require(Symbol::Equal, "expected `=` after type name")
+        .unwrap_or_else(|| TokenReference::basic_symbol("="));
+
+    let declare_as = parse_type(state).ok_or(())?;
+
+    Ok(ast::TypeDeclaration { type_token, base, equal_token, declare_as })
+}
+
+fn parse_prefix(state: &mut ParserState) -> ParserResult<ast::Prefix> {
+    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<ast::FunctionArgs> {
+    let Ok(current) = state.current() else {
+        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<ast::Suffix> {
+    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<ast::Suffix>)> {
+    let prefix = match parse_prefix(state) {
+        ParserResult::Value(prefix) => prefix,
+        ParserResult::LexerMoved => return ParserResult::LexerMoved,
+        ParserResult::NotFound => return ParserResult::NotFound,
+    };
+    let suffixes = std::iter::from_fn(|| parse_suffix(state).ok()).collect();
+    ParserResult::Value((prefix, suffixes))
+}
+
+fn parse_expression(state: &mut ParserState) -> ParserResult<Expression> {
+    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<Expression> {
+    let Ok(current_token) = state.current() else {
+        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(Box::new((function_token, function_body))))
+        }
+
+        TokenType::Symbol { symbol: Symbol::True | Symbol::False | Symbol::Nil } => {
+            ParserResult::Value(Expression::Symbol(state.consume().unwrap()))
+        }
+
+        TokenType::StringLiteral { .. } => ParserResult::Value(Expression::String(state.consume().unwrap())),
+        TokenType::Number { .. } => ParserResult::Value(Expression::Number(state.consume().unwrap())),
+
+        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,
+                }))))
+            }
+        }
+
+        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)
+        }
+
+        TokenType::Symbol { symbol: Symbol::LeftBrace } => {
+            let left_brace = state.consume().unwrap();
+            ParserResult::Value(ast::Expression::TableConstructor(force_table_constructor(state, left_brace)))
+        }
+
+        TokenType::Symbol { symbol: Symbol::If } => {
+            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,
+            }
+        }
+
+        _ => ParserResult::NotFound,
+    };
+
+    match expression {
+        ParserResult::Value(expression) => {
+            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<Expression> {
+    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 {
+                bin_op_precedence + 1
+            } else if ast::BinOp::is_right_associative_token(next_bin_op_token)
+                && next_bin_op_precedence == bin_op_precedence
+            {
+                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<ast::Expression> {
+    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),
+            Symbol::Tilde => ast::UnOp::Tilde(unary_operator_token),
+            _ => unreachable!(),
+        },
+
+        _ => unreachable!(),
+    };
+
+    let primary_expression = match parse_primary_expression(state) {
+        ParserResult::Value(expression) => expression,
+        ParserResult::NotFound => {
+            state.token_error(
+                unary_operator.token().clone(),
+                format!("expected an expression after {}", unary_operator.token().token()),
+            );
+            return ParserResult::NotFound;
+        }
+        ParserResult::LexerMoved => return ParserResult::LexerMoved,
+    };
+
+    let expression = match parse_expression_with_precedence(state, primary_expression, ast::UnOp::precedence()) {
+        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<FunctionBody> {
+    let Some(left_parenthesis) = state.consume_if(Symbol::LeftParen) else {
+        return ParserResult::NotFound;
+    };
+
+    let mut parameters = Punctuated::new();
+    let mut type_specifiers = Vec::new();
+    let right_parenthesis;
+
+    let unfinished_function_body = |left_parenthesis: TokenReference, mut parameters: Punctuated<Parameter>| {
+        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 type_specifiers here but it
+        // becomes messy with cfg feature toggles and moves.
+        ParserResult::Value(FunctionBody {
+            parameters_parentheses: ContainedSpan::new(left_parenthesis, TokenReference::basic_symbol(")")),
+            parameters,
+            type_specifiers: Vec::new(), // rewrite todo: fix
+            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(TokenReference { token: Token { token_type: TokenType::Identifier { .. }, .. }, .. }) => {
+                let name_parameter = match parse_name_with_type_specifiers(state) {
+                    ParserResult::Value(Name { name, type_specifier, .. }) => {
+                        type_specifiers.push(type_specifier);
+                        ast::Parameter { 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(), "trailing commas in arguments are not allowed");
+        parameters.push(Pair::End(last_parameter.into_value()));
+    }
+
+    let return_type = 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
+    };
+
+    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 {
+        parameters_parentheses: ContainedSpan::new(left_parenthesis, right_parenthesis),
+        parameters,
+        type_specifiers,
+        return_type,
+        block,
+        end_token: end,
+    })
+}
+
+fn expect_if_else_expression(state: &mut ParserState, if_token: TokenReference) -> Result<ast::IfExpression, ()> {
+    let condition = parse_expression(state).ok_or(())?;
+    let then_token = state
+        .require(Symbol::Then, "expected `then` after condition")
+        .ok_or(())?;
+    let if_expression = parse_expression(state).ok_or(())?;
+
+    let mut else_if_expressions = Vec::new();
+    while let Some(else_if_token) = state.consume_ifs(&[Symbol::ElseIf, Symbol::ElIf]) {
+        let condition = parse_expression(state).ok_or(())?;
+        let then_token = state
+            .require(Symbol::Then, "expected `then` after condition")
+            .ok_or(())?;
+        let expression = parse_expression(state).ok_or(())?;
+        else_if_expressions.push(ast::ElseIfExpression { else_if_token, condition, then_token, expression })
+    }
+
+    let else_token = state
+        .require(Symbol::Else, "expected `else` to end if-else expression")
+        .ok_or(())?;
+    let else_expression = parse_expression(state).ok_or(())?;
+
+    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),
+    })
+}
+
+fn parse_type(state: &mut ParserState) -> ParserResult<ast::TypeInfo> {
+    let ParserResult::Value(simple_type) = parse_simple_type(state) else {
+        return ParserResult::LexerMoved;
+    };
+
+    let mut current_type = simple_type;
+    while let Some(question_mark) = state.consume_if(Symbol::QuestionMark) {
+        current_type = ast::TypeInfo::Optional { base: Box::new(current_type), question_mark };
+    }
+    ParserResult::Value(current_type)
+}
+
+fn parse_simple_type(state: &mut ParserState) -> ParserResult<ast::TypeInfo> {
+    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::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 {
+                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 } => match expect_function_type(state) {
+            Ok(type_info) => ParserResult::Value(type_info),
+            Err(_) => ParserResult::LexerMoved,
+        },
+        _ => ParserResult::NotFound,
+    }
+}
+
+fn expect_type_table(state: &mut ParserState, left_brace: TokenReference) -> Result<ast::TypeInfo, ()> {
+    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) {
+            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 right_brace = state
+                .require(Symbol::RightBracket, "expected `]` to close `[` for type table field")
+                .ok_or(())?;
+            let colon = state
+                .require(Symbol::Colon, "expected `:` after type field key")
+                .ok_or(())?;
+
+            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 colon = state
+                        .require(Symbol::Colon, "expected `:` after type field key")
+                        .ok_or(())?;
+                    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(()),
+            }
+        };
+
+        match state.current() {
+            Ok(token) => {
+                if token.in_symbols(&[Symbol::Comma, 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 = 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 })
+    }
+}
+
+fn expect_function_type(state: &mut ParserState) -> Result<ast::TypeInfo, ()> {
+    let mut arguments = Punctuated::new();
+    let left_paren = state.require(Symbol::LeftParen, "expected `(`").ok_or(())?;
+
+    while !matches!(state.current(), Ok(token) if token.is_symbol(Symbol::RightParen)) {
+        let current_token = state.current()?;
+        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 type_info = parse_type(state).ok_or(())?;
+        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 right_paren = state
+        .require(Symbol::RightParen, "expected `)` to close `(`")
+        .ok_or(())?;
+
+    let parentheses = ContainedSpan::new(left_paren, right_paren);
+
+    if !arguments.iter().any(|arg: &ast::TypeArgument| arg.name().is_some())
+        && !matches!(state.current(), Ok(token) if token.is_symbol(Symbol::ThinArrow))
+        && !arguments.is_empty()
+    {
+        let types = arguments
+            .into_pairs()
+            .map(|pair| pair.map(|argument| argument.type_info))
+            .collect();
+        return Ok(ast::TypeInfo::Tuple { parentheses, types });
+    }
+
+    let arrow = state
+        .require(Symbol::ThinArrow, "expected `->` after `()` for function type")
+        .ok_or(())?;
+    let return_type = parse_return_type(state).ok_or(())?;
+
+    Ok(ast::TypeInfo::Callback { parentheses, arguments, arrow, return_type: Box::new(return_type) })
+}
+
+fn expect_type_specifier(state: &mut ParserState, punctuation: TokenReference) -> Result<ast::TypeSpecifier, ()> {
+    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 })
+}
+
+fn parse_return_type(state: &mut ParserState) -> ParserResult<ast::TypeInfo> {
+    parse_type(state)
+        .ok()
+        .map(ParserResult::Value)
+        .unwrap_or(ParserResult::LexerMoved)
+}
+
+#[derive(Clone)]
+struct Name {
+    name: TokenReference,
+    attribute: Option<super::Attribute>,
+    type_specifier: Option<ast::TypeSpecifier>,
+}
+
+fn parse_name(state: &mut ParserState) -> ParserResult<Name> {
+    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_identifier(state: &mut ParserState) -> ParserResult<TokenReference> {
+    let Ok(current_token) = state.current() else {
+        return ParserResult::NotFound;
+    };
+    let token = match current_token.token_type() {
+        TokenType::Identifier { .. } => state.consume().unwrap(),
+        _ => {
+            state.token_error(current_token.clone(), "expected an identifier");
+            return ParserResult::NotFound;
+        }
+    };
+    ParserResult::Value(token)
+}
+
+fn parse_name_with_attributes(state: &mut ParserState) -> ParserResult<Name> {
+    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<Name> {
+    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, attribute: None, type_specifier: None }
+}
+
+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 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(),
+            Ok(token) => {
+                state.token_error_ranged(token.clone(), ERROR_INVALID_ATTRIBUTE, &left_angle_bracket, &token.clone());
+                return Name { name, attribute: None, type_specifier: None };
+            }
+            Err(()) => {
+                state.token_error(left_angle_bracket, ERROR_INVALID_ATTRIBUTE);
+                return Name { name, attribute: None, type_specifier: None };
+            }
+        };
+
+        let Some(right_angle_bracket) = state.require(Symbol::GreaterThan, "expected `>` to close attribute") else {
+            return Name {
+                name,
+                attribute: Some(super::Attribute {
+                    brackets: ContainedSpan::new(left_angle_bracket, TokenReference::basic_symbol(">")),
+                    name: attribute_name,
+                }),
+                type_specifier: None,
+            };
+        };
+
+        return Name {
+            name,
+            attribute: Some(super::Attribute {
+                brackets: ContainedSpan::new(left_angle_bracket, right_angle_bracket),
+                name: attribute_name,
+            }),
+            type_specifier: None,
+        };
+    }
+
+    force_name_with_type_specifiers(state, name)
+}
+
+fn force_name_with_type_specifiers(state: &mut ParserState, name: TokenReference) -> Name {
+    match state.consume_if(Symbol::Colon).map(|p| expect_type_specifier(state, p)) {
+        Some(Ok(type_specifier)) => Name { name, attribute: None, type_specifier: Some(type_specifier) },
+        Some(Err(())) => Name { name, attribute: None, type_specifier: None },
+        None => force_name(state, name),
+    }
+}
+
+fn one_or_more<T, F: Fn(&mut ParserState) -> ParserResult<T>>(
+    state: &mut ParserState,
+    parser: F,
+    delimiter: Symbol,
+) -> ParserResult<Punctuated<T>> {
+    let mut values = Punctuated::new();
+
+    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)),
+            None => {
+                values.push(Pair::End(value));
+                break;
+            }
+        }
+    }
+
+    if values.is_empty() {
+        return ParserResult::NotFound;
+    }
+
+    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()));
+    }
+
+    ParserResult::Value(values)
+}
+
+fn parse_name_list(state: &mut ParserState) -> ParserResult<Punctuated<Name>> {
+    one_or_more(state, parse_name_with_type_specifiers, Symbol::Comma)
+}
+
+fn parse_expression_list(state: &mut ParserState) -> ParserResult<Punctuated<Expression>> {
+    one_or_more(state, parse_expression, Symbol::Comma)
+}
diff --git a/src/Rust/vvs_parser/src/ast/parsers/structs/ast_result.rs b/src/Rust/vvs_parser/src/ast/parsers/structs/ast_result.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9d4ab19016b2c7943a8ab7ee084b9ddd03b6da87
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/parsers/structs/ast_result.rs
@@ -0,0 +1,117 @@
+use crate::{
+    ast::{
+        parsers::{parse_block, ParserResult, ParserState},
+        Ast,
+    },
+    tokenizer::{Lexer, LexerResult, TokenKind},
+};
+
+/// 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<crate::Error>,
+}
+
+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) -> Self {
+        use crate::{ast::AstError, Error};
+        const UNEXPECTED_TOKEN_ERROR: &str = "unexpected token, this needs to be a statement";
+
+        let lexer = Lexer::new(code);
+        let mut parser_state = ParserState::new(lexer);
+        let mut block = parse_block(&mut parser_state).unwrap_or_defaut();
+
+        loop {
+            match parser_state.lexer.current() {
+                Some(LexerResult::Ok(token)) if token.token_kind() == TokenKind::Eof => break,
+                Some(LexerResult::Ok(_) | LexerResult::Recovered(_, _)) => {
+                    let ParserResult::Value(new_block) = parse_block(&mut parser_state) else {
+                        continue;
+                    };
+                    if new_block.stmts.is_empty() {
+                        match parser_state.current() {
+                            Ok(token) if token.token_kind() == TokenKind::Eof => break,
+                            _ => {}
+                        }
+                        match parser_state.consume() {
+                            ParserResult::Value(token) => match parser_state.errors.last() {
+                                Some(Error::AstError(AstError { additional, .. }))
+                                    if additional == UNEXPECTED_TOKEN_ERROR =>
+                                {
+                                    continue
+                                }
+                                Some(Error::AstError(AstError { .. })) => {
+                                    parser_state.token_error(token, UNEXPECTED_TOKEN_ERROR)
+                                }
+                                _ => parser_state.token_error(token, UNEXPECTED_TOKEN_ERROR),
+                            },
+                            ParserResult::LexerMoved => {}
+                            ParserResult::NotFound => unreachable!(),
+                        }
+                        continue;
+                    }
+                    block.merge_blocks(new_block);
+                }
+                Some(LexerResult::Fatal(_)) => parser_state.errors.extend(
+                    Option::unwrap(parser_state.lexer.consume())
+                        .unwrap_errors()
+                        .into_iter()
+                        .map(Error::TokenizerError),
+                ),
+                None => break,
+            }
+        }
+
+        let eof = match parser_state.lexer.consume().unwrap() {
+            LexerResult::Ok(token) => token,
+            LexerResult::Recovered(token, errors) => {
+                parser_state
+                    .errors
+                    .extend(errors.into_iter().map(Error::TokenizerError));
+                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<Ast, Vec<crate::Error>> {
+        self.into()
+    }
+}
+
+impl From<AstResult> for Result<Ast, Vec<crate::Error>> {
+    fn from(ast_result: AstResult) -> Self {
+        if ast_result.errors.is_empty() {
+            Ok(ast_result.ast)
+        } else {
+            Err(ast_result.errors)
+        }
+    }
+}
diff --git a/src/Rust/vvs_parser/src/ast/parsers/structs/mod.rs b/src/Rust/vvs_parser/src/ast/parsers/structs/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6dc9ff1913beae8732b50b1dd3fabdefbd8429f6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/parsers/structs/mod.rs
@@ -0,0 +1,148 @@
+use crate::{
+    tokenizer::{Lexer, LexerResult, Symbol, TokenKind, TokenReference},
+    traits::MaybeLazyString,
+};
+use std::borrow::Cow;
+
+mod ast_result;
+mod option_table_result;
+mod result;
+
+pub use crate::ast::parsers::structs::{ast_result::*, option_table_result::*, result::*};
+
+pub struct ParserState {
+    errors: Vec<crate::Error>,
+    lexer: Lexer,
+}
+
+impl ParserState {
+    pub fn new(lexer: Lexer) -> Self {
+        Self { errors: Vec::new(), lexer }
+    }
+
+    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<TokenReference> {
+        match self.lexer.consume() {
+            Some(LexerResult::Ok(token)) => ParserResult::Value(token),
+            Some(LexerResult::Recovered(token, errors)) => {
+                self.errors.extend(errors.into_iter().map(crate::Error::TokenizerError));
+                ParserResult::Value(token)
+            }
+            Some(LexerResult::Fatal(errors)) => {
+                self.errors.extend(errors.into_iter().map(crate::Error::TokenizerError));
+                ParserResult::LexerMoved
+            }
+            None => ParserResult::NotFound,
+        }
+    }
+
+    pub fn consume_ifs(&mut self, symbols: &[Symbol]) -> Option<TokenReference> {
+        symbols.iter().copied().find_map(|symbol| self.consume_if(symbol))
+    }
+
+    pub fn consume_if(&mut self, symbol: Symbol) -> Option<TokenReference> {
+        self.current().ok()?.is_symbol(symbol).then(|| self.consume().unwrap())
+    }
+
+    pub fn consume_kind(&mut self, kind: TokenKind) -> Option<TokenReference> {
+        if self.current().ok()?.is_kind(kind) {
+            Some(self.consume().unwrap())
+        } else {
+            self.token_error(self.current().unwrap().clone(), format!("expected a token of type {kind:?}"));
+            None
+        }
+    }
+
+    pub fn require(&mut self, symbol: Symbol, error: &'static str) -> Option<TokenReference> {
+        if self.current().ok()?.is_symbol(symbol) {
+            Some(self.consume().unwrap())
+        } else {
+            self.token_error(self.current().ok()?.clone(), error);
+            None
+        }
+    }
+
+    pub fn require_with_reference_token(
+        &mut self,
+        symbol: Symbol,
+        error: &'static str,
+        reference_token: &TokenReference,
+    ) -> Option<TokenReference> {
+        if self.current().ok()?.is_symbol(symbol) {
+            Some(self.consume().unwrap())
+        } else {
+            self.token_error(reference_token.clone(), error);
+            None
+        }
+    }
+
+    pub fn require_with_reference_range(
+        &mut self,
+        symbol: Symbol,
+        error: impl MaybeLazyString,
+        start_token: &TokenReference,
+        end_token: &TokenReference,
+    ) -> Option<TokenReference> {
+        let token = self.current().ok()?;
+        if token.is_symbol(symbol) {
+            Some(self.consume().unwrap())
+        } else {
+            self.token_error_ranged(token.clone(), error.to_str(), start_token, end_token);
+            None
+        }
+    }
+
+    pub fn require_with_reference_range_callback(
+        &mut self,
+        symbol: Symbol,
+        error: impl MaybeLazyString,
+        tokens: impl FnOnce() -> (TokenReference, TokenReference),
+    ) -> Option<TokenReference> {
+        let token = self.current().ok()?;
+        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
+        }
+    }
+
+    pub fn token_error(&mut self, token_reference: TokenReference, error: impl Into<Cow<'static, str>>) {
+        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: impl Into<Cow<'static, str>>,
+        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())),
+        }));
+    }
+}
diff --git a/src/Rust/vvs_parser/src/ast/parsers/structs/option_table_result.rs b/src/Rust/vvs_parser/src/ast/parsers/structs/option_table_result.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8c8a260e3c3a8abe596ac9b0b72397e93aded7b8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/parsers/structs/option_table_result.rs
@@ -0,0 +1,56 @@
+use crate::{
+    ast::{
+        parsers::{parse_option_table, ParserState},
+        OptionTable,
+    },
+    tokenizer::Lexer,
+};
+
+/// A produced [`OptionTable`](crate::ast::OptionTable), along with any errors found during
+/// parsing. This option table may not be exactly the same as the input code, as reconstruction may
+/// have occurred. For more information.
+pub struct OptionTableResult {
+    option_table: OptionTable,
+    errors: Vec<crate::Error>,
+}
+
+impl OptionTableResult {
+    /// Returns a reference to the [OptionTable] that was parsed. If there were any errors, this
+    /// will not be exactly the same, as reconstruction will have occurred.
+    pub fn option_table(&self) -> &OptionTable {
+        &self.option_table
+    }
+
+    /// Consumes the [OptionTable] that was parsed. If there were any errors, this will not be
+    /// exactly the same, as reconstruction will have occurred.
+    pub fn into_option_table(self) -> OptionTable {
+        self.option_table
+    }
+
+    /// Returns all errors that occurred during parsing.
+    pub fn errors(&self) -> &[crate::Error] {
+        &self.errors
+    }
+
+    pub(crate) fn parse_fallible(code: &str) -> Self {
+        let lexer = Lexer::new(code);
+        let mut parser_state = ParserState::new(lexer);
+        let option_table = parse_option_table(&mut parser_state).unwrap_or_defaut();
+        Self { option_table, errors: parser_state.errors }
+    }
+
+    /// Consumes this OptionTableResult, returning the [OptionTable] that was parsed.
+    pub fn into_result(self) -> Result<OptionTable, Vec<crate::Error>> {
+        self.into()
+    }
+}
+
+impl From<OptionTableResult> for Result<OptionTable, Vec<crate::Error>> {
+    fn from(result: OptionTableResult) -> Self {
+        if result.errors.is_empty() {
+            Ok(result.option_table)
+        } else {
+            Err(result.errors)
+        }
+    }
+}
diff --git a/src/Rust/vvs_parser/src/ast/parsers/structs/result.rs b/src/Rust/vvs_parser/src/ast/parsers/structs/result.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8231bb824dbf22209d450654822009d58fc81bf8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/parsers/structs/result.rs
@@ -0,0 +1,57 @@
+#[derive(Debug)]
+pub enum ParserResult<T> {
+    // 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<T> ParserResult<T> {
+    pub fn ok(self) -> Option<T> {
+        match self {
+            ParserResult::Value(value) => Some(value),
+            ParserResult::LexerMoved | ParserResult::NotFound => None,
+        }
+    }
+
+    pub fn ok_or<E>(self, error: E) -> Result<T, E> {
+        self.ok().ok_or(error)
+    }
+
+    pub fn expect(self, msg: &str) -> T {
+        self.ok().expect(msg)
+    }
+
+    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"),
+        }
+    }
+
+    pub fn unwrap_or(self, default: T) -> T {
+        match self {
+            ParserResult::Value(value) => value,
+            _ => default,
+        }
+    }
+
+    pub fn unwrap_or_else(self, cb: impl FnOnce() -> T) -> T {
+        match self {
+            ParserResult::Value(value) => value,
+            _ => cb(),
+        }
+    }
+}
+
+impl<T: Default> ParserResult<T> {
+    pub fn unwrap_or_defaut(self) -> T {
+        self.unwrap_or_else(Default::default)
+    }
+}
diff --git a/src/Rust/vvs_parser/src/ast/parsers/util.rs b/src/Rust/vvs_parser/src/ast/parsers/util.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1daef7139999e194144b0350da0fc391af865a5d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/parsers/util.rs
@@ -0,0 +1,16 @@
+// Consumes a ParserResult into an Option<T>.
+// 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! try_parser {
+    ($result:expr) => {{
+        use $crate::ast::parsers::ParserResult;
+        match $result {
+            ParserResult::Value(value) => Some(value),
+            ParserResult::NotFound => None,
+            ParserResult::LexerMoved => return ParserResult::LexerMoved,
+        }
+    }};
+}
diff --git a/src/Rust/vvs_parser/src/ast/punctuated.rs b/src/Rust/vvs_parser/src/ast/punctuated.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cb070f68f3c502458ad97a7220b3e112f553c865
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/punctuated.rs
@@ -0,0 +1,487 @@
+//! A punctuated sequence of syntax tree nodes separated by punctuation (tokens).
+//!
+//! Examples of punctuated sequences include:
+//! - Arguments in a function call are `Punctuated<Expression>`
+//! - Names and definitions in a local assignment are `Punctuated<TokenReference>` and `Punctuated<Expression>` respectively
+//! - The values of a return statement are `Punctuated<Expression>`
+//!
+//! Everything with punctuation uses the [`Punctuated<T>`](Punctuated) type with the following logic.
+
+use crate::{
+    node::{Node, TokenItem, Tokens},
+    private::Sealed,
+    tokenizer::{Position, TokenReference},
+    util,
+    visitors::{Visit, VisitMut, Visitor, VisitorMut},
+};
+use derive_more::Display;
+use serde::{Deserialize, Serialize};
+use std::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, Display, PartialEq, Eq, Deserialize, Serialize)]
+#[display(bound(T: Display))]
+#[display("{}", util::join_vec(pairs))]
+pub struct Punctuated<T> {
+    pairs: Vec<Pair<T>>,
+}
+
+impl<T> Punctuated<T> {
+    /// Creates an empty punctuated sequence
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated: Punctuated<i32> = Punctuated::new();
+    /// ```
+    pub const fn new() -> Self {
+        Self { pairs: Vec::new() }
+    }
+
+    /// Constructs a new, empty [Punctuated<T>] with at least the specified capacity.
+    ///
+    /// The vector will be able to hold at least `capacity` elements without
+    /// reallocating. This method is allowed to allocate for more elements than
+    /// `capacity`. If `capacity` is 0, the vector will not allocate.
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::<bool>::with_capacity(10);
+    /// assert!(punctuated.is_empty());
+    /// ```
+    pub fn with_capacity(capacity: usize) -> Self {
+        Self { pairs: Vec::with_capacity(capacity) }
+    }
+
+    /// Returns whether there's any nodes in the punctuated sequence
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::new();
+    /// assert!(punctuated.is_empty());
+    /// punctuated.push(Pair::new((), None));
+    /// assert!(!punctuated.is_empty());
+    /// ```
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Returns the number of pairs in the punctuated sequence
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::new();
+    /// assert_eq!(punctuated.len(), 0);
+    /// punctuated.push(Pair::new((), None));
+    /// assert_eq!(punctuated.len(), 1);
+    /// ```
+    pub fn len(&self) -> usize {
+        self.pairs.len()
+    }
+
+    /// Returns an iterator over references of the sequence values, ignoring punctuation
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::new();
+    /// punctuated.push(Pair::new(1, None));
+    /// let mut iterator = punctuated.iter();
+    /// assert_eq!(iterator.next(), Some(&1));
+    /// assert_eq!(iterator.next(), None);
+    /// ```
+    pub fn iter(&self) -> Iter<'_, T> {
+        self.into_iter()
+    }
+
+    /// Returns an iterator over mutable references of the sequence values, ignoring punctuation
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::new();
+    /// punctuated.push(Pair::new(1, None));
+    /// for item in punctuated.iter_mut() {
+    ///     *item += 1;
+    /// }
+    /// assert_eq!(punctuated.pop(), Some(Pair::new(2, None)));
+    /// ```
+    pub fn iter_mut(&mut self) -> IterMut<'_, T> {
+        self.into_iter()
+    }
+
+    /// Returns an iterator over pairs
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::new();
+    /// punctuated.push(Pair::new(1, None));
+    /// let mut iterator = punctuated.into_pairs();
+    /// assert_eq!(iterator.next(), Some(Pair::new(1, None)));
+    /// assert_eq!(iterator.next(), None);
+    /// ```
+    pub fn into_pairs(self) -> impl Iterator<Item = Pair<T>> {
+        self.pairs.into_iter()
+    }
+
+    /// Returns the first pair in the sequence
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::new();
+    /// assert_eq!(punctuated.first(), None);
+    /// punctuated.push(Pair::new(1, None));
+    /// assert_eq!(punctuated.first(), Some(&Pair::new(1, None)));
+    /// ```
+    pub fn first(&self) -> Option<&Pair<T>> {
+        self.pairs.first()
+    }
+
+    /// Returns the last pair in the sequence
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::new();
+    /// punctuated.push(Pair::new(1, None));
+    /// assert_eq!(punctuated.last(), Some(&Pair::new(1, None)));
+    /// ```
+    pub fn last(&self) -> Option<&Pair<T>> {
+        self.pairs.last()
+    }
+
+    /// Returns an iterator over pairs as references
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::new();
+    /// punctuated.push(Pair::new(1, None));
+    /// let mut iterator = punctuated.pairs();
+    /// assert_eq!(iterator.next(), Some(&Pair::new(1, None)));
+    /// assert_eq!(iterator.next(), None);
+    /// ```
+    pub fn pairs(&self) -> impl Iterator<Item = &Pair<T>> {
+        self.pairs.iter()
+    }
+
+    /// Returns an iterator over pairs as mutable references
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::new();
+    /// punctuated.push(Pair::new(1, None));
+    /// for item in punctuated.pairs_mut() {
+    ///     *item.value_mut() += 1;
+    /// }
+    /// assert_eq!(punctuated.pop(), Some(Pair::new(2, None)));
+    /// ```
+    pub fn pairs_mut(&mut self) -> impl Iterator<Item = &mut Pair<T>> {
+        self.pairs.iter_mut()
+    }
+
+    /// Pops off the last pair if it isn't empty
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::new();
+    /// punctuated.push(Pair::new(1, None));
+    /// assert_eq!(punctuated.pop(), Some(Pair::new(1, None)));
+    /// ```
+    pub fn pop(&mut self) -> Option<Pair<T>> {
+        self.pairs.pop()
+    }
+
+    /// Pushes a new pair onto the sequence
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut punctuated = Punctuated::new();
+    /// punctuated.push(Pair::new(1, None));
+    /// assert_eq!(punctuated.pop(), Some(Pair::new(1, None)));
+    /// ```
+    pub fn push(&mut self, pair: Pair<T>) {
+        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<T> Default for Punctuated<T> {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl<T> Sealed for Punctuated<T> {}
+
+impl<T: Node> Node for Punctuated<T> {
+    fn start_position(&self) -> Option<Position> {
+        self.pairs.first()?.start_position()
+    }
+
+    fn end_position(&self) -> Option<Position> {
+        self.pairs.last()?.end_position()
+    }
+
+    fn similar(&self, other: &Self) -> bool {
+        self.into_iter()
+            .collect::<Vec<_>>()
+            .similar(&other.into_iter().collect::<Vec<_>>())
+    }
+
+    fn tokens(&self) -> Tokens {
+        self.pairs.tokens()
+    }
+}
+
+impl<T: Visit> Visit for Punctuated<T> {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        self.pairs.visit(visitor);
+    }
+}
+
+impl<T: VisitMut> VisitMut for Punctuated<T> {
+    fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self {
+        Punctuated { pairs: self.pairs.visit_mut(visitor) }
+    }
+}
+
+impl<T> std::iter::Extend<Pair<T>> for Punctuated<T> {
+    fn extend<I: IntoIterator<Item = Pair<T>>>(&mut self, iter: I) {
+        self.pairs.extend(iter);
+    }
+}
+
+impl<T> IntoIterator for Punctuated<T> {
+    type Item = T;
+    type IntoIter = IntoIter<T>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        IntoIter { inner: self.pairs.into_iter() }
+    }
+}
+
+impl<T> FromIterator<Pair<T>> for Punctuated<T> {
+    fn from_iter<I: IntoIterator<Item = Pair<T>>>(iter: I) -> Self {
+        Punctuated { pairs: iter.into_iter().collect() }
+    }
+}
+
+impl<'a, T> IntoIterator for &'a Punctuated<T> {
+    type Item = &'a T;
+    type IntoIter = Iter<'a, T>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        Iter { inner: self.pairs.iter() }
+    }
+}
+
+impl<'a, T> IntoIterator for &'a mut Punctuated<T> {
+    type Item = &'a mut T;
+    type IntoIter = IterMut<'a, T>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        IterMut { inner: self.pairs.iter_mut() }
+    }
+}
+
+/// An iterator over owned values of type `T`.
+/// Refer to the [module documentation](index.html) for more details.
+pub struct IntoIter<T> {
+    inner: std::vec::IntoIter<Pair<T>>,
+}
+
+impl<T> Iterator for IntoIter<T> {
+    type Item = T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        Some(self.inner.next()?.into_value())
+    }
+}
+
+/// An iterator over borrowed values of type `&T`.
+/// Refer to the [module documentation](index.html) for more details.
+pub struct Iter<'a, T> {
+    inner: std::slice::Iter<'a, Pair<T>>,
+}
+
+impl<'a, T> Iterator for Iter<'a, T> {
+    type Item = &'a T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        Some(self.inner.next()?.value())
+    }
+}
+
+/// An iterator over borrowed values of type `&mut T`.
+/// Refer to the [module documentation](index.html) for more details.
+pub struct IterMut<'a, T> {
+    inner: std::slice::IterMut<'a, Pair<T>>,
+}
+
+impl<'a, T> Iterator for IterMut<'a, T> {
+    type Item = &'a mut T;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        Some(self.inner.next()?.value_mut())
+    }
+}
+
+/// A node `T` followed by the possible trailing
+/// [`TokenReference`](crate::tokenizer::TokenReference).
+/// Refer to the [module documentation](index.html) for more details.
+#[derive(Clone, Debug, Display, PartialEq, Eq, Deserialize, Serialize)]
+#[display(bound(T: Display))]
+pub enum Pair<T> {
+    /// A node `T` with no trailing punctuation
+    #[display("{_0}")]
+    End(T),
+
+    /// A node `T` followed by punctuation (in the form of a
+    /// [`TokenReference`](crate::tokenizer::TokenReference))
+    #[display("{_0}{_1}")]
+    Punctuated(T, TokenReference),
+}
+
+impl<T> Pair<T> {
+    /// Creates a `Pair` with node `T` and optional punctuation
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let pair = Pair::new(1, None);
+    /// ```
+    pub fn new(value: T, punctuation: Option<TokenReference>) -> Self {
+        match punctuation {
+            None => Pair::End(value),
+            Some(punctuation) => Pair::Punctuated(value, punctuation),
+        }
+    }
+
+    /// Takes the `Pair` and returns the node `T` and the punctuation, if it exists as a tuple
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let pair = Pair::new(1, None);
+    /// assert_eq!(pair.into_tuple(), (1, None));
+    /// ```
+    pub fn into_tuple(self) -> (T, Option<TokenReference>) {
+        match self {
+            Pair::End(value) => (value, None),
+            Pair::Punctuated(value, punctuation) => (value, Some(punctuation)),
+        }
+    }
+
+    /// Takes the `Pair` and returns the node `T`
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let pair = Pair::new(1, None);
+    /// assert_eq!(pair.into_value(), 1);
+    /// ```
+    pub fn into_value(self) -> T {
+        self.into_tuple().0
+    }
+
+    /// Returns a reference to the node `T`
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let pair = Pair::new(1, None);
+    /// assert_eq!(pair.value(), &1);
+    /// ```
+    pub fn value(&self) -> &T {
+        match self {
+            Pair::End(value) => value,
+            Pair::Punctuated(value, _) => value,
+        }
+    }
+
+    /// Returns a mutable reference to the node `T`
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let mut pair = Pair::new(1, None);
+    /// *pair.value_mut() += 1;
+    /// assert_eq!(pair.into_value(), 2);
+    /// ```
+    pub fn value_mut(&mut self) -> &mut T {
+        match self {
+            Pair::End(value) => value,
+            Pair::Punctuated(value, _) => value,
+        }
+    }
+
+    /// Returns the trailing punctuation, if it exists
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let pair = Pair::new(1, None);
+    /// assert_eq!(pair.punctuation(), None);
+    /// ```
+    pub fn punctuation(&self) -> Option<&TokenReference> {
+        match self {
+            Pair::End(_) => None,
+            Pair::Punctuated(_, punctuation) => Some(punctuation),
+        }
+    }
+
+    /// Maps a `Pair<T>` to a `Pair<U>` by applying a function to the value of the pair,
+    /// while preserving punctuation if it is not the end.
+    /// ```rust
+    /// # use vvs_parser::prelude::ast::*;
+    /// let pair = Pair::new(2, None);
+    /// assert_eq!(*pair.map(|i| i * 2).value(), 4);
+    /// ```
+    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Pair<U> {
+        match self {
+            Pair::End(value) => Pair::End(f(value)),
+            Pair::Punctuated(value, punctuated) => Pair::Punctuated(f(value), punctuated),
+        }
+    }
+}
+
+impl<T> Sealed for Pair<T> {}
+
+impl<T: Node> Node for Pair<T> {
+    fn start_position(&self) -> Option<Position> {
+        self.value().start_position()
+    }
+
+    fn end_position(&self) -> Option<Position> {
+        self.punctuation()
+            .and_then(Node::end_position)
+            .or_else(|| self.value().end_position())
+    }
+
+    fn similar(&self, other: &Self) -> bool {
+        self.value().similar(other.value())
+    }
+
+    fn tokens(&self) -> Tokens {
+        match self {
+            Pair::Punctuated(node, separator) => {
+                let mut items = node.tokens().items;
+                items.push(TokenItem::TokenReference(separator));
+                Tokens { items }
+            }
+            Pair::End(node) => node.tokens(),
+        }
+    }
+}
+
+impl<T: Visit> Visit for Pair<T> {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        match self {
+            Pair::End(value) => value.visit(visitor),
+            Pair::Punctuated(value, punctuation) => {
+                value.visit(visitor);
+                punctuation.visit(visitor);
+            }
+        }
+    }
+}
+
+impl<T: VisitMut> VisitMut for Pair<T> {
+    fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self {
+        match self {
+            Pair::End(value) => Pair::End(value.visit_mut(visitor)),
+            Pair::Punctuated(value, punctuation) => {
+                Pair::Punctuated(value.visit_mut(visitor), punctuation.visit_mut(visitor))
+            }
+        }
+    }
+}
diff --git a/src/Rust/vvs_parser/src/ast/span.rs b/src/Rust/vvs_parser/src/ast/span.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1b14ca1d8d5584eb225cf3e36ba921c281e1a5f5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/span.rs
@@ -0,0 +1,55 @@
+//! A representation of a "contained span", or a span within specific bounds.
+//!
+//! Examples of contained spans include:
+//! - Arguments in a function call use parentheses `(...)`
+//! - Indexing a table uses brackets `[...]`
+//! - Creating a table uses braces `{...}`
+//!
+//! Contained spans don't contain the inner data, just the start and end bounds.
+
+use crate::{
+    node::{Node, Tokens},
+    private::Sealed,
+    tokenizer::{Position, TokenReference},
+};
+use serde::{Deserialize, Serialize};
+use vvs_parser_derive::Visit;
+
+/// A contained span with the beginning and ending bounds.
+/// Refer to the [module documentation](index.html) for more details.
+#[derive(Clone, Debug, PartialEq, Eq, Visit, Deserialize, Serialize)]
+pub struct ContainedSpan {
+    pub(crate) tokens: (TokenReference, TokenReference),
+}
+
+impl ContainedSpan {
+    /// Creates a contained span from the start and end bounds
+    pub fn new(start: TokenReference, end: TokenReference) -> Self {
+        Self { tokens: (start, end) }
+    }
+
+    /// Returns the start and end bounds in a tuple as references
+    pub fn tokens(&self) -> (&TokenReference, &TokenReference) {
+        (&self.tokens.0, &self.tokens.1)
+    }
+}
+
+impl Node for ContainedSpan {
+    fn start_position(&self) -> Option<Position> {
+        self.tokens.0.start_position()
+    }
+
+    fn end_position(&self) -> Option<Position> {
+        self.tokens.1.end_position()
+    }
+
+    fn similar(&self, other: &Self) -> bool {
+        self.tokens.0.similar(&other.tokens.0) && self.tokens.1.similar(&other.tokens.1)
+    }
+
+    fn tokens(&self) -> Tokens {
+        self.tokens.tokens()
+    }
+}
+
+impl Sealed for ContainedSpan {}
diff --git a/src/Rust/vvs_parser/src/ast/update_positions.rs b/src/Rust/vvs_parser/src/ast/update_positions.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6939b6f9411791a9b6bb814501cae00a3355fe28
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/update_positions.rs
@@ -0,0 +1,87 @@
+use crate::{
+    ast::Ast,
+    tokenizer::{Position, Token, TokenKind, TokenReference},
+    visitors::VisitorMut,
+};
+
+#[derive(Default)]
+struct UpdatePositionsRewriter {
+    start_position: Position,
+    next_is_new_line: bool,
+}
+
+impl UpdatePositionsRewriter {
+    fn update_token(&mut self, token: &Token) -> Token {
+        let display = token.to_string();
+        let mut end_position = self.start_position;
+        if token.token_kind() != TokenKind::Eof {
+            for character in display.chars() {
+                if self.next_is_new_line {
+                    self.next_is_new_line = false;
+                    end_position.line += 1;
+                    end_position.character = 1;
+                }
+
+                if character == '\n' {
+                    self.next_is_new_line = true;
+                } else {
+                    end_position.character += 1;
+                }
+
+                end_position.bytes += character.len_utf8();
+            }
+        }
+
+        let result =
+            Token { start_position: self.start_position, end_position, token_type: token.token_type.to_owned() };
+
+        if self.next_is_new_line {
+            self.next_is_new_line = false;
+            end_position.line += 1;
+            end_position.character = 1;
+        }
+
+        self.start_position = end_position;
+        result
+    }
+}
+
+impl VisitorMut for UpdatePositionsRewriter {
+    fn visit_token_reference(&mut self, token: TokenReference) -> TokenReference {
+        TokenReference::new(
+            token.leading_trivia().map(|token| self.update_token(token)).collect(),
+            self.update_token(token.token()),
+            token.trailing_trivia().map(|token| self.update_token(token)).collect(),
+        )
+    }
+}
+
+impl Ast {
+    /// Will update the positions of all the tokens in the tree
+    /// Necessary if you are both mutating the tree and need the positions of the tokens
+    pub fn update_positions(self) -> Self {
+        UpdatePositionsRewriter { start_position: Position { bytes: 0, character: 1, line: 1 }, ..Default::default() }
+            .visit_ast(self)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::{node::Node, prelude::parser::parse_lua_tree};
+
+    #[test]
+    fn test_update_positions_validity() {
+        let ast = parse_lua_tree("local foo = 1\nlocal bar = 2").unwrap();
+        let old_positions: Vec<_> = ast
+            .tokens()
+            .map(|token| (token.start_position(), token.end_position()))
+            .collect();
+        let ast = ast.update_positions();
+        assert_eq!(
+            old_positions,
+            ast.tokens()
+                .map(|token| (token.start_position(), token.end_position()))
+                .collect::<Vec<_>>(),
+        );
+    }
+}
diff --git a/src/Rust/vvs_parser/src/ast/visitors.rs b/src/Rust/vvs_parser/src/ast/visitors.rs
new file mode 100644
index 0000000000000000000000000000000000000000..b95353f395d6cbd2e878f03a03699abe239e54bf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/ast/visitors.rs
@@ -0,0 +1,526 @@
+// Implementations of Visit and VisitMut that are not able to be automatically derived yet.
+// Ideally everything would be derived.
+use super::*;
+use crate::visitors::{Visit, VisitMut, Visitor, VisitorMut};
+
+// The following have `ContainedSpan`, which when automatically derived will visit the tokens containing
+// before they visit what they're actually containing.
+// For example, if there is an AST node that represents `(foo)`...
+// Then visitors will visit this as `()foo`.
+// This is fixed for structs with `#[visit(contains = "...")], but this is not supported on enums.
+
+impl Visit for Field {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_field(self);
+        match self {
+            Field::ExpressionKey { brackets, key, equal, value } => {
+                brackets.tokens.0.visit(visitor);
+                key.visit(visitor);
+                brackets.tokens.1.visit(visitor);
+                equal.visit(visitor);
+                value.visit(visitor);
+            }
+            Field::NameKey { key, equal, value } => {
+                key.visit(visitor);
+                equal.visit(visitor);
+                value.visit(visitor);
+            }
+            Field::NoKey(self_0) => self_0.visit(visitor),
+        };
+        visitor.visit_field_end(self);
+    }
+}
+
+impl VisitMut for Field {
+    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
+        self = visitor.visit_field(self);
+        self = match self {
+            Field::ExpressionKey { mut brackets, mut key, equal, value } => {
+                brackets.tokens.0 = brackets.tokens.0.visit_mut(visitor);
+                key = key.visit_mut(visitor);
+                brackets.tokens.1 = brackets.tokens.1.visit_mut(visitor);
+                Field::ExpressionKey { brackets, key, equal: equal.visit_mut(visitor), value: value.visit_mut(visitor) }
+            }
+            Field::NameKey { key, equal, value } => Field::NameKey {
+                key: key.visit_mut(visitor),
+                equal: equal.visit_mut(visitor),
+                value: value.visit_mut(visitor),
+            },
+            Field::NoKey(self_0) => Field::NoKey(self_0.visit_mut(visitor)),
+        };
+        self = visitor.visit_field_end(self);
+        self
+    }
+}
+
+impl Visit for Expression {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_expression(self);
+        match self {
+            Expression::BinaryOperator { lhs, binop, rhs } => {
+                lhs.visit(visitor);
+                binop.visit(visitor);
+                rhs.visit(visitor);
+            }
+            Expression::Parentheses { contained, expression } => {
+                contained.tokens.0.visit(visitor);
+                expression.visit(visitor);
+                contained.tokens.1.visit(visitor);
+            }
+            Expression::UnaryOperator { unop, expression } => {
+                unop.visit(visitor);
+                expression.visit(visitor);
+            }
+            Expression::Function(func) => {
+                func.0.visit(visitor);
+                func.1.visit(visitor);
+            }
+            Expression::TypeAssertion { expression, type_assertion } => {
+                expression.visit(visitor);
+                type_assertion.visit(visitor);
+            }
+            Expression::Number(token) | Expression::String(token) | Expression::Symbol(token) => {
+                token.visit(visitor);
+            }
+            Expression::FunctionCall(function_call) => function_call.visit(visitor),
+            Expression::IfExpression(if_expression) => if_expression.visit(visitor),
+            Expression::TableConstructor(table_constructor) => table_constructor.visit(visitor),
+            Expression::Var(var) => var.visit(visitor),
+        };
+        visitor.visit_expression_end(self);
+    }
+}
+
+impl VisitMut for Expression {
+    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
+        self = visitor.visit_expression(self);
+        self = match self {
+            Expression::BinaryOperator { lhs, binop, rhs } => Expression::BinaryOperator {
+                lhs: lhs.visit_mut(visitor),
+                binop: binop.visit_mut(visitor),
+                rhs: rhs.visit_mut(visitor),
+            },
+            Expression::Parentheses { mut contained, mut expression } => {
+                contained.tokens.0 = contained.tokens.0.visit_mut(visitor);
+                expression = expression.visit_mut(visitor);
+                contained.tokens.1 = contained.tokens.1.visit_mut(visitor);
+                Expression::Parentheses { contained, expression }
+            }
+            Expression::UnaryOperator { unop, expression } => {
+                Expression::UnaryOperator { unop: unop.visit_mut(visitor), expression: expression.visit_mut(visitor) }
+            }
+            Expression::Function(func) => {
+                Expression::Function(Box::new((func.0.visit_mut(visitor), func.1.visit_mut(visitor))))
+            }
+            Expression::FunctionCall(function_call) => Expression::FunctionCall(function_call.visit_mut(visitor)),
+            Expression::IfExpression(if_expression) => Expression::IfExpression(if_expression.visit_mut(visitor)),
+            Expression::TableConstructor(table_constructor) => {
+                Expression::TableConstructor(table_constructor.visit_mut(visitor))
+            }
+            Expression::TypeAssertion { expression, type_assertion } => Expression::TypeAssertion {
+                expression: expression.visit_mut(visitor),
+                type_assertion: type_assertion.visit_mut(visitor),
+            },
+            Expression::Number(token) => Expression::Number(token.visit_mut(visitor)),
+            Expression::String(token) => Expression::String(token.visit_mut(visitor)),
+            Expression::Symbol(token) => Expression::Symbol(token.visit_mut(visitor)),
+            Expression::Var(var) => Expression::Var(var.visit_mut(visitor)),
+        };
+        self = visitor.visit_expression_end(self);
+        self
+    }
+}
+
+impl Visit for Index {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_index(self);
+        match self {
+            Index::Brackets { brackets, expression } => {
+                brackets.tokens.0.visit(visitor);
+                expression.visit(visitor);
+                brackets.tokens.1.visit(visitor);
+            }
+            Index::Dot { dot, name } => {
+                dot.visit(visitor);
+                name.visit(visitor);
+            }
+        };
+        visitor.visit_index_end(self);
+    }
+}
+
+impl VisitMut for Index {
+    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
+        self = visitor.visit_index(self);
+        self = match self {
+            Index::Brackets { mut brackets, mut expression } => {
+                brackets.tokens.0 = brackets.tokens.0.visit_mut(visitor);
+                expression = expression.visit_mut(visitor);
+                brackets.tokens.1 = brackets.tokens.1.visit_mut(visitor);
+                Index::Brackets { brackets, expression }
+            }
+            Index::Dot { dot, name } => Index::Dot { dot: dot.visit_mut(visitor), name: name.visit_mut(visitor) },
+        };
+        self = visitor.visit_index_end(self);
+        self
+    }
+}
+
+impl Visit for FunctionArgs {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_function_args(self);
+        match self {
+            FunctionArgs::Parentheses { parentheses, arguments } => {
+                parentheses.tokens.0.visit(visitor);
+                arguments.visit(visitor);
+                parentheses.tokens.1.visit(visitor);
+            }
+            FunctionArgs::String(self_0) => self_0.visit(visitor),
+            FunctionArgs::TableConstructor(self_0) => self_0.visit(visitor),
+        };
+        visitor.visit_function_args_end(self);
+    }
+}
+
+impl VisitMut for FunctionArgs {
+    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
+        self = visitor.visit_function_args(self);
+        self = match self {
+            FunctionArgs::Parentheses { mut parentheses, mut arguments } => {
+                parentheses.tokens.0 = parentheses.tokens.0.visit_mut(visitor);
+                arguments = arguments.visit_mut(visitor);
+                parentheses.tokens.1 = parentheses.tokens.1.visit_mut(visitor);
+                FunctionArgs::Parentheses { parentheses, arguments }
+            }
+            FunctionArgs::String(self_0) => FunctionArgs::String(self_0.visit_mut(visitor)),
+            FunctionArgs::TableConstructor(self_0) => FunctionArgs::TableConstructor(self_0.visit_mut(visitor)),
+        };
+        self = visitor.visit_function_args_end(self);
+        self
+    }
+}
+
+// The following contain type signatures, which are addendums to previous identities
+impl Visit for FunctionBody {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_function_body(self);
+        self.parameters_parentheses.tokens.0.visit(visitor);
+        let mut type_specifiers = self.type_specifiers();
+
+        for parameter in &self.parameters {
+            parameter.visit(visitor);
+            type_specifiers.next().visit(visitor);
+        }
+
+        self.parameters_parentheses.tokens.1.visit(visitor);
+        self.return_type.visit(visitor);
+        self.block.visit(visitor);
+        self.end_token.visit(visitor);
+        visitor.visit_function_body_end(self);
+    }
+}
+
+impl VisitMut for FunctionBody {
+    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
+        self = visitor.visit_function_body(self);
+        self.parameters_parentheses.tokens.0 = self.parameters_parentheses.tokens.0.visit_mut(visitor);
+        let mut type_specifiers = self.type_specifiers.into_iter();
+        let mut new_type_specifiers = Vec::new();
+        let mut new_parameters = Punctuated::new();
+
+        for parameter_pair in self.parameters.into_pairs() {
+            let parameter_tuple = parameter_pair.into_tuple();
+            let parameter = parameter_tuple.0.visit_mut(visitor);
+            let type_specifier = type_specifiers
+                .next()
+                .and_then(|type_specifier| type_specifier)
+                .map(|type_specifier| type_specifier.visit_mut(visitor));
+            new_type_specifiers.push(type_specifier);
+            let punctuation = parameter_tuple.1.visit_mut(visitor);
+            new_parameters.push(Pair::new(parameter, punctuation));
+        }
+
+        self.parameters = new_parameters;
+        self.type_specifiers = new_type_specifiers;
+        self.parameters_parentheses.tokens.1 = self.parameters_parentheses.tokens.1.visit_mut(visitor);
+        self.return_type = self.return_type.visit_mut(visitor);
+        self.block = self.block.visit_mut(visitor);
+        self.end_token = self.end_token.visit_mut(visitor);
+        self = visitor.visit_function_body_end(self);
+        self
+    }
+}
+
+impl Visit for LocalAssignment {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_local_assignment(self);
+        self.local_token.visit(visitor);
+
+        let mut attributes = self.attributes();
+        let mut type_specifiers = self.type_specifiers();
+        for name in &self.name_list {
+            name.visit(visitor);
+            attributes.next().visit(visitor);
+            type_specifiers.next().visit(visitor);
+        }
+
+        self.equal_token.visit(visitor);
+        self.expr_list.visit(visitor);
+        visitor.visit_local_assignment_end(self);
+    }
+}
+
+impl VisitMut for LocalAssignment {
+    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
+        self = visitor.visit_local_assignment(self);
+        self.local_token = self.local_token.visit_mut(visitor);
+
+        let mut attributes = self.attributes.into_iter();
+        let mut type_specifiers = self.type_specifiers.into_iter();
+        let mut new_attributes = Vec::new();
+        let mut new_type_specifiers = Vec::new();
+        let mut new_names = Punctuated::new();
+
+        for parameter_pair in self.name_list.into_pairs() {
+            let parameter_tuple = parameter_pair.into_tuple();
+            let parameter = parameter_tuple.0.visit_mut(visitor);
+            let attribute = attributes
+                .next()
+                .flatten()
+                .map(|attribute| attribute.visit_mut(visitor));
+            let type_specifier = type_specifiers
+                .next()
+                .flatten()
+                .map(|type_specifier| type_specifier.visit_mut(visitor));
+
+            let punctuation = parameter_tuple.1.visit_mut(visitor);
+            new_attributes.push(attribute);
+            new_type_specifiers.push(type_specifier);
+            new_names.push(Pair::new(parameter, punctuation));
+        }
+
+        self.name_list = new_names;
+        self.attributes = new_attributes;
+        self.type_specifiers = new_type_specifiers;
+        self.equal_token = self.equal_token.visit_mut(visitor);
+        self.expr_list = self.expr_list.visit_mut(visitor);
+        self = visitor.visit_local_assignment_end(self);
+        self
+    }
+}
+
+impl Visit for GenericFor {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_generic_for(self);
+        self.for_token.visit(visitor);
+
+        let mut type_specifiers = self.type_specifiers();
+        for name in &self.names {
+            name.visit(visitor);
+            type_specifiers.next().visit(visitor);
+        }
+
+        self.in_token.visit(visitor);
+        self.expr_list.visit(visitor);
+        self.do_token.visit(visitor);
+        self.block.visit(visitor);
+        self.end_token.visit(visitor);
+
+        visitor.visit_generic_for_end(self);
+    }
+}
+
+impl VisitMut for GenericFor {
+    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
+        self = visitor.visit_generic_for(self);
+        self.for_token = self.for_token.visit_mut(visitor);
+
+        let mut type_specifiers = self.type_specifiers.into_iter();
+        let mut new_type_specifiers = Vec::new();
+        let mut new_names = Punctuated::new();
+
+        for parameter_pair in self.names.into_pairs() {
+            let parameter_tuple = parameter_pair.into_tuple();
+            let parameter = parameter_tuple.0.visit_mut(visitor);
+            let type_specifier = type_specifiers
+                .next()
+                .and_then(|type_specifier| type_specifier)
+                .map(|type_specifier| type_specifier.visit_mut(visitor));
+
+            let punctuation = parameter_tuple.1.visit_mut(visitor);
+            new_type_specifiers.push(type_specifier);
+            new_names.push(Pair::new(parameter, punctuation));
+        }
+
+        self.names = new_names;
+        self.type_specifiers = new_type_specifiers;
+        self.in_token = self.in_token.visit_mut(visitor);
+        self.expr_list = self.expr_list.visit_mut(visitor);
+        self.do_token = self.do_token.visit_mut(visitor);
+        self.block = self.block.visit_mut(visitor);
+        self.end_token = self.end_token.visit_mut(visitor);
+
+        self = visitor.visit_generic_for_end(self);
+        self
+    }
+}
+
+impl Visit for NumericFor {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_numeric_for(self);
+        self.for_token.visit(visitor);
+        self.index_variable.visit(visitor);
+        self.type_specifier.visit(visitor);
+        self.equal_token.visit(visitor);
+        self.start.visit(visitor);
+        self.start_end_comma.visit(visitor);
+        self.end.visit(visitor);
+        self.end_step_comma.visit(visitor);
+        self.step.visit(visitor);
+        self.do_token.visit(visitor);
+        self.block.visit(visitor);
+        self.end_token.visit(visitor);
+        visitor.visit_numeric_for_end(self);
+    }
+}
+
+impl VisitMut for NumericFor {
+    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
+        self = visitor.visit_numeric_for(self);
+        self.for_token = self.for_token.visit_mut(visitor);
+        self.index_variable = self.index_variable.visit_mut(visitor);
+        self.type_specifier = self.type_specifier.visit_mut(visitor);
+        self.equal_token = self.equal_token.visit_mut(visitor);
+        self.start = self.start.visit_mut(visitor);
+        self.start_end_comma = self.start_end_comma.visit_mut(visitor);
+        self.end = self.end.visit_mut(visitor);
+        self.end_step_comma = self.end_step_comma.visit_mut(visitor);
+        self.step = self.step.visit_mut(visitor);
+        self.do_token = self.do_token.visit_mut(visitor);
+        self.block = self.block.visit_mut(visitor);
+        self.end_token = self.end_token.visit_mut(visitor);
+        self = visitor.visit_numeric_for_end(self);
+        self
+    }
+}
+
+impl Visit for TypeInfo {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_type_info(self);
+        match self {
+            TypeInfo::Array { braces, type_info } => {
+                braces.tokens.0.visit(visitor);
+                type_info.visit(visitor);
+                braces.tokens.1.visit(visitor);
+            }
+            TypeInfo::Basic(self_0) => self_0.visit(visitor),
+            TypeInfo::Callback { parentheses, arguments, arrow, return_type } => {
+                parentheses.tokens.0.visit(visitor);
+                arguments.visit(visitor);
+                parentheses.tokens.1.visit(visitor);
+                arrow.visit(visitor);
+                return_type.visit(visitor);
+            }
+            TypeInfo::Optional { base, question_mark } => {
+                base.visit(visitor);
+                question_mark.visit(visitor);
+            }
+            TypeInfo::Table { braces, fields } => {
+                braces.tokens.0.visit(visitor);
+                fields.visit(visitor);
+                braces.tokens.1.visit(visitor);
+            }
+            TypeInfo::Typeof { typeof_token, parentheses, inner } => {
+                typeof_token.visit(visitor);
+                parentheses.tokens.0.visit(visitor);
+                inner.visit(visitor);
+                parentheses.tokens.1.visit(visitor);
+            }
+            TypeInfo::Tuple { parentheses, types } => {
+                parentheses.tokens.0.visit(visitor);
+                types.visit(visitor);
+                parentheses.tokens.1.visit(visitor);
+            }
+        };
+        visitor.visit_type_info_end(self);
+    }
+}
+
+impl VisitMut for TypeInfo {
+    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
+        self = visitor.visit_type_info(self);
+        self = match self {
+            TypeInfo::Array { mut braces, mut type_info } => {
+                braces.tokens.0 = braces.tokens.0.visit_mut(visitor);
+                type_info = type_info.visit_mut(visitor);
+                braces.tokens.1 = braces.tokens.1.visit_mut(visitor);
+                TypeInfo::Array { braces, type_info }
+            }
+            TypeInfo::Basic(self_0) => TypeInfo::Basic(self_0.visit_mut(visitor)),
+            TypeInfo::Callback { mut parentheses, mut arguments, mut arrow, mut return_type } => {
+                parentheses.tokens.0 = parentheses.tokens.0.visit_mut(visitor);
+                arguments = arguments.visit_mut(visitor);
+                parentheses.tokens.1 = parentheses.tokens.1.visit_mut(visitor);
+                arrow = arrow.visit_mut(visitor);
+                return_type = return_type.visit_mut(visitor);
+                TypeInfo::Callback { parentheses, arguments, arrow, return_type }
+            }
+            TypeInfo::Optional { base, question_mark } => {
+                TypeInfo::Optional { base: base.visit_mut(visitor), question_mark: question_mark.visit_mut(visitor) }
+            }
+            TypeInfo::Table { mut braces, mut fields } => {
+                braces.tokens.0 = braces.tokens.0.visit_mut(visitor);
+                fields = fields.visit_mut(visitor);
+                braces.tokens.1 = braces.tokens.1.visit_mut(visitor);
+                TypeInfo::Table { braces, fields }
+            }
+            TypeInfo::Typeof { mut typeof_token, mut parentheses, mut inner } => {
+                typeof_token = typeof_token.visit_mut(visitor);
+                parentheses.tokens.0 = parentheses.tokens.0.visit_mut(visitor);
+                inner = inner.visit_mut(visitor);
+                parentheses.tokens.1 = parentheses.tokens.1.visit_mut(visitor);
+                TypeInfo::Typeof { typeof_token, parentheses, inner }
+            }
+            TypeInfo::Tuple { mut parentheses, mut types } => {
+                parentheses.tokens.0 = parentheses.tokens.0.visit_mut(visitor);
+                types = types.visit_mut(visitor);
+                parentheses.tokens.1 = parentheses.tokens.1.visit_mut(visitor);
+                TypeInfo::Tuple { parentheses, types }
+            }
+        };
+        self = visitor.visit_type_info_end(self);
+        self
+    }
+}
+
+impl Visit for TypeFieldKey {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_type_field_key(self);
+        match self {
+            TypeFieldKey::Name(self_0) => self_0.visit(visitor),
+            TypeFieldKey::IndexSignature { brackets, inner } => {
+                brackets.tokens.0.visit(visitor);
+                inner.visit(visitor);
+                brackets.tokens.1.visit(visitor);
+            }
+        };
+        visitor.visit_type_field_key_end(self);
+    }
+}
+
+impl VisitMut for TypeFieldKey {
+    fn visit_mut<V: VisitorMut>(mut self, visitor: &mut V) -> Self {
+        self = visitor.visit_type_field_key(self);
+        self = match self {
+            TypeFieldKey::Name(self_0) => TypeFieldKey::Name(self_0.visit_mut(visitor)),
+            TypeFieldKey::IndexSignature { mut brackets, mut inner } => {
+                brackets.tokens.0 = brackets.tokens.0.visit_mut(visitor);
+                inner = inner.visit_mut(visitor);
+                brackets.tokens.1 = brackets.tokens.1.visit_mut(visitor);
+                TypeFieldKey::IndexSignature { brackets, inner }
+            }
+        };
+        self = visitor.visit_type_field_key_end(self);
+        self
+    }
+}
diff --git a/src/Rust/vvs_parser/src/error.rs b/src/Rust/vvs_parser/src/error.rs
new file mode 100644
index 0000000000000000000000000000000000000000..226e331f46bbb919751f96a9f4c84bd74e1377c0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/error.rs
@@ -0,0 +1,59 @@
+//! Special errors for the Vivy Script package, so we don't expose anything with anyhow.
+
+use crate::{
+    ast::AstError,
+    tokenizer::{Position, TokenizerError},
+};
+use derive_more::{Display, From};
+use serde::{Deserialize, Serialize};
+use std::{borrow::Cow, ops};
+
+/// An error type that consists of both [`AstError`](ast::AstError) and [`TokenizerError`](tokenizer::TokenizerError)
+/// Used by [`parse`]
+#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, From, Display)]
+pub enum Error {
+    /// Triggered if there's an issue creating an AST, but tokenizing must have succeeded
+    #[display("error occurred while creating ast: {_0}")]
+    AstError(AstError),
+
+    /// Triggered if there's an issue when tokenizing, and an AST can't be made
+    #[display("error occurred while tokenizing: {_0}")]
+    TokenizerError(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(),
+        }
+    }
+
+    /// Returns the range of the error in bytes
+    pub fn byte_range(&self) -> ops::Range<usize> {
+        let (start, end) = match self {
+            Error::AstError(error) => error.range(),
+            Error::TokenizerError(error) => error.range(),
+        };
+        start.bytes()..end.bytes()
+    }
+
+    /// Get the error code.
+    pub fn error_code(&self) -> &'static str {
+        match self {
+            Error::AstError(_) => "ast",
+            Error::TokenizerError(_) => "tokenizer",
+        }
+    }
+}
+
+impl std::error::Error for Error {}
diff --git a/src/Rust/vvs_parser/src/lib.rs b/src/Rust/vvs_parser/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..63d28204f9e095bd7711a1665f3b5c981b191cb8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/lib.rs
@@ -0,0 +1,57 @@
+#![warn(missing_docs)]
+#![allow(clippy::large_enum_variant)]
+
+//! # Vivy Script Parser.
+//!
+//! `vvs_parser` is a lossless parser for Vivy Script, inspired by Lua and Luau.
+
+mod ast;
+mod error;
+mod node;
+mod private;
+mod short_string;
+mod tokenizer;
+mod traits;
+mod util;
+mod visitors;
+mod vivy;
+
+#[cfg(test)]
+mod tests;
+
+use crate::{error::Error, short_string::ShortString};
+
+/// Crates depending upon [vss_parser] may import the prelude.
+pub mod prelude {
+    /// Re-export everything that is linked to the [Ast].
+    pub mod ast {
+        pub use crate::{ast::*, node::*, short_string::ShortString, tokenizer::*, visitors::*};
+    }
+
+    /// Parsers, get the raw representation of things without transforming or checking the
+    /// resulting things. May be used for debug or test only.
+    pub mod parser {
+        /// Creates an [`Ast`](ast::Ast) for VivyScript code.
+        ///
+        /// Note that the resulting code may not be entirely valid! You need to pass it into the
+        /// [CompilerPipeline] for that!
+        ///
+        /// # Errors
+        /// If the code passed cannot be tokenized, a TokenizerError will be returned.
+        /// If the code passed is not valid Lua 5.1 code, an AstError will be returned,
+        /// specifically AstError::UnexpectedToken.
+        pub fn parse_lua_tree(code: &str) -> Result<crate::ast::Ast, Vec<crate::Error>> {
+            crate::ast::AstResult::parse_fallible(code).into_result()
+        }
+
+        /// Given code, will produce an [`ast::OptionTableResult`]. This OptionTableResult always produces
+        /// some [OptionTableResult], regardless of errors. If a partial Ast is produced (i.e. if there are
+        /// any errors), a few guarantees are lost. The same remarks can be made as [parse_fallible].
+        pub fn parse_options_tree(code: &str) -> Result<crate::ast::OptionTable, Vec<crate::Error>> {
+            crate::ast::OptionTableResult::parse_fallible(code).into_result()
+        }
+    }
+
+    pub use crate::error::Error as VVSParserError;
+    pub use crate::vivy::*;
+}
diff --git a/src/Rust/vvs_parser/src/node.rs b/src/Rust/vvs_parser/src/node.rs
new file mode 100644
index 0000000000000000000000000000000000000000..dfe90349e1c25e5fc2e6243c69b1910eeeb50916
--- /dev/null
+++ b/src/Rust/vvs_parser/src/node.rs
@@ -0,0 +1,264 @@
+//! Contains the `Node` trait, implemented on all nodes
+
+use crate::{
+    ast::Ast,
+    private,
+    tokenizer::{Position, Token, TokenReference},
+};
+use std::fmt;
+
+/// Used to represent nodes such as tokens or function definitions
+///
+/// This trait is sealed and cannot be implemented for types outside of `full-moon`
+pub trait Node: private::Sealed {
+    /// The start position of a node. None if can't be determined
+    fn start_position(&self) -> Option<Position>;
+
+    /// The end position of a node. None if it can't be determined
+    fn end_position(&self) -> Option<Position>;
+
+    /// Whether another node of the same type is the same as this one semantically, ignoring position
+    fn similar(&self, other: &Self) -> bool
+    where
+        Self: Sized;
+
+    /// The token references that comprise a node
+    fn tokens(&self) -> Tokens;
+
+    /// The full range of a node, if it has both start and end positions
+    fn range(&self) -> Option<(Position, Position)> {
+        Some((self.start_position()?, self.end_position()?))
+    }
+
+    /// The tokens surrounding a node that are ignored and not accessible through the node's own accessors.
+    /// Use this if you want to get surrounding comments or whitespace.
+    /// Returns a tuple of the leading and trailing trivia.
+    fn surrounding_trivia(&self) -> (Vec<&Token>, Vec<&Token>) {
+        let mut tokens = self.tokens();
+        let leading = tokens.next().map(|token| token.leading_trivia().collect());
+        let trailing = tokens.next_back().map(|token| token.trailing_trivia().collect());
+        (leading.unwrap_or_default(), trailing.unwrap_or_default())
+    }
+}
+
+pub(crate) enum TokenItem<'a> {
+    MoreTokens(&'a dyn Node),
+    TokenReference(&'a TokenReference),
+}
+
+impl fmt::Debug for TokenItem<'_> {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            TokenItem::MoreTokens(_) => write!(formatter, "TokenItem::MoreTokens"),
+            TokenItem::TokenReference(token) => {
+                write!(formatter, "TokenItem::TokenReference({token})")
+            }
+        }
+    }
+}
+
+/// An iterator that iterates over the tokens of a node
+/// Returned by [`Node::tokens`]
+#[derive(Default)]
+pub struct Tokens<'a> {
+    pub(crate) items: Vec<TokenItem<'a>>,
+}
+
+impl<'a> Iterator for Tokens<'a> {
+    type Item = &'a TokenReference;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.items.is_empty() {
+            return None;
+        }
+
+        match self.items.remove(0) {
+            TokenItem::TokenReference(reference) => Some(reference),
+            TokenItem::MoreTokens(node) => {
+                let mut tokens = node.tokens();
+                tokens.items.append(&mut self.items);
+                self.items = tokens.items;
+                self.next()
+            }
+        }
+    }
+}
+
+impl<'a> DoubleEndedIterator for Tokens<'a> {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        if self.items.is_empty() {
+            return None;
+        }
+
+        match self.items.pop()? {
+            TokenItem::TokenReference(reference) => Some(reference),
+            TokenItem::MoreTokens(node) => {
+                let mut tokens = node.tokens();
+                self.items.append(&mut tokens.items);
+                self.next_back()
+            }
+        }
+    }
+}
+
+impl Node for Ast {
+    fn start_position(&self) -> Option<Position> {
+        self.nodes().start_position()
+    }
+
+    fn end_position(&self) -> Option<Position> {
+        self.nodes().end_position()
+    }
+
+    fn similar(&self, other: &Self) -> bool {
+        self.nodes().similar(other.nodes())
+    }
+
+    fn tokens(&self) -> Tokens {
+        self.nodes().tokens()
+    }
+}
+
+impl<T: Node> Node for Box<T> {
+    fn start_position(&self) -> Option<Position> {
+        (**self).start_position()
+    }
+
+    fn end_position(&self) -> Option<Position> {
+        (**self).end_position()
+    }
+
+    fn similar(&self, other: &Self) -> bool {
+        (**self).similar(other)
+    }
+
+    fn tokens(&self) -> Tokens {
+        (**self).tokens()
+    }
+}
+
+impl<T: Node> Node for &T {
+    fn start_position(&self) -> Option<Position> {
+        (**self).start_position()
+    }
+
+    fn end_position(&self) -> Option<Position> {
+        (**self).end_position()
+    }
+
+    fn similar(&self, other: &Self) -> bool {
+        (**self).similar(other)
+    }
+
+    fn tokens(&self) -> Tokens {
+        (**self).tokens()
+    }
+}
+
+impl<T: Node> Node for &mut T {
+    fn start_position(&self) -> Option<Position> {
+        (**self).start_position()
+    }
+
+    fn end_position(&self) -> Option<Position> {
+        (**self).end_position()
+    }
+
+    fn similar(&self, other: &Self) -> bool {
+        (**self).similar(other)
+    }
+
+    fn tokens(&self) -> Tokens {
+        (**self).tokens()
+    }
+}
+
+impl Node for TokenReference {
+    fn start_position(&self) -> Option<Position> {
+        Some((**self).start_position())
+    }
+
+    fn end_position(&self) -> Option<Position> {
+        Some((**self).end_position())
+    }
+
+    fn similar(&self, other: &Self) -> bool {
+        *self.token_type() == *other.token_type()
+    }
+
+    fn tokens(&self) -> Tokens {
+        Tokens { items: vec![TokenItem::TokenReference(self)] }
+    }
+}
+
+impl<T: Node> Node for Option<T> {
+    fn start_position(&self) -> Option<Position> {
+        self.as_ref().and_then(Node::start_position)
+    }
+
+    fn end_position(&self) -> Option<Position> {
+        self.as_ref().and_then(Node::end_position)
+    }
+
+    fn similar(&self, other: &Self) -> bool {
+        match (self.as_ref(), other.as_ref()) {
+            (Some(x), Some(y)) => x.similar(y),
+            (None, None) => true,
+            _ => false,
+        }
+    }
+
+    fn tokens(&self) -> Tokens {
+        self.as_ref().map(|node| node.tokens()).unwrap_or_default()
+    }
+}
+
+impl<T: Node> Node for Vec<T> {
+    fn start_position(&self) -> Option<Position> {
+        self.first()?.start_position()
+    }
+
+    fn end_position(&self) -> Option<Position> {
+        self.last()?.end_position()
+    }
+
+    fn similar(&self, other: &Self) -> bool {
+        if self.len() == other.len() {
+            self.iter().zip(other.iter()).all(|(x, y)| x.similar(y))
+        } else {
+            false
+        }
+    }
+
+    fn tokens(&self) -> Tokens {
+        Tokens { items: self.iter().flat_map(|node| node.tokens().items).collect() }
+    }
+}
+
+impl<A: Node, B: Node> Node for (A, B) {
+    fn start_position(&self) -> Option<Position> {
+        match (self.0.start_position(), self.1.start_position()) {
+            (Some(x), Some(y)) => Some(std::cmp::min(x, y)),
+            (Some(x), None) | (None, Some(x)) => Some(x),
+            (None, None) => None,
+        }
+    }
+
+    fn end_position(&self) -> Option<Position> {
+        match (self.0.end_position(), self.1.end_position()) {
+            (Some(x), Some(y)) => Some(std::cmp::max(x, y)),
+            (Some(x), None) | (None, Some(x)) => Some(x),
+            (None, None) => None,
+        }
+    }
+
+    fn similar(&self, other: &Self) -> bool {
+        self.0.similar(&other.0) && self.1.similar(&other.1)
+    }
+
+    fn tokens(&self) -> Tokens {
+        let mut items = self.0.tokens().items;
+        items.append(&mut self.1.tokens().items);
+        Tokens { items }
+    }
+}
diff --git a/src/Rust/vvs_parser/src/private.rs b/src/Rust/vvs_parser/src/private.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8483d03ca722a450bd9468d844c2e12842d1ce27
--- /dev/null
+++ b/src/Rust/vvs_parser/src/private.rs
@@ -0,0 +1,23 @@
+use crate::{
+    ast::{Ast, AstError},
+    tokenizer::{Token, TokenReference, TokenType, TokenizerError},
+    Error,
+};
+use std::borrow::Cow;
+
+pub trait Sealed {}
+
+impl<T> Sealed for &T {}
+impl<T> Sealed for &mut T {}
+impl<T: ToOwned> Sealed for Cow<'_, T> {}
+impl Sealed for Ast {}
+impl Sealed for AstError {}
+impl Sealed for Error {}
+impl Sealed for Token {}
+impl Sealed for TokenizerError {}
+impl Sealed for TokenReference {}
+impl Sealed for TokenType {}
+impl<T> Sealed for Box<T> {}
+impl<T> Sealed for Option<T> {}
+impl<T> Sealed for Vec<T> {}
+impl<A, B> Sealed for (A, B) {}
diff --git a/src/Rust/vvs_parser/src/short_string.rs b/src/Rust/vvs_parser/src/short_string.rs
new file mode 100644
index 0000000000000000000000000000000000000000..130edaee84d07ed768249f54e68aa945c7f49b17
--- /dev/null
+++ b/src/Rust/vvs_parser/src/short_string.rs
@@ -0,0 +1,118 @@
+//! A small string, with short string optimization.
+
+use serde::{Deserialize, Serialize};
+use smol_str::SmolStr;
+use std::{borrow::Borrow, fmt::Display, ops::Deref};
+
+/// A string as used in [crate::tokenizer::TokenType] and such. Does short string optimization.
+#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Hash, PartialOrd, Ord)]
+#[serde(transparent)]
+pub struct ShortString(SmolStr);
+
+impl ShortString {
+    /// Creates a new ShortString from the given text.
+    pub fn new<T: Into<String> + AsRef<str>>(text: T) -> Self
+    where
+        SmolStr: From<T>,
+    {
+        ShortString(SmolStr::from(text))
+    }
+
+    /// Constructs inline variant of [ShortString].
+    ///
+    /// Panics if `text.len() > 23`. (See [SmolStr::new_inline])
+    #[inline]
+    pub const fn new_inline(text: &str) -> Self {
+        ShortString(SmolStr::new_inline(text))
+    }
+
+    /// Constructs [ShortString]. Never allocates nor panic.
+    #[inline]
+    pub const fn new_static(text: &'static str) -> Self {
+        if text.len() <= 23 {
+            Self::new_inline(text)
+        } else {
+            ShortString(SmolStr::new_static(text))
+        }
+    }
+
+    /// Returns a `&str` representation of the ShortString.
+    pub fn as_str(&self) -> &str {
+        self.0.as_str()
+    }
+
+    /// Returns the length of the ShortString.
+    pub fn len(&self) -> usize {
+        self.0.len()
+    }
+
+    /// Returns whether or not the ShortString is empty.
+    pub fn is_empty(&self) -> bool {
+        self.0.is_empty()
+    }
+}
+
+impl Display for ShortString {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.0.fmt(f)
+    }
+}
+
+impl Deref for ShortString {
+    type Target = str;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl Borrow<str> for ShortString {
+    fn borrow(&self) -> &str {
+        self.as_str()
+    }
+}
+
+impl AsRef<str> for ShortString {
+    fn as_ref(&self) -> &str {
+        self.as_str()
+    }
+}
+
+impl<T: Into<String> + AsRef<str>> From<T> for ShortString
+where
+    SmolStr: From<T>,
+{
+    fn from(value: T) -> Self {
+        ShortString(SmolStr::from(value))
+    }
+}
+
+impl From<&ShortString> for ShortString {
+    fn from(value: &ShortString) -> Self {
+        value.clone()
+    }
+}
+
+impl From<ShortString> for String {
+    fn from(value: ShortString) -> Self {
+        value.0.to_string()
+    }
+}
+
+impl FromIterator<char> for ShortString {
+    fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
+        ShortString(SmolStr::from_iter(iter))
+    }
+}
+
+#[test]
+fn test_build_inline() {
+    assert_eq!(ShortString::new_inline("12345678901234567890123").len(), 23);
+    assert_eq!(ShortString::new_static("123456789012345678901230").len(), 24);
+}
+
+#[test]
+#[should_panic]
+fn test_oversized_inline() {
+    let _ = ShortString::new_inline("123456789012345678901230");
+}
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2166604ebbec8743e7913284657b95f7fede1977
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..72e2e4103c8115dd2c19c7810e24a881ebd17626
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/assignment-1
+---
+x =
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..dd052ce7a4937e0fdc7f6eb739e11522df94d1e8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8fdfabb4b77157cf8f071f7fd0c2fb962f20174b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..03c979a26bf68aceef72d5b2947a3b4714dc0868
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/source.lua
@@ -0,0 +1 @@
+x =
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f4fa4fa5adad880613c8dcfd8ecaec61fc451ca5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-1/tokens.snap
@@ -0,0 +1,50 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/assignment-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..163310d0e7906c866f303a22ee78e39e659ee4a2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3aac99086e101954f7697ef8a9c1b876204831d0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/assignment-2
+---
+"x = "
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..94e9ebe9ffe2057f168c63dfdba04239544cb50b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a286586338093cf5c96a54dabf1f2f13a4170c9d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..078176905b4b84ced4d01fc7fe9a7dc03cb95948
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/source.lua
@@ -0,0 +1 @@
+x = end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cbed2bbac98c611e923db907be697ae9913bb8fb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-2/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/assignment-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1a91149afdb182fea35f5543b554e696acb3e93d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-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/assignment-3
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8adbdbcadae2f0e35697e53d8d1343eea4449d81
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/assignment-3
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..384242f51df9ee6e749c9576046a5e8900050131
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..48344c4d3af390c7230ec7d6ecdbe32f099a9380
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..43f04f253dc58ee84756c2118fa0e0c4ae4d2115
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/source.lua
@@ -0,0 +1 @@
+until = 3
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..57970b57f3e5042c08a5188a5cb43891d06c0051
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/assignment-3/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/assignment-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: until
+- 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: Symbol
+    symbol: "="
+- 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: Number
+    text: "3"
+- start_position:
+    bytes: 9
+    line: 1
+    character: 10
+  end_position:
+    bytes: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..53a108c4e3af67f0ffa18e2e8ff802396a87688b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5c1cf3b14fb4cc009afd47e3bcefe6680f008c07
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/bin-op-1
+---
+"return 1 "
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..751e6d01bf30930f48c1714599753f285d9db28c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..89abb66ff7731f25d67e9b01fc088a5d66df34b2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..b6842ad8d238ce47ce0eed8fdd521ab850e0e652
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/source.lua
@@ -0,0 +1 @@
+return 1 +
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3328193814061c6372a7b15d77b1742652add1cc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-1/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/bin-op-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Number
+    text: "1"
+- 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: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..244911f1ab7c94f5f8f7e9b871607ef635cb122a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f0d37dcbed67421f3d75b80d154191ac18d852df
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/bin-op-2
+---
+"return 1 "
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..606bcb79643bfc9d58217a61fa7b32a31457c652
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6cdc9042b4a8ddaff8f6c0681ad08d46081659b0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f18ec0a95cf6b3b72ac55c64da941ef2af5873b3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/source.lua
@@ -0,0 +1 @@
+return 1 + until
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..770706729abe089c4e259240a0d0c4981def4308
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/bin-op-2/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/bin-op-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Number
+    text: "1"
+- 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: until
+- start_position:
+    bytes: 16
+    line: 1
+    character: 17
+  end_position:
+    bytes: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5842f2263b63575712fc83140cbe435a731b7eb8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..004a49c7b140dce8887a91fedfd53e414f699fb5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/call-1
+---
+call()
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..fe2ed585b934fef0616fa276fb1302801c58c2ba
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b1efc06a0e9bda275bf614b5156808191ca88d61
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f3433589e9d7828c575efa02dd09699ac3180bf9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/source.lua
@@ -0,0 +1 @@
+call(
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0c665ccf19f2dbebb0f9f63b9aaec4c721cbacd9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-1/tokens.snap
@@ -0,0 +1,39 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/call-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ab8efbb4d04350d44f12db60d337313d600a64f5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..894dba2d765ca03687191ec8133e9d84b3222c73
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/call-2
+---
+"call(\"hello\")"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b00135ec23f09e6afc4040e36b73e119918e0eb3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..55506155d36b9d8554d45c0c0cc062ced05547b2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..5457ce11752cb5c1108230fbeff88d7f53f732ac
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/source.lua
@@ -0,0 +1 @@
+call("hello"
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cea03670ac7abad6393a3efde06ba36e913cc81e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-2/tokens.snap
@@ -0,0 +1,51 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/call-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- 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
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 12
+    line: 1
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..beadf471b4017a6188991b0c4489deab3a3553de
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..04ae5b44063124d728b43e34fcf6544e5bfb6e6b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/call-3
+---
+"call(\"hello\", \"world\")"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..eb09a07012e3660a9e9898c8acf8e83aa26b055e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..083784b640d425d9a90200651826240e1b792d61
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..30bd92016172de76cdf86626ed15826fd8f364c2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/source.lua
@@ -0,0 +1 @@
+call("hello", "world"
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f04e3f041efce7b0505ebfb530ee07cb5308ffa0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-3/tokens.snap
@@ -0,0 +1,85 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/call-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- 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
+- 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: 21
+    line: 1
+    character: 22
+  token_type:
+    type: StringLiteral
+    literal: world
+    quote_type: Double
+- start_position:
+    bytes: 21
+    line: 1
+    character: 22
+  end_position:
+    bytes: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..215fa48745d3c7ccb9f6787be939f21972ea281a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9571c27f9fe8495f680ec29f83cdcf7989479f8b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/call-4
+---
+call()
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8e453c8ded59a34534eee64b4f9093fc98460033
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..904d3da45dbac7921825fb761e4cae692715115a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..80e92aba26c937081b4369705c5d20e8b028e50a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/source.lua
@@ -0,0 +1 @@
+call(end)
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..638e16b1948812f1ee1d45d13254bbc0c5ca08d8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/call-4/tokens.snap
@@ -0,0 +1,61 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/call-4
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: end
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c13b270f4d04fa5357e3651afd61a93b8c5abeb7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..94e4a870df1356c8035f3f3cd96a399992e2fcfb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/do-1
+---
+"do\n\tcall()end"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..256493136baf42507cfc28ff2a4cb4db912663c1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..289afb5847b4b972136f788620bb8de1a057ed7d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..d280f93e03a50bf1b456ed23903b6ac5fa41213f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/source.lua
@@ -0,0 +1,2 @@
+do
+	call()
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..51f120520a463459e86054a8785b99f87998f040
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-1/tokens.snap
@@ -0,0 +1,83 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/do-1
+
+---
+- 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: 4
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 4
+    line: 2
+    character: 2
+  end_position:
+    bytes: 8
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 8
+    line: 2
+    character: 6
+  end_position:
+    bytes: 9
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 9
+    line: 2
+    character: 7
+  end_position:
+    bytes: 10
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 10
+    line: 2
+    character: 8
+  end_position:
+    bytes: 10
+    line: 2
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..73409e151ab62c3e8964d24b8e051cdec5aadaa4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a858773488261c7c01f28110745fbab4f7c89b89
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/do-2
+---
+do end
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cc5ae9ca9b2ff24b8f65e369a74c8ff07d76a8bc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e8441877cea4c93261e1c1e4693cdd63eba3899d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..de672635c5ddc5188c9ad34422c1b0fa66656905
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/source.lua
@@ -0,0 +1 @@
+do until end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1978377432e424092025faaa9910058387981f0c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/do-2/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/do-2
+
+---
+- 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: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: until
+- 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: Symbol
+    symbol: end
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 12
+    line: 1
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..de634353a1d42d4553a4bb516cbdbda7d05e703e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/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-1
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..906b407ced718cb53c591f9bed5c350890a3c87a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/function-1
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3d60663607c6ecd74789f2529769951b2a59b5c9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7f753354de8cabc728425d72a0544047bc307a25
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..b2e1f1229a51ffc62cbb46d46d72aabdc91403d5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/source.lua
@@ -0,0 +1 @@
+function
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..938768d0407411a179be7fc45d67d1ca6abd429e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-1/tokens.snap
@@ -0,0 +1,28 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/function-1
+
+---
+- 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: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cde02936df6dc0cf51c7020c4ef86246955448b2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/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-2
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8812d23d2b5ae42910a4c18369aed5a084fb9f18
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/function-2
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..827de55ed7e806450b078bb6f42dbf6395936a68
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..28aa641992564388b4596431264c170cb3f43276
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..5e3e2e833ed34b712deae9fecee66de49bc0dc34
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/source.lua
@@ -0,0 +1 @@
+function end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8ab216d8a3fa4fa7cb48fd28ef5447f72857bcf1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-2/tokens.snap
@@ -0,0 +1,50 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/function-2
+
+---
+- 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: Symbol
+    symbol: end
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 12
+    line: 1
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7f93d13626637402ab08b85d0b578ab97b032690
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..851f72c64a9894c81685f04c5df5b6a86d676708
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/function-3
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..226d16c47d71bd54fb1dcba962c53ac14867a053
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b72091325b6f9c8c6a62988fd532922d6291d6d9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..793ec7ed02f0bb37fb9c3ef2f61fb22c88b9fcc2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/source.lua
@@ -0,0 +1 @@
+function() end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d1155e113362d84719680e4696245a9a2b1913bf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-3/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/function-3
+
+---
+- 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: Symbol
+    symbol: (
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 14
+    line: 1
+    character: 15
+  end_position:
+    bytes: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3d453548bec0cd6f9bc032d296b1a18911672599
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..43856080a3bbd6738af718b9dbee76fa400ed498
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/function-4
+---
+function x()end
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2eba71d8498b318528f8a9b8f9ef540cf3dd04f2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a7b350d2e034edd0a1de1974e2ee7676f7769953
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..447d4a177bf23efe38efa8de177524932fa87871
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/source.lua
@@ -0,0 +1 @@
+function x(
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7ae41340cd4224f94ff4d7a0000a4a39e06f0553
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-4/tokens.snap
@@ -0,0 +1,61 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/function-4
+
+---
+- 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: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..87d5c55d033135cf417ca54efb0c10cf57745399
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/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-5
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..91e673b7f411eed0164401d205b527c1f2e3f7d1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/function-5
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cec5bb6b0ab35c63dfb500de5c71a3f1fbc89cb8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3444232458edf6e1b48a94982ba3f37233d9e9f6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..c6fc78628a8264d16b3d9012af00cebf79c26d0e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/source.lua
@@ -0,0 +1 @@
+function local() end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1d1464292cb90a0470c9fea8cb681d3a642cefa1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-5/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/function-5
+
+---
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: local
+- 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: 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: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bc1697614d6b3e871967e07b06491a88fb1bb0bf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e7cd0ba7dff0f64ce8e4a3776b185c498b89cb28
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/function-6
+---
+function x()end
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2153c8672e10b360faef2ea3e7bd275d5e190eb2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b9ee670c161e35ce2e20c1039abd1dc86a10a65b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..dc4f65057b9f64bc4264df33530872aafb4ba6e3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/source.lua
@@ -0,0 +1 @@
+function x()
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..81f1cb73074675eb8bd40c8fbcacac69fac02241
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-6/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/function-6
+
+---
+- 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: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 13
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 12
+    line: 1
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..fc5e2f60a0b9e83a6e5ed8a9603f2dfc99808377
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..245a4a88b65a8e84ad6e590ae00c3e8cf5cd2c9b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/function-7
+---
+function x(...)end
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..67de43c3f2840c67880abcd9ad02f32bd11d56c8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..55df5d9f99da4d92e4eb2aaa6a0b2f4e1e3e6b5d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f628947310d7d53f8ec9d211d7436fc02bd42f74
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/source.lua
@@ -0,0 +1,2 @@
+function x(..., a)
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..463022fc3357b2a4154c710824ce17348d8447fb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-7/tokens.snap
@@ -0,0 +1,138 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/function-7
+
+---
+- 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: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 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: 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: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: a
+- 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: 22
+    line: 2
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 22
+    line: 2
+    character: 4
+  end_position:
+    bytes: 22
+    line: 2
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..afa57b903ed80d12b07290f796c3005e962c596f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/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-8
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c19595d0ca7c2a0ebf3b1845f9d0951f8c7c0b0e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/function-8
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bc83b3fe913cef9206fd75cfdcf7367d129a8478
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..11c643febda6ae3a064009ef6f9cb6138572a2e7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..7f185b65a907ec6c1ec738634eefabd65a9108e8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/source.lua
@@ -0,0 +1 @@
+function name:3() end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c9ff1ce7796243666f5e86f6e60c232e7512b4c7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/function-8/tokens.snap
@@ -0,0 +1,116 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/function-8
+
+---
+- 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: 13
+    line: 1
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: name
+- 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: Number
+    text: "3"
+- 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: 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: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 21
+    line: 1
+    character: 22
+  end_position:
+    bytes: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a53668a6edeec34fe40a0883d6981950eb98419f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/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/generic-for-1
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1c545d69a9f7d139a3f8003e22b8533a53fad00a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/generic-for-1
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..27048f70c844a4cc53e3f7f28490eb1421e7ff0e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..99949dca80c1d14aac69ebad66679803958044e5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f433096f9affec2ea127d0905bb070f41f40cab7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/source.lua
@@ -0,0 +1 @@
+for x in
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9952424c2aebf83253f9f0a36c78b1f5baec37bd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-1/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/generic-for-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: Identifier
+    identifier: x
+- 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: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: in
+- start_position:
+    bytes: 8
+    line: 1
+    character: 9
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..578e0015b089fe36c418b426ba273d4033978dfc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..920bfe9e8b527b2826dd09ba4c2cdbda2958ae34
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/generic-for-2
+---
+for x in pairs(y)doend
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..67fae56e89b4ecac6dcb2dedcfee3971972c6e24
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8f834d21eae344b77930628d5eb238cc88689b92
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..88e9a0b7d60e678b5e381ad1bcfce3e1ea12e376
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/source.lua
@@ -0,0 +1 @@
+for x in pairs(y)
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f3f3f884f2f7030bb88fe96f9c5fd2bed02d430d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-2/tokens.snap
@@ -0,0 +1,127 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/generic-for-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: Identifier
+    identifier: x
+- 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: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: in
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: pairs
+- 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: Identifier
+    identifier: y
+- 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: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7972c504c902f46aa434928260c72beea2d10f81
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f739f29bde124dbfcf9995ae30fadfd54e838c91
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/generic-for-3
+---
+for x in pairs(y) doend
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2e9cf822cd62e723447da3a454205878cba40863
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a7760826323e85a39b8e297456e3c5cf4b98b24a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..1636a9e1fc6a38aca6f91108a2b1222e7aff7e33
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/source.lua
@@ -0,0 +1 @@
+for x in pairs(y) do
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e4ef33dd9da2c3ee756561076f680c7eaa252917
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-3/tokens.snap
@@ -0,0 +1,149 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/generic-for-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: Identifier
+    identifier: x
+- 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: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: in
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: pairs
+- 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: Identifier
+    identifier: y
+- 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: Whitespace
+    characters: " "
+- start_position:
+    bytes: 18
+    line: 1
+    character: 19
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9ebd07a61eb5e951efaab78146793b2072da8662
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..80b3ee21f328ac81ed272b040f40c0efa80be23c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/generic-for-4
+---
+pairs(list) do end
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..22df658980360f62c780c97ead1a8bd90f865b97
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c2e5d95d8958856ba0a172e98bc8003541a063d8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0ef1ebdaf4e1b4c789e6fc4c83e803b8aba38f60
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/source.lua
@@ -0,0 +1 @@
+for index, local in pairs(list) do end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..520288b7c6eeb0b0b3aa1fe9b8a3bcd31419c43b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/generic-for-4/tokens.snap
@@ -0,0 +1,204 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/generic-for-4
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: index
+- 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: local
+- 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: 19
+    line: 1
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: in
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 25
+    line: 1
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: pairs
+- 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: 30
+    line: 1
+    character: 31
+  token_type:
+    type: Identifier
+    identifier: list
+- start_position:
+    bytes: 30
+    line: 1
+    character: 31
+  end_position:
+    bytes: 31
+    line: 1
+    character: 32
+  token_type:
+    type: Symbol
+    symbol: )
+- 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: do
+- 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: 38
+    line: 1
+    character: 39
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 38
+    line: 1
+    character: 39
+  end_position:
+    bytes: 38
+    line: 1
+    character: 39
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..175f404d493ba5d6fe5e4f7d2fd6e0ffff051b0c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9a5d68df8ecdc9255387ac2bd3ebcdbc55919754
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/if-1
+---
+if x thenend
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..fcb0be217aa8f6018e87c52996f40aad8a7925b9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..19e156e53888ba2166bf03438e0b87e471e42ffa
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..a3f9a84a473694aef08e3804487de2198887436a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/source.lua
@@ -0,0 +1 @@
+if x then
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6cdda87bffc9f789564fbd7b5232f97fde1f1b4b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-1/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/if-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 9
+    line: 1
+    character: 10
+  end_position:
+    bytes: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c9be778194828f7eb5926dda09e6bc128738a217
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..748f4d41b7bf269b521c50dc1642eba7c3ae8f26
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/if-2
+---
+"if x then\nelse\n\tcall()end"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c69c5395bbbbcd56c1a38fa99a445efd0be0ec19
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e06a89615923641a206b357b3c8909776f1549bb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..76b5f4e03d524513200c2a98eaafd31b45243576
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/source.lua
@@ -0,0 +1,3 @@
+if x then
+else
+	call()
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1effc926137e3b41368f385e275cd0937dc5e250
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-2/tokens.snap
@@ -0,0 +1,149 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/if-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: then
+- 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: 14
+    line: 2
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 14
+    line: 2
+    character: 5
+  end_position:
+    bytes: 15
+    line: 2
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 3
+    character: 1
+  end_position:
+    bytes: 16
+    line: 3
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 16
+    line: 3
+    character: 2
+  end_position:
+    bytes: 20
+    line: 3
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 20
+    line: 3
+    character: 6
+  end_position:
+    bytes: 21
+    line: 3
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 21
+    line: 3
+    character: 7
+  end_position:
+    bytes: 22
+    line: 3
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 22
+    line: 3
+    character: 8
+  end_position:
+    bytes: 22
+    line: 3
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1ec7da5e8b1dea944a1e08bd23fe63acb11d1e11
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-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/if-3
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..fe1b1c2c9b5c675187a4e8c57f5833c455d59c80
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/if-3
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b1b5b87cf458fb30b8332e7704b2b8d60da1fa1d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ea1d4d90e4e2b02cc106b64089c9e2ca411a5150
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..11aed1fa0ea2879e7d2bddf8b7ae87d11f85cc3b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/source.lua
@@ -0,0 +1 @@
+if local then end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1eed2f7ab9f2b73c0d29cd0563b9fb84bfd99959
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-3/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/if-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: local
+- 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: 13
+    line: 1
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: then
+- 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: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 17
+    line: 1
+    character: 18
+  end_position:
+    bytes: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..482fc269435878e68d1f9d395e6b2eecbadbd44c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1adf8e810d916988af4f8d155d72fe1387a7df33
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/if-4
+---
+"if x then\nelseif y thenend"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a4493dd0b617303f6505eab8eebcf891bfb1e803
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4e4d976334794a301505da2cda6d076b3cdcc7a7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..fcaba29b7fabd4c6d148ab6ad2876396c9670541
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/source.lua
@@ -0,0 +1,2 @@
+if x then
+elseif y then
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7a3e1820f56365a5be2cc31963d74c33cb7fb0da
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-4/tokens.snap
@@ -0,0 +1,138 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/if-4
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: then
+- 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: 16
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: elseif
+- start_position:
+    bytes: 16
+    line: 2
+    character: 7
+  end_position:
+    bytes: 17
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 17
+    line: 2
+    character: 8
+  end_position:
+    bytes: 18
+    line: 2
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 18
+    line: 2
+    character: 9
+  end_position:
+    bytes: 19
+    line: 2
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 19
+    line: 2
+    character: 10
+  end_position:
+    bytes: 23
+    line: 2
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 23
+    line: 2
+    character: 14
+  end_position:
+    bytes: 23
+    line: 2
+    character: 14
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2a9e911167c57f0bf9679b03f442302f7f7ee2ee
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f7343c4eb59ccd36ddcb194306e60c6a24901d08
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c47c9ef31f4982429d54ddd2b407ff59d4ad1d4d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9af48a5ac3437b30ad9bd51f5d68ee30e2572979
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..31487e7f626406b6521e4995c0aa8f1bd69940e5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/source.lua
@@ -0,0 +1,7 @@
+if x then
+	call1()
+else
+	call2()
+elseif y then
+	call3()
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d381cb1fd821fd1616247827c41339fb6fd85eeb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-5/tokens.snap
@@ -0,0 +1,347 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/if-5
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: then
+- 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: 11
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 11
+    line: 2
+    character: 2
+  end_position:
+    bytes: 16
+    line: 2
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: call1
+- start_position:
+    bytes: 16
+    line: 2
+    character: 7
+  end_position:
+    bytes: 17
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 17
+    line: 2
+    character: 8
+  end_position:
+    bytes: 18
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 18
+    line: 2
+    character: 9
+  end_position:
+    bytes: 19
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 19
+    line: 3
+    character: 1
+  end_position:
+    bytes: 23
+    line: 3
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 23
+    line: 3
+    character: 5
+  end_position:
+    bytes: 24
+    line: 3
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 24
+    line: 4
+    character: 1
+  end_position:
+    bytes: 25
+    line: 4
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 25
+    line: 4
+    character: 2
+  end_position:
+    bytes: 30
+    line: 4
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: call2
+- start_position:
+    bytes: 30
+    line: 4
+    character: 7
+  end_position:
+    bytes: 31
+    line: 4
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 31
+    line: 4
+    character: 8
+  end_position:
+    bytes: 32
+    line: 4
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 32
+    line: 4
+    character: 9
+  end_position:
+    bytes: 33
+    line: 4
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 33
+    line: 5
+    character: 1
+  end_position:
+    bytes: 39
+    line: 5
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: elseif
+- start_position:
+    bytes: 39
+    line: 5
+    character: 7
+  end_position:
+    bytes: 40
+    line: 5
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 40
+    line: 5
+    character: 8
+  end_position:
+    bytes: 41
+    line: 5
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 41
+    line: 5
+    character: 9
+  end_position:
+    bytes: 42
+    line: 5
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 42
+    line: 5
+    character: 10
+  end_position:
+    bytes: 46
+    line: 5
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 46
+    line: 5
+    character: 14
+  end_position:
+    bytes: 47
+    line: 5
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 47
+    line: 6
+    character: 1
+  end_position:
+    bytes: 48
+    line: 6
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 48
+    line: 6
+    character: 2
+  end_position:
+    bytes: 53
+    line: 6
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: call3
+- start_position:
+    bytes: 53
+    line: 6
+    character: 7
+  end_position:
+    bytes: 54
+    line: 6
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 54
+    line: 6
+    character: 8
+  end_position:
+    bytes: 55
+    line: 6
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 55
+    line: 6
+    character: 9
+  end_position:
+    bytes: 56
+    line: 6
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 56
+    line: 7
+    character: 1
+  end_position:
+    bytes: 59
+    line: 7
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 59
+    line: 7
+    character: 4
+  end_position:
+    bytes: 59
+    line: 7
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f632be91ba0fd394e7142b5ec60519b6d844234c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bd3740cbb20d4eae98f57858d48b19f8a5bcce15
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/if-6
+---
+"if x then\nelse end\tcall()\n"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c8f4e2544a577149da9d951ae2f7055767fbd095
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..25bf982ae7bd0c236aff4cf9b34a737dc350f9b3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..eac8a784df1e575714def2606bcd646dfb9ddea8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/source.lua
@@ -0,0 +1,4 @@
+if x then
+else then
+	call()
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6559e117db226eb08ba4929e34b917bdbb5d52a4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-6/tokens.snap
@@ -0,0 +1,193 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/if-6
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: then
+- 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: 14
+    line: 2
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 14
+    line: 2
+    character: 5
+  end_position:
+    bytes: 15
+    line: 2
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 15
+    line: 2
+    character: 6
+  end_position:
+    bytes: 19
+    line: 2
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 19
+    line: 2
+    character: 10
+  end_position:
+    bytes: 20
+    line: 2
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 20
+    line: 3
+    character: 1
+  end_position:
+    bytes: 21
+    line: 3
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 21
+    line: 3
+    character: 2
+  end_position:
+    bytes: 25
+    line: 3
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 25
+    line: 3
+    character: 6
+  end_position:
+    bytes: 26
+    line: 3
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 26
+    line: 3
+    character: 7
+  end_position:
+    bytes: 27
+    line: 3
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 27
+    line: 3
+    character: 8
+  end_position:
+    bytes: 28
+    line: 3
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 28
+    line: 4
+    character: 1
+  end_position:
+    bytes: 31
+    line: 4
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 31
+    line: 4
+    character: 4
+  end_position:
+    bytes: 31
+    line: 4
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a8bee9d91a2f812c9e0615e233bbc338983d3848
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..942af31f4625ca007eb587238ddde366eebb8fb9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/if-7
+---
+"if x then do\nendend"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ee217fae2d801b0fae909417a70ea64ad7f6a53c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e3e0debd8597173d1717b28a96f74700f16c79d6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..40a78b9522c46ab625f71318ad5f7c5e919e5fde
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/source.lua
@@ -0,0 +1,2 @@
+if x then do
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..660eb1b5d5050f4037b57559b0808b2bdc40f0c8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/if-7/tokens.snap
@@ -0,0 +1,116 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/if-7
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: then
+- 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: 12
+    line: 1
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 13
+    line: 1
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 13
+    line: 2
+    character: 1
+  end_position:
+    bytes: 16
+    line: 2
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 16
+    line: 2
+    character: 4
+  end_position:
+    bytes: 16
+    line: 2
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..222e0dec1e1b9b00fae4e31da4c04090de09a1de
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/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/index-1
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bd24341fe3cd3d802682e77ccaaba8d14f5b7bcb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/index-1
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9c69eac1a3098576d58e9f6572f94f7f50ab428e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..dfb0f21989831310c3bff4523b0a70e0f503e67e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..5073f14eb3b44fb291141514ea8d08e8084eb968
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/source.lua
@@ -0,0 +1 @@
+x[2
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c7666f35a265f8163fc9ca816a236337473015a4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-1/tokens.snap
@@ -0,0 +1,50 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/index-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 1
+    line: 1
+    character: 2
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9b6dfa6a561d37590f820f33ffde2ebc0d1fd48d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/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/index-2
+---
+nodes:
+  stmts: []
+eof:
+  leading_trivia: []
+  token:
+    start_position:
+      bytes: 2
+      line: 1
+      character: 3
+    end_position:
+      bytes: 2
+      line: 1
+      character: 3
+    token_type:
+      type: Eof
+  trailing_trivia: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..929be64c46cde6cbf3dee88b73129a0d47d625b2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/index-2
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8c235bac74208a863b4005078fdf32f735d730e7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..feb31115d55ffce3a103cd74c10959778a8522b4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..4ba02ce0053d72d3333c85777dae519427cb0fba
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/source.lua
@@ -0,0 +1 @@
+x[
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a7314f44001def67515be7a26e0cfb278e27e142
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-2/tokens.snap
@@ -0,0 +1,39 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/index-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 1
+    line: 1
+    character: 2
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..71001217e22063877530ea4d4b5dce0d4ea427d9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-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/index-3
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9603cdc42d7466a1bab518d0a8e47b0c4c76d19d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/index-3
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5a4c49c382088c035d97093c39bdc643ea1c29b9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..76ffc51c273ee33f0272f27ce183e5e41d83997f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..96f85a9d93222463a20c9f6e6eed2d7f0d460aa1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/source.lua
@@ -0,0 +1 @@
+x[] = 1
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..65167c72a49b408f2b1a420bae4bb435e5d968a7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-3/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/index-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 1
+    line: 1
+    character: 2
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "["
+- 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: Symbol
+    symbol: "="
+- 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: Number
+    text: "1"
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5b390d31017cd5b297cf9fc491427822c5096ceb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2c4d24a33d59476e97f4a9c4ea31a5776a5818db
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/index-4
+---
+local y = x
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..69b67390f3482860aad56bc3221437ec11f37245
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c640f83f66c0e7f13f6640e97a85030a7d26235f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..92169c410006ea0f43fa469a529614005418286a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/source.lua
@@ -0,0 +1 @@
+local y = x[end]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7cb056ba3dc01986f7655dba80ea5b25ed599f18
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-4/tokens.snap
@@ -0,0 +1,127 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/index-4
+
+---
+- 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: y
+- 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: Identifier
+    identifier: x
+- 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: 15
+    line: 1
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: end
+- 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7440fbe50b45a14b33ebd25fb2375cdc75132fea
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5358da6503875cc10c72e14c87e7e7fdae9dfaab
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/index-5
+---
+return name
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7fd11fc6b063ac637f4f785019e96e51f9c7f7f8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c086086bd37aafcdaf8eab8b012e9c0c1db4092b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..ebc7fd017aab6fb3745fddfafea496a4d75e1fda
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/source.lua
@@ -0,0 +1 @@
+return name.until
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..faaa37d9f4d9f91cafa60664420ee29131409331
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/index-5/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/index-5
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: name
+- 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: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: until
+- start_position:
+    bytes: 17
+    line: 1
+    character: 18
+  end_position:
+    bytes: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a85c6eb6c0e06cb4d2b6ab182e253d31619c3612
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/ast.snap
@@ -0,0 +1,292 @@
+---
+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:
+            generics: ~
+            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: []
+            type_specifiers: []
+            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/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a8f0478edd6a4a0cad4db9d6d0edd637bd586e72
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::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/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..aa58c7139d60098b43214dbf9d146898192c2a00
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d08c245eff153df28508e6196ee2dc0809a1ec05
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..82fa7719b6bc5875081253e4b72de88d0dec8be4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/source.lua
@@ -0,0 +1,4 @@
+local function x()
+	return 1
+	return 2
+end
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/last-stmt-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..63be35e326ff5bcf45f35e48a4f42dc90330d62b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ae6bfc2a24025b8cc086412248a5142c6b478efa
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..460d2b6458505e166d2098e6ad6adaa8ba17684a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-assignment-1
+---
+"local x "
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ef5a06f1770e55e0d6746ebb9963ca71a98e5296
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c96d532124f818ae8fa7ecdf5899440198fe9bd7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0cf360b38e3ba5a7dd4ce77ae4e2f1817980b47a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/source.lua
@@ -0,0 +1 @@
+local x y
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d6f53d923d4921af1f18e1e7e9ffbc573397b3d5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-1/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/local-assignment-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: 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: Identifier
+    identifier: y
+- start_position:
+    bytes: 9
+    line: 1
+    character: 10
+  end_position:
+    bytes: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..59339fecf1c0b2d71389b08456b1a7aae562c8ea
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6e832ffeb306ae0713e25fbfddaa3c45322e03f7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-assignment-2
+---
+local x =
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2d3cc9bc4ffa169fee4af84757394e60f95483da
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..96c0cc2aa334cc95e1bfd20b90248c0bc9da3a40
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2c2dc7b9e5f03fb0c774a9e0ace9dc6d2471d6b1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/source.lua
@@ -0,0 +1 @@
+local x =
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..fa211a7d8ea15a1437e973c04a23f3b5544d2c87
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-2/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/local-assignment-2
+
+---
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ae264791d9c3c8011174c6fa1016213abd50b747
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..abf8f3d5f5fbdc41d73dcb338bf7747ea6267c09
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-assignment-3
+---
+local x = 1
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..df0ad91634d3ae3a442de2ba7fb2cb1407b69600
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..803e6f8620d928b827110080e89978ee227ed004
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..300b32197ec3dca35c6b86d7d621757d5d8deee0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/source.lua
@@ -0,0 +1 @@
+local x = 1,
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b93054fcfcb02ec9bb0de403f189fc03f7fd9a79
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-3/tokens.snap
@@ -0,0 +1,105 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/local-assignment-3
+
+---
+- 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: Number
+    text: "1"
+- 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: 12
+    line: 1
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c2680a6d4b38cb4c586e97d2cc7351519d901335
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/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/local-assignment-4
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0c38b06a45ec540af2451482cdecbd39a63165d0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-assignment-4
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1e8474d97a19ef6195b4857bdc245381f1f0489d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0986aef8761ef48122afd5d151c69c0bf3e1422c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8caefb4edddcde0411600a3d7c333fcddc1e9baa
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/source.lua
@@ -0,0 +1 @@
+local end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..75376bb336f447df8e363cc79a92828831f585e0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-4/tokens.snap
@@ -0,0 +1,50 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/local-assignment-4
+
+---
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 9
+    line: 1
+    character: 10
+  end_position:
+    bytes: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b0996b9e2e53a938354d7bad509f8e9aad3e24bd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..176d6100caeb3c34381a15b043b60c15257b5816
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-assignment-5
+---
+"local x = "
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a0e10c7850c663f4ffe330f414d3c73a46798a98
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..24481c2eb56cbc0ade2de04c764d0a4a76830720
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..3f05e71f2542416b9c7eb5d205502f296296bc64
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/source.lua
@@ -0,0 +1 @@
+local x = end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..79c63ff56f14a9986b2dcdad6784ee7c9a644838
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-5/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/local-assignment-5
+
+---
+- 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: Symbol
+    symbol: end
+- start_position:
+    bytes: 13
+    line: 1
+    character: 14
+  end_position:
+    bytes: 13
+    line: 1
+    character: 14
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c028da3662519a17e9d6d917f077193ad587edc3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f2e679fd3329658770ed515d232f85b5fd13e15b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-assignment-6
+---
+"local x =\nlocal y = 2\n"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5a0551bf93410479ab1292c8cbb5fdce4e78c131
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4cd3d0c482b4dcc65f8ae0d07280e6279a870dbd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..19f15f419a89c400c320278d08fc09610a5cca20
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/source.lua
@@ -0,0 +1,2 @@
+local x =
+local y = 2
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-assignment-6/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f139ed2f23e4a9029789825789e962576559bd8c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8f35e17d6f6bbc41d7f2fccfd7db5d3ecc8f7a45
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/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/local-function-1
+---
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8d76b470bc3e5ed9e19187004103570256c98c31
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-function-1
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b0f0828bd454361ab90f5be51decb088d8778a21
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..df14f81b3438fde5ca26c84275cc10df5d3439bc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..4ed1c4ee1afbd62c1784ae37391e157ac29e959b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/source.lua
@@ -0,0 +1 @@
+local function
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..715bb932194148612d8b2e6f85ce15a35eb22b7c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-1/tokens.snap
@@ -0,0 +1,50 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/local-function-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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b8d987d67a2d4618bb9f26a1727c254008318637
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/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/local-function-2
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ce98dbbd355efdb9167e5763f2f7592e4709796c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-function-2
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bcac5b4cd3b3a5b8d948151b88ccb1a246e16593
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..deacbda1040cee869446f7b615424e50fa42038c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..71294aa321d4266f8cd1b0aa5c2fb1cc4b306c8b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/source.lua
@@ -0,0 +1 @@
+local function x
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cbecbfdadad33cb1d198f0f157f5fef62ea12788
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-2/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/local-function-2
+
+---
+- 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a773c2b70715ec776357fbf73fdfd258bc4873e2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..dcd065bc88adc126f4c4e800949a7de82d5beb6e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-function-3
+---
+local function x()end
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5869ede9a8a2fb8d47fb20c5145a328eab6687b8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9eb9335c6acb01f6fc16d18048141746c9977d5f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..77406ec971ec3aaca37d4525b132527611ec674f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/source.lua
@@ -0,0 +1 @@
+local function x(
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cda814402975d5b424393bdb5041e8b0a4eb3fda
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-3/tokens.snap
@@ -0,0 +1,83 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/local-function-3
+
+---
+- 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: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4a10477cbf0adb9a0b2e39de7494d6308d71f7fe
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ac7252d66f3cdff17e2282ccdd01846dbcdb47c0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-function-4
+---
+"local function x()\n\tcall()end"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6f3e49e12ccefdba884742fe361a42de1b79d708
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5af4c8dcdc226946abca16a0eddb1e0c79c72e38
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..331172a3f721eacee237f197b0e246b0052c0032
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/source.lua
@@ -0,0 +1,2 @@
+local function x()
+	call()
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b0627c737e825a21fb1fda8f937ef34df3ba6bc5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-4/tokens.snap
@@ -0,0 +1,149 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/local-function-4
+
+---
+- 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: 24
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 24
+    line: 2
+    character: 6
+  end_position:
+    bytes: 25
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 25
+    line: 2
+    character: 7
+  end_position:
+    bytes: 26
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 26
+    line: 2
+    character: 8
+  end_position:
+    bytes: 26
+    line: 2
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0b5cf6080f132d43a5aa067a4ef75ff1a7ae1cdb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..de523db4473eda33b301e8d34667685fbb81d074
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-function-5
+---
+"\tcall()\n"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1dfd6ef626b9c9e789f027eedc256b6b8ae07498
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..62ba729e21dc0ed73698d5ab863ce1c148764e69
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..da8ec8e722d9a6c5b167edbe473b3233e6abdd15
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/source.lua
@@ -0,0 +1,3 @@
+local function do()
+	call()
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..033bdb9e185df42940edde99262bc2dec3156c1c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-5/tokens.snap
@@ -0,0 +1,171 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/local-function-5
+
+---
+- 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: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: do
+- 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: 20
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 20
+    line: 1
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 20
+    line: 2
+    character: 1
+  end_position:
+    bytes: 21
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 21
+    line: 2
+    character: 2
+  end_position:
+    bytes: 25
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 25
+    line: 2
+    character: 6
+  end_position:
+    bytes: 26
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 26
+    line: 2
+    character: 7
+  end_position:
+    bytes: 27
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 27
+    line: 2
+    character: 8
+  end_position:
+    bytes: 28
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 28
+    line: 3
+    character: 1
+  end_position:
+    bytes: 31
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 31
+    line: 3
+    character: 4
+  end_position:
+    bytes: 31
+    line: 3
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e78329aadda9ca8a34e968643ad0a31f4d5a72b6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0c52e3cbfef9aa5a5cd585c3153c97832ad518cc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/local-function-6
+---
+local function x()end
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f975547be845a56e442757c0c88efeb83d270ef2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e362a18e3323196b60996ade0f0b2ece1e9c989e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..c336e50fac229bc8d66560a99a9defd9049417d7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/source.lua
@@ -0,0 +1,2 @@
+local function x(,,,)
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e9f5a5605799ab10b4f68c3cc2252aba7b9638a4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-6/tokens.snap
@@ -0,0 +1,149 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/local-function-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: 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: 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: Symbol
+    symbol: ","
+- 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: 22
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 22
+    line: 2
+    character: 1
+  end_position:
+    bytes: 25
+    line: 2
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 25
+    line: 2
+    character: 4
+  end_position:
+    bytes: 25
+    line: 2
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e7e3d4c8c987a56a62e1b6698f034922dad3e2b0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1220ccdc504db1b7c481050e2d25c84957815ae7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5eeef31cdb311385c5569acf78a61bf914ec2c95
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9d5612ccbe906817d9b1b9a5975484e1d2b7f853
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..504b767851a30193242afdd77747a15dce986cbd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/local-function-7/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f7d41dc317be00fa8d3133d18e050ea307345694
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..10cea19b2a0020ff4d74a9688ab63ba059d36ad0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..34862c5a9473231f0ec2fc277e9a3b3dc5a5f680
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/method-call-1
+---
+return name
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..30fe852b1652331e979dd5cf9fb0fa477c4f4253
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7ec3fb30bfb5218714638d86341b189d9621e25a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0f7db618c4ddc75bfe56e889fa2b58d48b02a62c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/source.lua
@@ -0,0 +1 @@
+return name:
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b8f4c4345513da039c4001cef868687a379abcf2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-1/tokens.snap
@@ -0,0 +1,61 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/method-call-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: name
+- 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: 12
+    line: 1
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..249ed2dedbd3d06af70a06ffb06097502637e09d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b2bfc3fcaf8f0643267c3a03ec09625551460605
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/method-call-2
+---
+"return name:method()"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2fbc475f72211455041feafb2d288956cdf34e5a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..87bf91f99a9e18f2d0d483f3a43374cf88c6cf32
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..31c242137becd656c8116c1f166ba515bd72fd51
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/source.lua
@@ -0,0 +1 @@
+return name:method
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e27b8bc2f9fbc1f42b44c0be2c6aa6c78b28e8a1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-2/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/method-call-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: name
+- 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: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: method
+- start_position:
+    bytes: 18
+    line: 1
+    character: 19
+  end_position:
+    bytes: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9135a8022e0747d03786ac92bccb9594589aa962
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..753afafe66c1b17ff60fa8e290c8ec4e33ab8fdf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/method-call-3
+---
+"return name:method()"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3d5571a1511caeecd5c9fe8443116ca0f20ec4d3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7d92bd966e23e998095491b3d494c1f47d6cb5c1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..429cba6ffa10899eb08518fecbb57875729b7c8b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/source.lua
@@ -0,0 +1 @@
+return name:method(until)
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a4b10b3c53012fd1a33fb34cf25f4e85f193ce7d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/method-call-3/tokens.snap
@@ -0,0 +1,105 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/method-call-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: name
+- 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: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: method
+- 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: 24
+    line: 1
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: until
+- 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: 25
+    line: 1
+    character: 26
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..50bd5002485d0c57408fae57e66c88f6dd896966
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/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/numeric-for-1
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..363e04143ddc77bff490cbe59258ca430aebd43b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/numeric-for-1
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cdc726b12cb83bf7f928eb6c2c6b182d429d20bf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c2a73d30c64652f62708d95399d972271b5e5d7f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0c7580fbd55234e2f33b547ea7cbf4a0199cc81f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/source.lua
@@ -0,0 +1 @@
+for x
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e164a83469a4048209043a3a7f7c5020b1d9bc36
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-1/tokens.snap
@@ -0,0 +1,50 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/numeric-for-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: Identifier
+    identifier: x
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..547db2e22765bd1d546ae5c9696d049fed493304
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/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/numeric-for-2
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..70fc306dd5b5ac6e4ce678ae2b10ae6881cc5b94
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/numeric-for-2
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f73b49c048d3ff106c51042e7810410a9ce4e182
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7204f02399c901deea3a8fa14107c66c20251d7b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..1f74b3d40e68aa5670e5dbc38ddf87e4f8cea61f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/source.lua
@@ -0,0 +1 @@
+for x =
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9e7fbad166897de718f777f61696ed899df421b1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-2/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/numeric-for-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: Identifier
+    identifier: x
+- 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: Symbol
+    symbol: "="
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8fed389ee9a7fe7b028d7e15fe96230da53ceb7e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-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/numeric-for-3
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9fb0dbedfbae1e795fb369d480c31e89c31293c7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/numeric-for-3
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..920020088426c951f645c115f5d769706a3a1821
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e82f9db0ae4c79c2f5c4de06ce23f7081cc79fd9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f4d3b123d5ec5d334e698ebc4132d271a01b656e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/source.lua
@@ -0,0 +1 @@
+for x = 1
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c8d19ffde936df174b87edb851f1795c2f54321f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-3/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/numeric-for-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: Identifier
+    identifier: x
+- 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: Symbol
+    symbol: "="
+- 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: Number
+    text: "1"
+- start_position:
+    bytes: 9
+    line: 1
+    character: 10
+  end_position:
+    bytes: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..92be5c7f3b34d6dfb671230dfcadd0ce18910e89
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..395156c092edb476706e054554f544bef34925a8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/numeric-for-4
+---
+"for x = 1, 10 doend"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d6a949819f39d87cd4499c42baf4b19033dde88b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5a548ac903e71e88fb401a143eaed92ff9b71e9f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0d07ab005349139f949327e6b1b59ca482d32af2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/source.lua
@@ -0,0 +1 @@
+for x = 1, 10 do
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3e9336960139b98dd54c8c24e514bd73e6210979
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-4/tokens.snap
@@ -0,0 +1,149 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/numeric-for-4
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: Identifier
+    identifier: x
+- 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: Symbol
+    symbol: "="
+- 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: Number
+    text: "1"
+- 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: 13
+    line: 1
+    character: 14
+  token_type:
+    type: Number
+    text: "10"
+- 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 16
+    line: 1
+    character: 17
+  end_position:
+    bytes: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2ef9e72370685117cc2ae826b93781f09227865a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bc70ea9e65bb3f67831bc60b9d8e44ada365b08a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/numeric-for-5
+---
+do end
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6dd956acde3eeac9b63cac8d4612434ece0d7dea
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b9069091cd820feeaf8db9c3eb2804ee081d0bc1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..45af1fab8f3468d2514cd9ffe501bfd56fa8b863
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/source.lua
@@ -0,0 +1 @@
+for local = 1, 10 do end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6d0e42a24ff6b43ea15f12b170766536dd80d4e5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/numeric-for-5/tokens.snap
@@ -0,0 +1,171 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/numeric-for-5
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: local
+- 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: 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: Number
+    text: "1"
+- 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: Number
+    text: "10"
+- 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: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 21
+    line: 1
+    character: 22
+  end_position:
+    bytes: 24
+    line: 1
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 24
+    line: 1
+    character: 25
+  end_position:
+    bytes: 24
+    line: 1
+    character: 25
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9a618d3f99a7ab68aeaf7b9afb275452ec7d86bd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5f9ff840359585f180b2834ba66f96f7369dc937
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/paren-expression-1
+---
+"return "
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3fbcc487cbe870129eab9f8a723607ae52650068
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..94c958e99652af787a390f1ee1da084a481d4adf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..498797ac04a166e7ad1493a94717c06c298da6ae
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/source.lua
@@ -0,0 +1 @@
+return (
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..17476f3c50561e57579303090097f0e0e8252a89
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-1/tokens.snap
@@ -0,0 +1,50 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/paren-expression-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 8
+    line: 1
+    character: 9
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a1bed51048e45062f9d295a25dba1f08ede2b82e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e6a440014723035f9019a233566e9d81dc6a9793
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/paren-expression-2
+---
+"return (3), 4"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f9bdf54885876896bb0bb4a286e91d563b7bc8f2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..87e5d06e78b76386476905bb55b06a63c0460672
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..b60c08d971161f7ea34fcf3c6010f325fc98b95c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/source.lua
@@ -0,0 +1 @@
+return (3, 4
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..055a1c059888f0dc27528a3a3f24b458acdc083b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-2/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/paren-expression-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 8
+    line: 1
+    character: 9
+  end_position:
+    bytes: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Number
+    text: "3"
+- 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: Number
+    text: "4"
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 12
+    line: 1
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2729875cc27c3275854aa44ad62678f389df5fce
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..38dd977ea46c485f7cd7165723e0d5549216c9f3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/paren-expression-3
+---
+"return (3), 4"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f71cc90fb8791c1a90c623ac391ae3b2138b8188
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..39c04a7bd05ab74dec144e653260d3461adf6d52
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2ae24baed03959c0ca9de0fd002f71d3764ed63e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/source.lua
@@ -0,0 +1 @@
+return (3, 4,
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d2b2f69d943c07f7edd26e534706803cfad1d899
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-3/tokens.snap
@@ -0,0 +1,105 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/paren-expression-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 8
+    line: 1
+    character: 9
+  end_position:
+    bytes: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Number
+    text: "3"
+- 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: Number
+    text: "4"
+- 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: 13
+    line: 1
+    character: 14
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..81bfc7d2ee38be6c0882f92eb0525823a81870ec
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..dfbce515b4887f49d571400de8d35fe5048cae48
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/paren-expression-4
+---
+"return "
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0651705c1c3d29e7eb6648fc4b276cc22ce1a931
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a8953076c6518f6beab303a4ae8a35b0535816b5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..008b3d5c1754cc3a974a74173d94a8cb875b4234
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/source.lua
@@ -0,0 +1 @@
+return ()
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..52735c2fb88d146af927b97eb35cec4d0f1f6338
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-4/tokens.snap
@@ -0,0 +1,61 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/paren-expression-4
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: (
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..19f591f1d212fc7bcf0368c35fb1094fa3740fb4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e7b4acaa691f9bb8182f04c5049640f8a25304b0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/paren-expression-5
+---
+"return "
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f0a08736463530507f1be6c8bcef51944831b0aa
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7d3f51798633c48d41cb83ee1d29e7ec49b16131
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..91e91af97cbe67bfee5ba7660010d2f98ad3b387
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/source.lua
@@ -0,0 +1 @@
+return (until)
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a227c80b0d4d11dd34db8d61d3aa3924f2e84c00
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/paren-expression-5/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/paren-expression-5
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 8
+    line: 1
+    character: 9
+  end_position:
+    bytes: 13
+    line: 1
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: until
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f387c3cd64d3b74623bc681288d28d6c332c8823
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a2fdc4329f1d0de76f8756bce0a07042f53d29bd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/repeat-until-1
+---
+"do\n\nend"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bbc3c0f3678b525a1ecf1ffdf66c6229f14e592a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f9d9c70617d767fc8b33c905ce3cdcef9c920f39
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..04611be224fef867cb214f0ed7d7b6646edd8d08
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/source.lua
@@ -0,0 +1 @@
+repeat
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8bba2cde2ad894837a0ac3900cd8d9f75397ef9f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-1/tokens.snap
@@ -0,0 +1,28 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/repeat-until-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: repeat
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..49243233e777647aba7a53ac4100745d36716787
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ceaa951c773d733002bb3392ffe5378e30c35f59
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/repeat-until-2
+---
+"do\n\tcall()\nend"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..df4d7506b1d5d306e1c198649209d57ae5ee5774
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d3726ae89c85fd5d12efb3cd52fc03271e0de603
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..a263ef25120f6849ff8a68fefd7fa4c399269741
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/source.lua
@@ -0,0 +1,2 @@
+repeat
+	call()
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a9c3341eb4023dfd9e3071ebf464df37299315d3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-2/tokens.snap
@@ -0,0 +1,83 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/repeat-until-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: repeat
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 7
+    line: 2
+    character: 1
+  end_position:
+    bytes: 8
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 8
+    line: 2
+    character: 2
+  end_position:
+    bytes: 12
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 12
+    line: 2
+    character: 6
+  end_position:
+    bytes: 13
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 13
+    line: 2
+    character: 7
+  end_position:
+    bytes: 14
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 14
+    line: 2
+    character: 8
+  end_position:
+    bytes: 14
+    line: 2
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1ba3b873d16a0467e2c95ae7b32c9b3bcc585658
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1ab5241a533b490de16de817e4eee34fc0805877
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/repeat-until-3
+---
+"do\n\tcall()\n\nend"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d07697591a12ee00c23854efca45bf18533a7213
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..babdc5f4d1c3b5e0dbb46d7ee4bf38db4f16a6fe
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..e13a9379c33b6de3e5a9e53593d5717187c87945
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/source.lua
@@ -0,0 +1,3 @@
+repeat
+	call()
+until
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b9d2db4c3b783291464a5b991724885b08b12ae0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-3/tokens.snap
@@ -0,0 +1,105 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/repeat-until-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: repeat
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 7
+    line: 2
+    character: 1
+  end_position:
+    bytes: 8
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 8
+    line: 2
+    character: 2
+  end_position:
+    bytes: 12
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 12
+    line: 2
+    character: 6
+  end_position:
+    bytes: 13
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 13
+    line: 2
+    character: 7
+  end_position:
+    bytes: 14
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 14
+    line: 2
+    character: 8
+  end_position:
+    bytes: 15
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 3
+    character: 1
+  end_position:
+    bytes: 20
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: until
+- start_position:
+    bytes: 20
+    line: 3
+    character: 6
+  end_position:
+    bytes: 20
+    line: 3
+    character: 6
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6e35709d3b5b0b65a5027ef733003570aa25fb5e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ee53670a33222e14400beee8e2a18652aeaa6132
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/repeat-until-4
+---
+"do\n\tcall()\n\nend"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..39b0e1663830895286f6b54d02cb5ad00b564cd3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..03319562d5faa0e83bda7bf8cc1a4172c46d9b46
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..56da3c666b500639484c86504cf7c8d3df93000d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/source.lua
@@ -0,0 +1,3 @@
+repeat
+	call()
+until end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4195eacb22b12b4c66c8ee996ab994c94ebaa6bf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/repeat-until-4/tokens.snap
@@ -0,0 +1,127 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/repeat-until-4
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: repeat
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 7
+    line: 2
+    character: 1
+  end_position:
+    bytes: 8
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 8
+    line: 2
+    character: 2
+  end_position:
+    bytes: 12
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 12
+    line: 2
+    character: 6
+  end_position:
+    bytes: 13
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 13
+    line: 2
+    character: 7
+  end_position:
+    bytes: 14
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 14
+    line: 2
+    character: 8
+  end_position:
+    bytes: 15
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 3
+    character: 1
+  end_position:
+    bytes: 20
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: until
+- start_position:
+    bytes: 20
+    line: 3
+    character: 6
+  end_position:
+    bytes: 21
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 21
+    line: 3
+    character: 7
+  end_position:
+    bytes: 24
+    line: 3
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 24
+    line: 3
+    character: 10
+  end_position:
+    bytes: 24
+    line: 3
+    character: 10
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..58b9d344c90c15a8d78570e505e6c23c278346a6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..73f5712f05caef0778bf9e61cc8b89d497ff87ee
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/table-1
+---
+"return {}"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7ad52e5fddf0cb40d5fd94828e0fea41c498b4ef
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..77ace4f119a7a346dafbc77ea780f2cd76c1d017
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..23e3e4f4a44d0b8e23e11dcee2f72965ec8f80a7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/source.lua
@@ -0,0 +1 @@
+return {
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e1e72060143c6796ffc9460b3be6b7b764f8d793
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-1/tokens.snap
@@ -0,0 +1,50 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/table-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 8
+    line: 1
+    character: 9
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3a606172ae648f5a2c26074ca3d1e5d77d3bcf1a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..16718b2051f3bce4ef3d471291ba55c0691a4f8f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/table-2
+---
+"return {\n\ta = 1,}"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0951cb021ebd32ebd3808e9d59c14975e1abb5fe
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2f301a96175fc5e8a411ac5d140c4a309cb7c3bf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..99c33b1255e42dfc14bf426566df0959f1e3c26f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/source.lua
@@ -0,0 +1,2 @@
+return {
+	a = 1,
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f27fdbae858d6fafae90c6e31569282728688d21
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-2/tokens.snap
@@ -0,0 +1,138 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/table-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "{"
+- 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: 10
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 10
+    line: 2
+    character: 2
+  end_position:
+    bytes: 11
+    line: 2
+    character: 3
+  token_type:
+    type: Identifier
+    identifier: a
+- start_position:
+    bytes: 11
+    line: 2
+    character: 3
+  end_position:
+    bytes: 12
+    line: 2
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 12
+    line: 2
+    character: 4
+  end_position:
+    bytes: 13
+    line: 2
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 13
+    line: 2
+    character: 5
+  end_position:
+    bytes: 14
+    line: 2
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 14
+    line: 2
+    character: 6
+  end_position:
+    bytes: 15
+    line: 2
+    character: 7
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 15
+    line: 2
+    character: 7
+  end_position:
+    bytes: 16
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 16
+    line: 2
+    character: 8
+  end_position:
+    bytes: 16
+    line: 2
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..89fa71520f8abf8291df817462991c8b22fb69ec
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0748551eecad33113d7055ff322419b02f97b005
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/table-3
+---
+"return {\n}"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7608225a6545832e5ff697e256a1eb645a72ef77
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8374a65d1e316809f8123c905679d94e028bf1c3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f34b20b0f12d551429bc8329adb28ed803a05695
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/source.lua
@@ -0,0 +1,2 @@
+return {
+	a =
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..53557b98526d9cef380f3b65d87aa068e692a841
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-3/tokens.snap
@@ -0,0 +1,105 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/table-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "{"
+- 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: 10
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 10
+    line: 2
+    character: 2
+  end_position:
+    bytes: 11
+    line: 2
+    character: 3
+  token_type:
+    type: Identifier
+    identifier: a
+- start_position:
+    bytes: 11
+    line: 2
+    character: 3
+  end_position:
+    bytes: 12
+    line: 2
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 12
+    line: 2
+    character: 4
+  end_position:
+    bytes: 13
+    line: 2
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 13
+    line: 2
+    character: 5
+  end_position:
+    bytes: 13
+    line: 2
+    character: 5
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d96f796a6b36283ce1a5e536f77fc355eac1589e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d66c4a495bc2049a7012dedc4ca71f358f35bd52
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/table-4
+---
+"return { }"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7b15952565bdffacf06bd7c1d7b424ba87d018eb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f33beb1a658d9bfd907517ae19d5f0b2f853a695
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..163261ba2ec127ede84677dd4a750f8e4f94cbdd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/source.lua
@@ -0,0 +1 @@
+return { until }
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b6df8acc73d9ae769953cd6eff07744a6fb4640c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-4/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/table-4
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "{"
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: until
+- 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9cf4e57029cde470090dcdd52454501aecd44817
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3be3249a283d196494c6999f4ef6ee3af6bb320e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/table-5
+---
+"return {\n}"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..121aee3cbd74aba8bb3f6ce913b387e7e7dc1da7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5d2d3d61b8c558c477dcdf7c088805b842d9ee85
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..d7ba7765a03064e897d5f1d4b9571923479c7cb5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/source.lua
@@ -0,0 +1,3 @@
+return {
+	until = 1,
+}
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..58c636e30d72b098d4b63ee175e3585cf6f67e4f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-5/tokens.snap
@@ -0,0 +1,160 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/table-5
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "{"
+- 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: 10
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 10
+    line: 2
+    character: 2
+  end_position:
+    bytes: 15
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: until
+- start_position:
+    bytes: 15
+    line: 2
+    character: 7
+  end_position:
+    bytes: 16
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 16
+    line: 2
+    character: 8
+  end_position:
+    bytes: 17
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 17
+    line: 2
+    character: 9
+  end_position:
+    bytes: 18
+    line: 2
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 18
+    line: 2
+    character: 10
+  end_position:
+    bytes: 19
+    line: 2
+    character: 11
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 19
+    line: 2
+    character: 11
+  end_position:
+    bytes: 20
+    line: 2
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: ","
+- 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: 22
+    line: 3
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 22
+    line: 3
+    character: 2
+  end_position:
+    bytes: 22
+    line: 3
+    character: 2
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4505fdafda2d18a7b52ef0b82952ede07f431cbf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..40491c210d9bb9e96a2cd24b8a440bcb0264e007
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/table-6
+---
+"return {\n}"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..286e8f6f5c41396b36e67f058b76ed22ef46fc7f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e553ca921bd77e99dc40695efec867e809ffa4ad
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..38575b34630233f6a286b83df777f8c8dd600f85
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/source.lua
@@ -0,0 +1,3 @@
+return {
+	x = until,
+}
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e4e88c08aadf1d22db11e15591b6723fefb3362c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-6/tokens.snap
@@ -0,0 +1,160 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/table-6
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "{"
+- 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: 10
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 10
+    line: 2
+    character: 2
+  end_position:
+    bytes: 11
+    line: 2
+    character: 3
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 11
+    line: 2
+    character: 3
+  end_position:
+    bytes: 12
+    line: 2
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 12
+    line: 2
+    character: 4
+  end_position:
+    bytes: 13
+    line: 2
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 13
+    line: 2
+    character: 5
+  end_position:
+    bytes: 14
+    line: 2
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 14
+    line: 2
+    character: 6
+  end_position:
+    bytes: 19
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: until
+- start_position:
+    bytes: 19
+    line: 2
+    character: 11
+  end_position:
+    bytes: 20
+    line: 2
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: ","
+- 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: 22
+    line: 3
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 22
+    line: 3
+    character: 2
+  end_position:
+    bytes: 22
+    line: 3
+    character: 2
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b243fc3cdbf077fd191e9d91b346e39d0689b7da
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b1cb6febc11aaeb5c90d791f8e6673df78fbe6d4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/table-7
+---
+"return {\n}"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cc620248de909f1c0ae8dce440e94bc6a6244969
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b83763dc2319048cc047bd8d787043db6e550196
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..aca8efbfb43a780520b13d32bffd72724c828c61
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/source.lua
@@ -0,0 +1,3 @@
+return {
+	[until] = true,
+}
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2bf7f49d5c3e65fa73fea177300a337402406be1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-7/tokens.snap
@@ -0,0 +1,182 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/table-7
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "{"
+- 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: 10
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 10
+    line: 2
+    character: 2
+  end_position:
+    bytes: 11
+    line: 2
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 11
+    line: 2
+    character: 3
+  end_position:
+    bytes: 16
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: until
+- start_position:
+    bytes: 16
+    line: 2
+    character: 8
+  end_position:
+    bytes: 17
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 17
+    line: 2
+    character: 9
+  end_position:
+    bytes: 18
+    line: 2
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 18
+    line: 2
+    character: 10
+  end_position:
+    bytes: 19
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 19
+    line: 2
+    character: 11
+  end_position:
+    bytes: 20
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 20
+    line: 2
+    character: 12
+  end_position:
+    bytes: 24
+    line: 2
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 24
+    line: 2
+    character: 16
+  end_position:
+    bytes: 25
+    line: 2
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 25
+    line: 2
+    character: 17
+  end_position:
+    bytes: 26
+    line: 2
+    character: 17
+  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: 27
+    line: 3
+    character: 2
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0f781755cc5556f04cb6048e05cc9e8c7852c7be
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..286760f98405fa9d83e8c6751f53b551744588cb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/table-8
+---
+"return {\n}"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bc85e288320e2652f8bbfc122a70c430c21e52e1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c7358df81a649c51a03ffe7440aa48d58d5a0095
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0f02f728ee11d7e80272ef188b3e23a5f350f8ce
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/source.lua
@@ -0,0 +1,3 @@
+return {
+	[] = 1,
+}
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..52a393608d7cd88e76a0a1adb63c8a86f9c5a6ed
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-8/tokens.snap
@@ -0,0 +1,171 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/table-8
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "{"
+- 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: 10
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 10
+    line: 2
+    character: 2
+  end_position:
+    bytes: 11
+    line: 2
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 11
+    line: 2
+    character: 3
+  end_position:
+    bytes: 12
+    line: 2
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 12
+    line: 2
+    character: 4
+  end_position:
+    bytes: 13
+    line: 2
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 13
+    line: 2
+    character: 5
+  end_position:
+    bytes: 14
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: "="
+- 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: Number
+    text: "1"
+- start_position:
+    bytes: 16
+    line: 2
+    character: 8
+  end_position:
+    bytes: 17
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 17
+    line: 2
+    character: 9
+  end_position:
+    bytes: 18
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 18
+    line: 3
+    character: 1
+  end_position:
+    bytes: 19
+    line: 3
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 19
+    line: 3
+    character: 2
+  end_position:
+    bytes: 19
+    line: 3
+    character: 2
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9aa867fc8463bf8768e3dcd3e1622f5bcdb25ba8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f4d3d21b6b2b2889e5cc66c4c07fb2a90cc51d68
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/table-9
+---
+"local x = {\n}"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..72573f05b44ec8aed63804162a81e8ee7a36ba5d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ccf239f322fdd863c8fd3b7068225c10268ef9e6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..6542bbab62394aced99ed3abb2c57037e6336c60
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/source.lua
@@ -0,0 +1,3 @@
+local x = {
+	[a.b.c = 10,
+}
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/table-9/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7306243126c607f398898388a96e7dcc47ba9352
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5d28823ba8aa156295ceb22ab1a2287d8b4b1d4c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b01c7ca56ab392f3d49b9c8a475fd2122b6e2f9c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/un-op-1
+---
+"return "
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f2790f9856fac0fc44b73fc3a46ab25c9946afe0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..859b418dd43169cacca7e30d7cfa65b42398096a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..92bfc95a4957b0839528f49827ac804f9cff9253
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/source.lua
@@ -0,0 +1 @@
+return not
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..83a4ac560708daec8e0b374d2884e67f22e1b235
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-1/tokens.snap
@@ -0,0 +1,50 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/un-op-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: not
+- start_position:
+    bytes: 10
+    line: 1
+    character: 11
+  end_position:
+    bytes: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d2570e5fdf184056ce243204b7377f76b9915d13
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..eecaca40929b001fbefd11e3b17d7c3eb49eab8b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/un-op-2
+---
+"return "
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..dd20efda5a19a13c3eec5e076f058a7da1a1e723
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c08fea06f96c03e5701f35cf779f6b81fc4e4617
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..064ff24c1f91859e0ea8d3ebbbb0885fc6251802
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/source.lua
@@ -0,0 +1 @@
+return not end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..db794b31dce283e2ed468a01f18a62d7e85ee217
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/un-op-2/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/un-op-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: not
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 14
+    line: 1
+    character: 15
+  end_position:
+    bytes: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6a48f01de7ef713ec89e1a0458041c4c201eaf34
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/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/while-1
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..18ec32b5045e7a111a0315b8e43a793c9352f44b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/while-1
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..48e07b49681a0521c6979838b9456d8fefe6965b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d8515702d5bc40efc9b37f800dca0ee73b3e30a6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2da15dcd359064e1dfd7d2e70b7a24a56908d0b5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/source.lua
@@ -0,0 +1 @@
+while
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..31d74a441f1d538d85658e0bbe9c8ab78a3aa5e7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-1/tokens.snap
@@ -0,0 +1,28 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/while-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: while
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..adaf1c40548e16c64c72a624c1366f24d53aa971
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2c8c9bda1a31060f62be77756cae0f30c167e968
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/while-2
+---
+do end
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e9620dbd5cc1eb3a8d81ba6d7a4d1accd482243e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b7c0b69f9a054bc137ea07ae0d4a2237a09c6e6f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..14f3bb405379754967d8c617543fd8d1634cb8f7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/source.lua
@@ -0,0 +1 @@
+while until do end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..fb92dc20713bf7f950751ef420b696b291004751
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-2/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/while-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: while
+- 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: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: until
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: do
+- 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: Symbol
+    symbol: end
+- start_position:
+    bytes: 18
+    line: 1
+    character: 19
+  end_position:
+    bytes: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b7c92c2e4fa48386b4df62a70053fb7a2e5e09e0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3eadd26171060d96433f0f1ae5de3a241ccc827e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/while-3
+---
+"while true do\n\tcall()end"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ded292d9df001d4f50f2509347e226e32503bcf6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..772a07f7596dbca6f1b3ceba5678af911fbcdc55
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..7c04dad3743f7c4d828e36488f66661944e5e9b3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/source.lua
@@ -0,0 +1,2 @@
+while true do
+	call()
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c8818f4ac8e824b5cde786530eec6a49b0c6a460
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-3/tokens.snap
@@ -0,0 +1,127 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/while-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: while
+- 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: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: "true"
+- 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: 13
+    line: 1
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: do
+- 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: 15
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 15
+    line: 2
+    character: 2
+  end_position:
+    bytes: 19
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 19
+    line: 2
+    character: 6
+  end_position:
+    bytes: 20
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 20
+    line: 2
+    character: 7
+  end_position:
+    bytes: 21
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 21
+    line: 2
+    character: 8
+  end_position:
+    bytes: 21
+    line: 2
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1333b843adbdd5304433fec05822e7679757d34b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0879fc7bbbd405f81a173e1c5b5f54c5432ef364
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/parser/while-4
+---
+"while true\n do\nend\n\tcall()\n"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..db15cbd6320fb103e31cafd44f1737956f024ca0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..65f224700d7604b03316199d1e900cefa0dea3c8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0d39995bffe3031f836c494515fb6f6df5c03ae4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/source.lua
@@ -0,0 +1,3 @@
+while true
+	call()
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..26f8e428452a6a66f8f8d8fc8076b46dd35b10c0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/parser/while-4/tokens.snap
@@ -0,0 +1,127 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/fail/parser/while-4
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: while
+- 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: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 10
+    line: 1
+    character: 11
+  end_position:
+    bytes: 11
+    line: 1
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 11
+    line: 2
+    character: 1
+  end_position:
+    bytes: 12
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 12
+    line: 2
+    character: 2
+  end_position:
+    bytes: 16
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 16
+    line: 2
+    character: 6
+  end_position:
+    bytes: 17
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 17
+    line: 2
+    character: 7
+  end_position:
+    bytes: 18
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 18
+    line: 2
+    character: 8
+  end_position:
+    bytes: 19
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 19
+    line: 3
+    character: 1
+  end_position:
+    bytes: 22
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 22
+    line: 3
+    character: 4
+  end_position:
+    bytes: 22
+    line: 3
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b453902a7b5c6f347c270750f3faf79a92b20670
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..62feedb15b23df2ea5eacaf2898b656b5b21b46c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/tokenizer/bad-numbers-1
+---
+_ = 1edoge
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b61cd5824476b8209daf3023309aad85cd773ef5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0f3c48c8b71fd5afa424086e3966cfd7a12b01d0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..56135fcbea6a4dcb0f3e2e24864514e6a3dd802c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/source.lua
@@ -0,0 +1 @@
+_ = 1edoge
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/tokens_result.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/bad-numbers-1/tokens_result.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b0e88e720db509628eed1fbe36e5d0b6d17e1dc0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2acc2d98b279758bb87d0adaf33df908dce56085
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2f2e2bc7578cc38a6fc573aa80a77e5d50e9f13b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/ast_to_string.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 22
+expression: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/tokenizer/unclosed-comment-1
+---
+"--[[]]"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..55c576c7bfd25719079787618225b7f22c42112c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d9190a80820fcb6d76afa1e55867bfad10535d3b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..3238c3ae1e7a11b0866225dabc011b8b59f21121
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/source.lua
@@ -0,0 +1 @@
+--[[
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/tokens_result.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-comment-1/tokens_result.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7fa651a6441093bf1dbd245d080bbf708d569e65
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..000f99807e5fb8071a15053660c70df8e7c2aa3e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3c4c30da964cd81cac9e99a73758a34da4813953
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/ast_to_string.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 22
+expression: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-1
+---
+"local x = \"hello\""
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a9aee9e141b20154792487d550bf023a27af62d8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3b7b839d637f9acdb268d5dd03ecae96e2a15421
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..9dca219fc7f74c602fbd3a7814464cc99930f686
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/source.lua
@@ -0,0 +1 @@
+local x = "hello
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/tokens_result.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-1/tokens_result.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ca212c3902db082f60288e4070197976ebd56855
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..364ec714bd880fd769d15a3d7823475d98ffd62e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..42c8f44fe88eb61878b0a8a3b60343143062b548
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/ast_to_string.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 22
+expression: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-2
+---
+"local x = 'hello'"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b082d0e2540d3e13f12d8aced41b2b7f2fb6d023
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3a8b885fd0f1079061f7079154ff02a14b31e0bf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..c6f7c89c615c9e2f6bce60ee7b22d154d069e6b3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/source.lua
@@ -0,0 +1 @@
+local x = 'hello
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/tokens_result.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-2/tokens_result.snap
new file mode 100644
index 0000000000000000000000000000000000000000..32fb822d29728e50288efe2dcc0d2091977f223e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3a413e5961f8c9a9af1e0e9939f33b6d4c0351dd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d0bd99b2a9caa5730480547908ec44ef6204e0d5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/ast_to_string.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 22
+expression: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-3
+---
+"local x = [[hello\nworld]]"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6621bcaf61d7b91235cd9bfc270ebd00429f87aa
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8abe8a49ccf0fbf3fe806d4b053a4080a6e79b45
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..87cc2e0c63f89b830b4509b4691d930bbecd99d4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/source.lua
@@ -0,0 +1,2 @@
+local x = [[hello
+world
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/tokens_result.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-3/tokens_result.snap
new file mode 100644
index 0000000000000000000000000000000000000000..515ed292a8e2cbc7e96ef0e1b7258a43bc7cdd51
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ee77f72cd2290d7373eab748b6ca52fa507e1cb2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ea8fc21312d22e6265db5038e0e7093a41d35ec0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/tokenizer/unclosed-string-4
+---
+"local x = 1\n"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8f4a56d88981f5e76af309ff0b922ec3f1ba668e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3e25c8d00b80a577cab7d578633bf194b236cb0d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..743fa914328a16a24abbfa962638e80ed5caddf1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/source.lua
@@ -0,0 +1,2 @@
+"recover
+local x = 1
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/tokens_result.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unclosed-string-4/tokens_result.snap
new file mode 100644
index 0000000000000000000000000000000000000000..be8a9872d72915e1daa2ec57d9a4e5bc8c73481a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1c975d698b604d958c5aff606423e5ced9f6492f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8278fb831f916bdb512fdc1d4956239edbab2be4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/ast_to_string.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 22
+expression: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/tokenizer/unexpected-character
+---
+"local x = "
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..651118bb0a8ef47649a5d076cef45956b7ebf617
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3c99633f67482b95e7e1e7efd75c118c6fac9697
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..e02637d243c99245a66d50f0fd5cf64abba3e289
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/source.lua
@@ -0,0 +1 @@
+local x = 🤔
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/tokens_result.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/unexpected-character/tokens_result.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b7d68acf01fa6ac8639bc1c784b96e0ed1e1cbe1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/ast.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8e9236e85630d738e2033c9ddf7aad74390c47a1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..618ae30a9057df482362fd293a87cb9851a7da6e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/ast_to_string.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 22
+expression: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/cases/fail/tokenizer/wrong-place-shebang
+---
+"\nprint(\"hello\");\n"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/error_display.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bf153f55db073c8dfc6381d9f676468eac9e94a8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/errors.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e4ebedfe1b9cd924a86aab088a7bfea88338c128
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/source.lua b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..5bd6f605818907ca6924e03c233eecfb45b39984
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/source.lua
@@ -0,0 +1,4 @@
+
+#!/usr/bin/env luajit
+
+print("hello");
diff --git a/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/tokens_result.snap b/src/Rust/vvs_parser/src/tests/cases/fail/tokenizer/wrong-place-shebang/tokens_result.snap
new file mode 100644
index 0000000000000000000000000000000000000000..57db51e304fbe4030649030ae8160b2d62d66f83
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..09ba8f1983ebc60a5447f1c8dc57d40dee1c490c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-1/ast.snap
@@ -0,0 +1,271 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/anonymous-functions-1
+---
+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:
+                Function:
+                  - leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 10
+                        line: 1
+                        character: 11
+                      end_position:
+                        bytes: 18
+                        line: 1
+                        character: 19
+                      token_type:
+                        type: Symbol
+                        symbol: function
+                    trailing_trivia: []
+                  - 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: 19
+                              line: 1
+                              character: 20
+                            end_position:
+                              bytes: 20
+                              line: 1
+                              character: 21
+                            token_type:
+                              type: Symbol
+                              symbol: )
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 20
+                                line: 1
+                                character: 21
+                              end_position:
+                                bytes: 21
+                                line: 1
+                                character: 21
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+                    parameters:
+                      pairs: []
+                    block:
+                      stmts:
+                        - - FunctionCall:
+                              prefix:
+                                Name:
+                                  leading_trivia:
+                                    - start_position:
+                                        bytes: 21
+                                        line: 2
+                                        character: 1
+                                      end_position:
+                                        bytes: 22
+                                        line: 2
+                                        character: 2
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\t"
+                                  token:
+                                    start_position:
+                                      bytes: 22
+                                      line: 2
+                                      character: 2
+                                    end_position:
+                                      bytes: 26
+                                      line: 2
+                                      character: 6
+                                    token_type:
+                                      type: Identifier
+                                      identifier: call
+                                  trailing_trivia: []
+                              suffixes:
+                                - Call:
+                                    AnonymousCall:
+                                      Parentheses:
+                                        parentheses:
+                                          tokens:
+                                            - leading_trivia: []
+                                              token:
+                                                start_position:
+                                                  bytes: 26
+                                                  line: 2
+                                                  character: 6
+                                                end_position:
+                                                  bytes: 27
+                                                  line: 2
+                                                  character: 7
+                                                token_type:
+                                                  type: Symbol
+                                                  symbol: (
+                                              trailing_trivia: []
+                                            - leading_trivia: []
+                                              token:
+                                                start_position:
+                                                  bytes: 28
+                                                  line: 2
+                                                  character: 8
+                                                end_position:
+                                                  bytes: 29
+                                                  line: 2
+                                                  character: 9
+                                                token_type:
+                                                  type: Symbol
+                                                  symbol: )
+                                              trailing_trivia:
+                                                - start_position:
+                                                    bytes: 29
+                                                    line: 2
+                                                    character: 9
+                                                  end_position:
+                                                    bytes: 30
+                                                    line: 2
+                                                    character: 9
+                                                  token_type:
+                                                    type: Whitespace
+                                                    characters: "\n"
+                                        arguments:
+                                          pairs:
+                                            - End:
+                                                Number:
+                                                  leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 27
+                                                      line: 2
+                                                      character: 7
+                                                    end_position:
+                                                      bytes: 28
+                                                      line: 2
+                                                      character: 8
+                                                    token_type:
+                                                      type: Number
+                                                      text: "1"
+                                                  trailing_trivia: []
+                          - ~
+                    end_token:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 30
+                          line: 3
+                          character: 1
+                        end_position:
+                          bytes: 33
+                          line: 3
+                          character: 4
+                        token_type:
+                          type: Symbol
+                          symbol: end
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 33
+                            line: 3
+                            character: 4
+                          end_position:
+                            bytes: 34
+                            line: 3
+                            character: 4
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..ddc145a2d9ff9392cbbedef014d05ac9f9398da3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-1/source.lua
@@ -0,0 +1,3 @@
+local x = function()
+	call(1)
+end
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..00d3ace0f6af6112cc2beec5cf0b3ff7bc0e7447
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-1/tokens.snap
@@ -0,0 +1,215 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/anonymous-functions-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: 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: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: function
+- 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: Symbol
+    symbol: )
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 21
+    line: 1
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 21
+    line: 2
+    character: 1
+  end_position:
+    bytes: 22
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 22
+    line: 2
+    character: 2
+  end_position:
+    bytes: 26
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 26
+    line: 2
+    character: 6
+  end_position:
+    bytes: 27
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 27
+    line: 2
+    character: 7
+  end_position:
+    bytes: 28
+    line: 2
+    character: 8
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 28
+    line: 2
+    character: 8
+  end_position:
+    bytes: 29
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 29
+    line: 2
+    character: 9
+  end_position:
+    bytes: 30
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 30
+    line: 3
+    character: 1
+  end_position:
+    bytes: 33
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 33
+    line: 3
+    character: 4
+  end_position:
+    bytes: 34
+    line: 3
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 34
+    line: 4
+    character: 1
+  end_position:
+    bytes: 34
+    line: 4
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7d5f15821c1fae771e693062e7327a2150867243
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-2/ast.snap
@@ -0,0 +1,232 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 48
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/anonymous-functions-2
+---
+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: 31
+                            line: 3
+                            character: 4
+                          end_position:
+                            bytes: 32
+                            line: 3
+                            character: 5
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia: []
+                  arguments:
+                    pairs:
+                      - End:
+                          Function:
+                            - leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 5
+                                  line: 1
+                                  character: 6
+                                end_position:
+                                  bytes: 13
+                                  line: 1
+                                  character: 14
+                                token_type:
+                                  type: Symbol
+                                  symbol: function
+                              trailing_trivia: []
+                            - generics: ~
+                              parameters_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: 16
+                                        token_type:
+                                          type: Whitespace
+                                          characters: "\n"
+                              parameters:
+                                pairs: []
+                              type_specifiers: []
+                              block:
+                                stmts:
+                                  - - FunctionCall:
+                                        prefix:
+                                          Name:
+                                            leading_trivia:
+                                              - start_position:
+                                                  bytes: 16
+                                                  line: 2
+                                                  character: 1
+                                                end_position:
+                                                  bytes: 17
+                                                  line: 2
+                                                  character: 2
+                                                token_type:
+                                                  type: Whitespace
+                                                  characters: "\t"
+                                            token:
+                                              start_position:
+                                                bytes: 17
+                                                line: 2
+                                                character: 2
+                                              end_position:
+                                                bytes: 20
+                                                line: 2
+                                                character: 5
+                                              token_type:
+                                                type: Identifier
+                                                identifier: foo
+                                            trailing_trivia: []
+                                        suffixes:
+                                          - Call:
+                                              AnonymousCall:
+                                                Parentheses:
+                                                  parentheses:
+                                                    tokens:
+                                                      - leading_trivia: []
+                                                        token:
+                                                          start_position:
+                                                            bytes: 20
+                                                            line: 2
+                                                            character: 5
+                                                          end_position:
+                                                            bytes: 21
+                                                            line: 2
+                                                            character: 6
+                                                          token_type:
+                                                            type: Symbol
+                                                            symbol: (
+                                                        trailing_trivia: []
+                                                      - leading_trivia: []
+                                                        token:
+                                                          start_position:
+                                                            bytes: 26
+                                                            line: 2
+                                                            character: 11
+                                                          end_position:
+                                                            bytes: 27
+                                                            line: 2
+                                                            character: 12
+                                                          token_type:
+                                                            type: Symbol
+                                                            symbol: )
+                                                        trailing_trivia:
+                                                          - start_position:
+                                                              bytes: 27
+                                                              line: 2
+                                                              character: 12
+                                                            end_position:
+                                                              bytes: 28
+                                                              line: 2
+                                                              character: 12
+                                                            token_type:
+                                                              type: Whitespace
+                                                              characters: "\n"
+                                                  arguments:
+                                                    pairs:
+                                                      - End:
+                                                          String:
+                                                            leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 21
+                                                                line: 2
+                                                                character: 6
+                                                              end_position:
+                                                                bytes: 26
+                                                                line: 2
+                                                                character: 11
+                                                              token_type:
+                                                                type: StringLiteral
+                                                                literal: bar
+                                                                quote_type: Double
+                                                            trailing_trivia: []
+                                    - ~
+                              end_token:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 28
+                                    line: 3
+                                    character: 1
+                                  end_position:
+                                    bytes: 31
+                                    line: 3
+                                    character: 4
+                                  token_type:
+                                    type: Symbol
+                                    symbol: end
+                                trailing_trivia: []
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..20df3976a5e4cad8117fa73a14f11d4ba346de2b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-2/source.lua
@@ -0,0 +1,3 @@
+call(function()
+	foo("bar")
+end)
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..731b65834956013391421f22856f2d9d9f315829
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-2/tokens.snap
@@ -0,0 +1,172 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/anonymous-functions-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 13
+    line: 1
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: function
+- 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: 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: 17
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 17
+    line: 2
+    character: 2
+  end_position:
+    bytes: 20
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 20
+    line: 2
+    character: 5
+  end_position:
+    bytes: 21
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 21
+    line: 2
+    character: 6
+  end_position:
+    bytes: 26
+    line: 2
+    character: 11
+  token_type:
+    type: StringLiteral
+    literal: bar
+    quote_type: Double
+- start_position:
+    bytes: 26
+    line: 2
+    character: 11
+  end_position:
+    bytes: 27
+    line: 2
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 27
+    line: 2
+    character: 12
+  end_position:
+    bytes: 28
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 28
+    line: 3
+    character: 1
+  end_position:
+    bytes: 31
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 31
+    line: 3
+    character: 4
+  end_position:
+    bytes: 32
+    line: 3
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 32
+    line: 3
+    character: 5
+  end_position:
+    bytes: 32
+    line: 3
+    character: 5
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0db3a00b242a71a0e0eb49f9c8bff29a707468ce
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-3/ast.snap
@@ -0,0 +1,184 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/anonymous-functions-3
+---
+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:
+                Function:
+                  - leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 10
+                        line: 1
+                        character: 11
+                      end_position:
+                        bytes: 18
+                        line: 1
+                        character: 19
+                      token_type:
+                        type: Symbol
+                        symbol: function
+                    trailing_trivia: []
+                  - 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: 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: " "
+                    parameters:
+                      pairs:
+                        - End:
+                            Ellipse:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 19
+                                  line: 1
+                                  character: 20
+                                end_position:
+                                  bytes: 22
+                                  line: 1
+                                  character: 23
+                                token_type:
+                                  type: Symbol
+                                  symbol: "..."
+                              trailing_trivia: []
+                    block:
+                      stmts: []
+                    end_token:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 24
+                          line: 1
+                          character: 25
+                        end_position:
+                          bytes: 27
+                          line: 1
+                          character: 28
+                        token_type:
+                          type: Symbol
+                          symbol: end
+                      trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..567ee735fe4c15263f5d3bdfc82ed6fa38bc61b4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-3/source.lua
@@ -0,0 +1 @@
+local x = function(...) end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8b9972f2777e326096588e9794c2f38e62254cb9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-3/tokens.snap
@@ -0,0 +1,149 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/anonymous-functions-3
+
+---
+- 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: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: function
+- 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: 22
+    line: 1
+    character: 23
+  token_type:
+    type: Symbol
+    symbol: "..."
+- 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: 27
+    line: 1
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 27
+    line: 1
+    character: 28
+  end_position:
+    bytes: 27
+    line: 1
+    character: 28
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0163437fe5385cdc159b2bae2d78ba6f925d56b2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-4/ast.snap
@@ -0,0 +1,266 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/anonymous-functions-4
+---
+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:
+                Function:
+                  - leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 10
+                        line: 1
+                        character: 11
+                      end_position:
+                        bytes: 18
+                        line: 1
+                        character: 19
+                      token_type:
+                        type: Symbol
+                        symbol: function
+                    trailing_trivia: []
+                  - 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: 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: " "
+                    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: a
+                                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: " "
+                        - Punctuated:
+                            - 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: b
+                                trailing_trivia: []
+                            - 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: " "
+                        - End:
+                            Ellipse:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 25
+                                  line: 1
+                                  character: 26
+                                end_position:
+                                  bytes: 28
+                                  line: 1
+                                  character: 29
+                                token_type:
+                                  type: Symbol
+                                  symbol: "..."
+                              trailing_trivia: []
+                    block:
+                      stmts: []
+                    end_token:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 30
+                          line: 1
+                          character: 31
+                        end_position:
+                          bytes: 33
+                          line: 1
+                          character: 34
+                        token_type:
+                          type: Symbol
+                          symbol: end
+                      trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..566d1999ed3d2f0444b3f810cf6a908c45f738f4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-4/source.lua
@@ -0,0 +1 @@
+local x = function(a, b, ...) end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b23833aec85e903c307c3577416b4b89d5b96d6d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/anonymous-functions-4/tokens.snap
@@ -0,0 +1,215 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/anonymous-functions-4
+
+---
+- 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: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: function
+- 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: a
+- 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: b
+- 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: 28
+    line: 1
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: "..."
+- start_position:
+    bytes: 28
+    line: 1
+    character: 29
+  end_position:
+    bytes: 29
+    line: 1
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 29
+    line: 1
+    character: 30
+  end_position:
+    bytes: 30
+    line: 1
+    character: 31
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 30
+    line: 1
+    character: 31
+  end_position:
+    bytes: 33
+    line: 1
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 33
+    line: 1
+    character: 34
+  end_position:
+    bytes: 33
+    line: 1
+    character: 34
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e2c733e50567420c980384be16f5c72c6028cde7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-1/ast.snap
@@ -0,0 +1,83 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/assignment-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: 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:
+            - 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: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..3d2b4b14efe535966493ee555dd7faa81063a251
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-1/source.lua
@@ -0,0 +1 @@
+x = 1
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..24cb47eb8474ebe7b97e8e90189e3e51395a4acc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-1/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/assignment-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3ee1a2ffeee20d113c5ff84025d066f98c76f025
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-2/ast.snap
@@ -0,0 +1,165 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/assignment-2
+---
+stmts:
+  - - Assignment:
+        var_list:
+          pairs:
+            - Punctuated:
+                - 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: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 1
+                      line: 1
+                      character: 2
+                    end_position:
+                      bytes: 2
+                      line: 1
+                      character: 3
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 2
+                        line: 1
+                        character: 3
+                      end_position:
+                        bytes: 3
+                        line: 1
+                        character: 4
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                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: b
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 4
+                        line: 1
+                        character: 5
+                      end_position:
+                        bytes: 5
+                        line: 1
+                        character: 6
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 5
+              line: 1
+              character: 6
+            end_position:
+              bytes: 6
+              line: 1
+              character: 7
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 6
+                line: 1
+                character: 7
+              end_position:
+                bytes: 7
+                line: 1
+                character: 8
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - Punctuated:
+                - 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: []
+                - 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: " "
+            - End:
+                Symbol:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 10
+                      line: 1
+                      character: 11
+                    end_position:
+                      bytes: 14
+                      line: 1
+                      character: 15
+                    token_type:
+                      type: Symbol
+                      symbol: "true"
+                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8b162b6742b1034d6716dd5c0c4702c054ef421b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-2/source.lua
@@ -0,0 +1 @@
+a, b = 1, true
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..83fb8d0e94d236ed8135c916e960ca6b9e7eb12d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-2/tokens.snap
@@ -0,0 +1,138 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/assignment-2
+
+---
+- 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: Symbol
+    symbol: ","
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: b
+- 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: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Number
+    text: "1"
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 14
+    line: 1
+    character: 15
+  end_position:
+    bytes: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cb4e5f48bc045d177cf5c98be471a2be8aa2cdd7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-3/ast.snap
@@ -0,0 +1,829 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/assignment-3
+---
+stmts:
+  - - Assignment:
+        var_list:
+          pairs:
+            - Punctuated:
+                - Name:
+                    leading_trivia:
+                      - start_position:
+                          bytes: 0
+                          line: 1
+                          character: 1
+                        end_position:
+                          bytes: 48
+                          line: 1
+                          character: 49
+                        token_type:
+                          type: SingleLineComment
+                          comment: " Crazy assignment code from AmaranthineCodices"
+                      - start_position:
+                          bytes: 48
+                          line: 1
+                          character: 49
+                        end_position:
+                          bytes: 49
+                          line: 1
+                          character: 49
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+                    token:
+                      start_position:
+                        bytes: 49
+                        line: 2
+                        character: 1
+                      end_position:
+                        bytes: 50
+                        line: 2
+                        character: 2
+                      token_type:
+                        type: Identifier
+                        identifier: a
+                    trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 50
+                      line: 2
+                      character: 2
+                    end_position:
+                      bytes: 51
+                      line: 2
+                      character: 3
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 51
+                        line: 2
+                        character: 3
+                      end_position:
+                        bytes: 52
+                        line: 2
+                        character: 4
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - Punctuated:
+                - Name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 52
+                        line: 2
+                        character: 4
+                      end_position:
+                        bytes: 53
+                        line: 2
+                        character: 5
+                      token_type:
+                        type: Identifier
+                        identifier: b
+                    trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 53
+                      line: 2
+                      character: 5
+                    end_position:
+                      bytes: 54
+                      line: 2
+                      character: 6
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 54
+                        line: 2
+                        character: 6
+                      end_position:
+                        bytes: 55
+                        line: 2
+                        character: 7
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - Punctuated:
+                - Expression:
+                    prefix:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 55
+                            line: 2
+                            character: 7
+                          end_position:
+                            bytes: 56
+                            line: 2
+                            character: 8
+                          token_type:
+                            type: Identifier
+                            identifier: c
+                        trailing_trivia: []
+                    suffixes:
+                      - Index:
+                          Dot:
+                            dot:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 56
+                                  line: 2
+                                  character: 8
+                                end_position:
+                                  bytes: 57
+                                  line: 2
+                                  character: 9
+                                token_type:
+                                  type: Symbol
+                                  symbol: "."
+                              trailing_trivia: []
+                            name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 57
+                                  line: 2
+                                  character: 9
+                                end_position:
+                                  bytes: 58
+                                  line: 2
+                                  character: 10
+                                token_type:
+                                  type: Identifier
+                                  identifier: d
+                              trailing_trivia: []
+                      - Index:
+                          Dot:
+                            dot:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 58
+                                  line: 2
+                                  character: 10
+                                end_position:
+                                  bytes: 59
+                                  line: 2
+                                  character: 11
+                                token_type:
+                                  type: Symbol
+                                  symbol: "."
+                              trailing_trivia: []
+                            name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 59
+                                  line: 2
+                                  character: 11
+                                end_position:
+                                  bytes: 60
+                                  line: 2
+                                  character: 12
+                                token_type:
+                                  type: Identifier
+                                  identifier: e
+                              trailing_trivia: []
+                      - Index:
+                          Brackets:
+                            brackets:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 60
+                                      line: 2
+                                      character: 12
+                                    end_position:
+                                      bytes: 61
+                                      line: 2
+                                      character: 13
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "["
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 62
+                                      line: 2
+                                      character: 14
+                                    end_position:
+                                      bytes: 63
+                                      line: 2
+                                      character: 15
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "]"
+                                  trailing_trivia: []
+                            expression:
+                              Var:
+                                Name:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 61
+                                      line: 2
+                                      character: 13
+                                    end_position:
+                                      bytes: 62
+                                      line: 2
+                                      character: 14
+                                    token_type:
+                                      type: Identifier
+                                      identifier: f
+                                  trailing_trivia: []
+                      - Index:
+                          Brackets:
+                            brackets:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 63
+                                      line: 2
+                                      character: 15
+                                    end_position:
+                                      bytes: 64
+                                      line: 2
+                                      character: 16
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "["
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 65
+                                      line: 2
+                                      character: 17
+                                    end_position:
+                                      bytes: 66
+                                      line: 2
+                                      character: 18
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "]"
+                                  trailing_trivia: []
+                            expression:
+                              Var:
+                                Name:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 64
+                                      line: 2
+                                      character: 16
+                                    end_position:
+                                      bytes: 65
+                                      line: 2
+                                      character: 17
+                                    token_type:
+                                      type: Identifier
+                                      identifier: g
+                                  trailing_trivia: []
+                      - Index:
+                          Brackets:
+                            brackets:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 66
+                                      line: 2
+                                      character: 18
+                                    end_position:
+                                      bytes: 67
+                                      line: 2
+                                      character: 19
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "["
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 68
+                                      line: 2
+                                      character: 20
+                                    end_position:
+                                      bytes: 69
+                                      line: 2
+                                      character: 21
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "]"
+                                  trailing_trivia: []
+                            expression:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 67
+                                    line: 2
+                                    character: 19
+                                  end_position:
+                                    bytes: 68
+                                    line: 2
+                                    character: 20
+                                  token_type:
+                                    type: Number
+                                    text: "1"
+                                trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 69
+                      line: 2
+                      character: 21
+                    end_position:
+                      bytes: 70
+                      line: 2
+                      character: 22
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 70
+                        line: 2
+                        character: 22
+                      end_position:
+                        bytes: 71
+                        line: 2
+                        character: 23
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                Expression:
+                  prefix:
+                    Name:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 71
+                          line: 2
+                          character: 23
+                        end_position:
+                          bytes: 72
+                          line: 2
+                          character: 24
+                        token_type:
+                          type: Identifier
+                          identifier: h
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        MethodCall:
+                          colon_token:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 72
+                                line: 2
+                                character: 24
+                              end_position:
+                                bytes: 73
+                                line: 2
+                                character: 25
+                              token_type:
+                                type: Symbol
+                                symbol: ":"
+                            trailing_trivia: []
+                          name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 73
+                                line: 2
+                                character: 25
+                              end_position:
+                                bytes: 74
+                                line: 2
+                                character: 26
+                              token_type:
+                                type: Identifier
+                                identifier: i
+                            trailing_trivia: []
+                          args:
+                            Parentheses:
+                              parentheses:
+                                tokens:
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 74
+                                        line: 2
+                                        character: 26
+                                      end_position:
+                                        bytes: 75
+                                        line: 2
+                                        character: 27
+                                      token_type:
+                                        type: Symbol
+                                        symbol: (
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 75
+                                        line: 2
+                                        character: 27
+                                      end_position:
+                                        bytes: 76
+                                        line: 2
+                                        character: 28
+                                      token_type:
+                                        type: Symbol
+                                        symbol: )
+                                    trailing_trivia: []
+                              arguments:
+                                pairs: []
+                    - Index:
+                        Dot:
+                          dot:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 76
+                                line: 2
+                                character: 28
+                              end_position:
+                                bytes: 77
+                                line: 2
+                                character: 29
+                              token_type:
+                                type: Symbol
+                                symbol: "."
+                            trailing_trivia: []
+                          name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 77
+                                line: 2
+                                character: 29
+                              end_position:
+                                bytes: 78
+                                line: 2
+                                character: 30
+                              token_type:
+                                type: Identifier
+                                identifier: j
+                            trailing_trivia: []
+                    - Index:
+                        Brackets:
+                          brackets:
+                            tokens:
+                              - leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 78
+                                    line: 2
+                                    character: 30
+                                  end_position:
+                                    bytes: 79
+                                    line: 2
+                                    character: 31
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "["
+                                trailing_trivia: []
+                              - leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 80
+                                    line: 2
+                                    character: 32
+                                  end_position:
+                                    bytes: 81
+                                    line: 2
+                                    character: 33
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "]"
+                                trailing_trivia: []
+                          expression:
+                            Var:
+                              Name:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 79
+                                    line: 2
+                                    character: 31
+                                  end_position:
+                                    bytes: 80
+                                    line: 2
+                                    character: 32
+                                  token_type:
+                                    type: Identifier
+                                    identifier: k
+                                trailing_trivia: []
+                    - Call:
+                        MethodCall:
+                          colon_token:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 81
+                                line: 2
+                                character: 33
+                              end_position:
+                                bytes: 82
+                                line: 2
+                                character: 34
+                              token_type:
+                                type: Symbol
+                                symbol: ":"
+                            trailing_trivia: []
+                          name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 82
+                                line: 2
+                                character: 34
+                              end_position:
+                                bytes: 83
+                                line: 2
+                                character: 35
+                              token_type:
+                                type: Identifier
+                                identifier: l
+                            trailing_trivia: []
+                          args:
+                            Parentheses:
+                              parentheses:
+                                tokens:
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 83
+                                        line: 2
+                                        character: 35
+                                      end_position:
+                                        bytes: 84
+                                        line: 2
+                                        character: 36
+                                      token_type:
+                                        type: Symbol
+                                        symbol: (
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 84
+                                        line: 2
+                                        character: 36
+                                      end_position:
+                                        bytes: 85
+                                        line: 2
+                                        character: 37
+                                      token_type:
+                                        type: Symbol
+                                        symbol: )
+                                    trailing_trivia: []
+                              arguments:
+                                pairs: []
+                    - Index:
+                        Brackets:
+                          brackets:
+                            tokens:
+                              - leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 85
+                                    line: 2
+                                    character: 37
+                                  end_position:
+                                    bytes: 86
+                                    line: 2
+                                    character: 38
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "["
+                                trailing_trivia: []
+                              - leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 87
+                                    line: 2
+                                    character: 39
+                                  end_position:
+                                    bytes: 88
+                                    line: 2
+                                    character: 40
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "]"
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 88
+                                      line: 2
+                                      character: 40
+                                    end_position:
+                                      bytes: 89
+                                      line: 2
+                                      character: 41
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                          expression:
+                            Var:
+                              Name:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 86
+                                    line: 2
+                                    character: 38
+                                  end_position:
+                                    bytes: 87
+                                    line: 2
+                                    character: 39
+                                  token_type:
+                                    type: Identifier
+                                    identifier: m
+                                trailing_trivia: []
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 89
+              line: 2
+              character: 41
+            end_position:
+              bytes: 90
+              line: 2
+              character: 42
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 90
+                line: 2
+                character: 42
+              end_position:
+                bytes: 91
+                line: 2
+                character: 43
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - Punctuated:
+                - Symbol:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 91
+                        line: 2
+                        character: 43
+                      end_position:
+                        bytes: 95
+                        line: 2
+                        character: 47
+                      token_type:
+                        type: Symbol
+                        symbol: "true"
+                    trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 95
+                      line: 2
+                      character: 47
+                    end_position:
+                      bytes: 96
+                      line: 2
+                      character: 48
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 96
+                        line: 2
+                        character: 48
+                      end_position:
+                        bytes: 97
+                        line: 2
+                        character: 49
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - Punctuated:
+                - Symbol:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 97
+                        line: 2
+                        character: 49
+                      end_position:
+                        bytes: 102
+                        line: 2
+                        character: 54
+                      token_type:
+                        type: Symbol
+                        symbol: "false"
+                    trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 102
+                      line: 2
+                      character: 54
+                    end_position:
+                      bytes: 103
+                      line: 2
+                      character: 55
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 103
+                        line: 2
+                        character: 55
+                      end_position:
+                        bytes: 104
+                        line: 2
+                        character: 56
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - Punctuated:
+                - Number:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 104
+                        line: 2
+                        character: 56
+                      end_position:
+                        bytes: 105
+                        line: 2
+                        character: 57
+                      token_type:
+                        type: Number
+                        text: "1"
+                    trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 105
+                      line: 2
+                      character: 57
+                    end_position:
+                      bytes: 106
+                      line: 2
+                      character: 58
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 106
+                        line: 2
+                        character: 58
+                      end_position:
+                        bytes: 107
+                        line: 2
+                        character: 59
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 107
+                      line: 2
+                      character: 59
+                    end_position:
+                      bytes: 108
+                      line: 2
+                      character: 60
+                    token_type:
+                      type: Number
+                      text: "4"
+                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..fab2edb95048bddece94016d2e1ab2846a05395e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-3/source.lua
@@ -0,0 +1,2 @@
+-- Crazy assignment code from AmaranthineCodices
+a, b, c.d.e[f][g][1], h:i().j[k]:l()[m] = true, false, 1, 4
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a3be75e09074b145440e6086617749c5e82269c0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-3/tokens.snap
@@ -0,0 +1,611 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/assignment-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 48
+    line: 1
+    character: 49
+  token_type:
+    type: SingleLineComment
+    comment: " Crazy assignment code from AmaranthineCodices"
+- start_position:
+    bytes: 48
+    line: 1
+    character: 49
+  end_position:
+    bytes: 49
+    line: 1
+    character: 49
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 49
+    line: 2
+    character: 1
+  end_position:
+    bytes: 50
+    line: 2
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: a
+- start_position:
+    bytes: 50
+    line: 2
+    character: 2
+  end_position:
+    bytes: 51
+    line: 2
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 51
+    line: 2
+    character: 3
+  end_position:
+    bytes: 52
+    line: 2
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 52
+    line: 2
+    character: 4
+  end_position:
+    bytes: 53
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 53
+    line: 2
+    character: 5
+  end_position:
+    bytes: 54
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 54
+    line: 2
+    character: 6
+  end_position:
+    bytes: 55
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 55
+    line: 2
+    character: 7
+  end_position:
+    bytes: 56
+    line: 2
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: c
+- start_position:
+    bytes: 56
+    line: 2
+    character: 8
+  end_position:
+    bytes: 57
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 57
+    line: 2
+    character: 9
+  end_position:
+    bytes: 58
+    line: 2
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: d
+- start_position:
+    bytes: 58
+    line: 2
+    character: 10
+  end_position:
+    bytes: 59
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 59
+    line: 2
+    character: 11
+  end_position:
+    bytes: 60
+    line: 2
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: e
+- start_position:
+    bytes: 60
+    line: 2
+    character: 12
+  end_position:
+    bytes: 61
+    line: 2
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 61
+    line: 2
+    character: 13
+  end_position:
+    bytes: 62
+    line: 2
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: f
+- start_position:
+    bytes: 62
+    line: 2
+    character: 14
+  end_position:
+    bytes: 63
+    line: 2
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 63
+    line: 2
+    character: 15
+  end_position:
+    bytes: 64
+    line: 2
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 64
+    line: 2
+    character: 16
+  end_position:
+    bytes: 65
+    line: 2
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: g
+- start_position:
+    bytes: 65
+    line: 2
+    character: 17
+  end_position:
+    bytes: 66
+    line: 2
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 66
+    line: 2
+    character: 18
+  end_position:
+    bytes: 67
+    line: 2
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 67
+    line: 2
+    character: 19
+  end_position:
+    bytes: 68
+    line: 2
+    character: 20
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 68
+    line: 2
+    character: 20
+  end_position:
+    bytes: 69
+    line: 2
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 69
+    line: 2
+    character: 21
+  end_position:
+    bytes: 70
+    line: 2
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 70
+    line: 2
+    character: 22
+  end_position:
+    bytes: 71
+    line: 2
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 71
+    line: 2
+    character: 23
+  end_position:
+    bytes: 72
+    line: 2
+    character: 24
+  token_type:
+    type: Identifier
+    identifier: h
+- start_position:
+    bytes: 72
+    line: 2
+    character: 24
+  end_position:
+    bytes: 73
+    line: 2
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 73
+    line: 2
+    character: 25
+  end_position:
+    bytes: 74
+    line: 2
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: i
+- start_position:
+    bytes: 74
+    line: 2
+    character: 26
+  end_position:
+    bytes: 75
+    line: 2
+    character: 27
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 75
+    line: 2
+    character: 27
+  end_position:
+    bytes: 76
+    line: 2
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 76
+    line: 2
+    character: 28
+  end_position:
+    bytes: 77
+    line: 2
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 77
+    line: 2
+    character: 29
+  end_position:
+    bytes: 78
+    line: 2
+    character: 30
+  token_type:
+    type: Identifier
+    identifier: j
+- start_position:
+    bytes: 78
+    line: 2
+    character: 30
+  end_position:
+    bytes: 79
+    line: 2
+    character: 31
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 79
+    line: 2
+    character: 31
+  end_position:
+    bytes: 80
+    line: 2
+    character: 32
+  token_type:
+    type: Identifier
+    identifier: k
+- start_position:
+    bytes: 80
+    line: 2
+    character: 32
+  end_position:
+    bytes: 81
+    line: 2
+    character: 33
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 81
+    line: 2
+    character: 33
+  end_position:
+    bytes: 82
+    line: 2
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 82
+    line: 2
+    character: 34
+  end_position:
+    bytes: 83
+    line: 2
+    character: 35
+  token_type:
+    type: Identifier
+    identifier: l
+- start_position:
+    bytes: 83
+    line: 2
+    character: 35
+  end_position:
+    bytes: 84
+    line: 2
+    character: 36
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 84
+    line: 2
+    character: 36
+  end_position:
+    bytes: 85
+    line: 2
+    character: 37
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 85
+    line: 2
+    character: 37
+  end_position:
+    bytes: 86
+    line: 2
+    character: 38
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 86
+    line: 2
+    character: 38
+  end_position:
+    bytes: 87
+    line: 2
+    character: 39
+  token_type:
+    type: Identifier
+    identifier: m
+- start_position:
+    bytes: 87
+    line: 2
+    character: 39
+  end_position:
+    bytes: 88
+    line: 2
+    character: 40
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 88
+    line: 2
+    character: 40
+  end_position:
+    bytes: 89
+    line: 2
+    character: 41
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 89
+    line: 2
+    character: 41
+  end_position:
+    bytes: 90
+    line: 2
+    character: 42
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 90
+    line: 2
+    character: 42
+  end_position:
+    bytes: 91
+    line: 2
+    character: 43
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 91
+    line: 2
+    character: 43
+  end_position:
+    bytes: 95
+    line: 2
+    character: 47
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 95
+    line: 2
+    character: 47
+  end_position:
+    bytes: 96
+    line: 2
+    character: 48
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 96
+    line: 2
+    character: 48
+  end_position:
+    bytes: 97
+    line: 2
+    character: 49
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 97
+    line: 2
+    character: 49
+  end_position:
+    bytes: 102
+    line: 2
+    character: 54
+  token_type:
+    type: Symbol
+    symbol: "false"
+- start_position:
+    bytes: 102
+    line: 2
+    character: 54
+  end_position:
+    bytes: 103
+    line: 2
+    character: 55
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 103
+    line: 2
+    character: 55
+  end_position:
+    bytes: 104
+    line: 2
+    character: 56
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 104
+    line: 2
+    character: 56
+  end_position:
+    bytes: 105
+    line: 2
+    character: 57
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 105
+    line: 2
+    character: 57
+  end_position:
+    bytes: 106
+    line: 2
+    character: 58
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 106
+    line: 2
+    character: 58
+  end_position:
+    bytes: 107
+    line: 2
+    character: 59
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 107
+    line: 2
+    character: 59
+  end_position:
+    bytes: 108
+    line: 2
+    character: 60
+  token_type:
+    type: Number
+    text: "4"
+- start_position:
+    bytes: 108
+    line: 2
+    character: 60
+  end_position:
+    bytes: 108
+    line: 2
+    character: 60
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2dae33e58c296f0a0590803bec31226f78742dfc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/pass/assignment-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..223ca50d99502c4cf15a026d366965225e573961
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-4/source.lua
@@ -0,0 +1,2 @@
+a = 1
+b = 2
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..afabdf98095ce5fd180dd3aeeba89805dcf03212
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/pass/assignment-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a97a907a0af26704d583ebb10b1ac7d7532f1dc1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/pass/assignment-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8a751ba08eed9e7e9747ec0dbc760109ae37dc45
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-5/source.lua
@@ -0,0 +1 @@
+gui.Label.Text = "LOADING DATA" .. ("."):rep(dotCount)
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/assignment-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/assignment-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7006f66c9350088dfb3e448f56d919393eaf65aa
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/pass/binops/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/binops/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2a2b13a5b1472135dc4b81a3cab778f946c37be6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/binops/ast.snap
@@ -0,0 +1,1840 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/binops
+---
+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:
+                BinaryOperator:
+                  lhs:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 4
+                            line: 1
+                            character: 5
+                          end_position:
+                            bytes: 7
+                            line: 1
+                            character: 8
+                          token_type:
+                            type: Identifier
+                            identifier: foo
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 7
+                              line: 1
+                              character: 8
+                            end_position:
+                              bytes: 8
+                              line: 1
+                              character: 9
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  binop:
+                    And:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 8
+                          line: 1
+                          character: 9
+                        end_position:
+                          bytes: 11
+                          line: 1
+                          character: 12
+                        token_type:
+                          type: Symbol
+                          symbol: and
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 11
+                            line: 1
+                            character: 12
+                          end_position:
+                            bytes: 12
+                            line: 1
+                            character: 13
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 12
+                            line: 1
+                            character: 13
+                          end_position:
+                            bytes: 15
+                            line: 1
+                            character: 16
+                          token_type:
+                            type: Identifier
+                            identifier: bar
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 15
+                              line: 1
+                              character: 16
+                            end_position:
+                              bytes: 16
+                              line: 1
+                              character: 16
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+    - ~
+  - - Assignment:
+        var_list:
+          pairs:
+            - End:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 16
+                      line: 2
+                      character: 1
+                    end_position:
+                      bytes: 17
+                      line: 2
+                      character: 2
+                    token_type:
+                      type: Identifier
+                      identifier: b
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 17
+                        line: 2
+                        character: 2
+                      end_position:
+                        bytes: 18
+                        line: 2
+                        character: 3
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 18
+              line: 2
+              character: 3
+            end_position:
+              bytes: 19
+              line: 2
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 19
+                line: 2
+                character: 4
+              end_position:
+                bytes: 20
+                line: 2
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    BinaryOperator:
+                      lhs:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 20
+                                line: 2
+                                character: 5
+                              end_position:
+                                bytes: 23
+                                line: 2
+                                character: 8
+                              token_type:
+                                type: Identifier
+                                identifier: foo
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 23
+                                  line: 2
+                                  character: 8
+                                end_position:
+                                  bytes: 24
+                                  line: 2
+                                  character: 9
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      binop:
+                        And:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 24
+                              line: 2
+                              character: 9
+                            end_position:
+                              bytes: 27
+                              line: 2
+                              character: 12
+                            token_type:
+                              type: Symbol
+                              symbol: and
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 27
+                                line: 2
+                                character: 12
+                              end_position:
+                                bytes: 28
+                                line: 2
+                                character: 13
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      rhs:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 28
+                                line: 2
+                                character: 13
+                              end_position:
+                                bytes: 31
+                                line: 2
+                                character: 16
+                              token_type:
+                                type: Identifier
+                                identifier: bar
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 31
+                                  line: 2
+                                  character: 16
+                                end_position:
+                                  bytes: 32
+                                  line: 2
+                                  character: 17
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                  binop:
+                    Or:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 32
+                          line: 2
+                          character: 17
+                        end_position:
+                          bytes: 34
+                          line: 2
+                          character: 19
+                        token_type:
+                          type: Symbol
+                          symbol: or
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 34
+                            line: 2
+                            character: 19
+                          end_position:
+                            bytes: 35
+                            line: 2
+                            character: 20
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 35
+                            line: 2
+                            character: 20
+                          end_position:
+                            bytes: 38
+                            line: 2
+                            character: 23
+                          token_type:
+                            type: Identifier
+                            identifier: baz
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 38
+                              line: 2
+                              character: 23
+                            end_position:
+                              bytes: 39
+                              line: 2
+                              character: 23
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+    - ~
+  - - Assignment:
+        var_list:
+          pairs:
+            - End:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 39
+                      line: 3
+                      character: 1
+                    end_position:
+                      bytes: 40
+                      line: 3
+                      character: 2
+                    token_type:
+                      type: Identifier
+                      identifier: c
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 40
+                        line: 3
+                        character: 2
+                      end_position:
+                        bytes: 41
+                        line: 3
+                        character: 3
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 41
+              line: 3
+              character: 3
+            end_position:
+              bytes: 42
+              line: 3
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 42
+                line: 3
+                character: 4
+              end_position:
+                bytes: 43
+                line: 3
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    BinaryOperator:
+                      lhs:
+                        Number:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 43
+                              line: 3
+                              character: 5
+                            end_position:
+                              bytes: 44
+                              line: 3
+                              character: 6
+                            token_type:
+                              type: Number
+                              text: "1"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 44
+                                line: 3
+                                character: 6
+                              end_position:
+                                bytes: 45
+                                line: 3
+                                character: 7
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      binop:
+                        Plus:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 45
+                              line: 3
+                              character: 7
+                            end_position:
+                              bytes: 46
+                              line: 3
+                              character: 8
+                            token_type:
+                              type: Symbol
+                              symbol: +
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 46
+                                line: 3
+                                character: 8
+                              end_position:
+                                bytes: 47
+                                line: 3
+                                character: 9
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      rhs:
+                        BinaryOperator:
+                          lhs:
+                            Number:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 47
+                                  line: 3
+                                  character: 9
+                                end_position:
+                                  bytes: 48
+                                  line: 3
+                                  character: 10
+                                token_type:
+                                  type: Number
+                                  text: "2"
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 48
+                                    line: 3
+                                    character: 10
+                                  end_position:
+                                    bytes: 49
+                                    line: 3
+                                    character: 11
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                          binop:
+                            Star:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 49
+                                  line: 3
+                                  character: 11
+                                end_position:
+                                  bytes: 50
+                                  line: 3
+                                  character: 12
+                                token_type:
+                                  type: Symbol
+                                  symbol: "*"
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 50
+                                    line: 3
+                                    character: 12
+                                  end_position:
+                                    bytes: 51
+                                    line: 3
+                                    character: 13
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                          rhs:
+                            Number:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 51
+                                  line: 3
+                                  character: 13
+                                end_position:
+                                  bytes: 52
+                                  line: 3
+                                  character: 14
+                                token_type:
+                                  type: Number
+                                  text: "3"
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 52
+                                    line: 3
+                                    character: 14
+                                  end_position:
+                                    bytes: 53
+                                    line: 3
+                                    character: 15
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                  binop:
+                    Minus:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 53
+                          line: 3
+                          character: 15
+                        end_position:
+                          bytes: 54
+                          line: 3
+                          character: 16
+                        token_type:
+                          type: Symbol
+                          symbol: "-"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 54
+                            line: 3
+                            character: 16
+                          end_position:
+                            bytes: 55
+                            line: 3
+                            character: 17
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    BinaryOperator:
+                      lhs:
+                        Number:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 55
+                              line: 3
+                              character: 17
+                            end_position:
+                              bytes: 56
+                              line: 3
+                              character: 18
+                            token_type:
+                              type: Number
+                              text: "4"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 56
+                                line: 3
+                                character: 18
+                              end_position:
+                                bytes: 57
+                                line: 3
+                                character: 19
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      binop:
+                        Caret:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 57
+                              line: 3
+                              character: 19
+                            end_position:
+                              bytes: 58
+                              line: 3
+                              character: 20
+                            token_type:
+                              type: Symbol
+                              symbol: ^
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 58
+                                line: 3
+                                character: 20
+                              end_position:
+                                bytes: 59
+                                line: 3
+                                character: 21
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      rhs:
+                        Number:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 59
+                              line: 3
+                              character: 21
+                            end_position:
+                              bytes: 60
+                              line: 3
+                              character: 22
+                            token_type:
+                              type: Number
+                              text: "2"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 60
+                                line: 3
+                                character: 22
+                              end_position:
+                                bytes: 61
+                                line: 3
+                                character: 22
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+    - ~
+  - - Assignment:
+        var_list:
+          pairs:
+            - End:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 61
+                      line: 4
+                      character: 1
+                    end_position:
+                      bytes: 62
+                      line: 4
+                      character: 2
+                    token_type:
+                      type: Identifier
+                      identifier: d
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 62
+                        line: 4
+                        character: 2
+                      end_position:
+                        bytes: 63
+                        line: 4
+                        character: 3
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 63
+              line: 4
+              character: 3
+            end_position:
+              bytes: 64
+              line: 4
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 64
+                line: 4
+                character: 4
+              end_position:
+                bytes: 65
+                line: 4
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    BinaryOperator:
+                      lhs:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 65
+                                line: 4
+                                character: 5
+                              end_position:
+                                bytes: 66
+                                line: 4
+                                character: 6
+                              token_type:
+                                type: Identifier
+                                identifier: a
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 66
+                                  line: 4
+                                  character: 6
+                                end_position:
+                                  bytes: 67
+                                  line: 4
+                                  character: 7
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      binop:
+                        Plus:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 67
+                              line: 4
+                              character: 7
+                            end_position:
+                              bytes: 68
+                              line: 4
+                              character: 8
+                            token_type:
+                              type: Symbol
+                              symbol: +
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 68
+                                line: 4
+                                character: 8
+                              end_position:
+                                bytes: 69
+                                line: 4
+                                character: 9
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      rhs:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 69
+                                line: 4
+                                character: 9
+                              end_position:
+                                bytes: 70
+                                line: 4
+                                character: 10
+                              token_type:
+                                type: Identifier
+                                identifier: i
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 70
+                                  line: 4
+                                  character: 10
+                                end_position:
+                                  bytes: 71
+                                  line: 4
+                                  character: 11
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                  binop:
+                    LessThan:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 71
+                          line: 4
+                          character: 11
+                        end_position:
+                          bytes: 72
+                          line: 4
+                          character: 12
+                        token_type:
+                          type: Symbol
+                          symbol: "<"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 72
+                            line: 4
+                            character: 12
+                          end_position:
+                            bytes: 73
+                            line: 4
+                            character: 13
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    BinaryOperator:
+                      lhs:
+                        BinaryOperator:
+                          lhs:
+                            Var:
+                              Name:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 73
+                                    line: 4
+                                    character: 13
+                                  end_position:
+                                    bytes: 74
+                                    line: 4
+                                    character: 14
+                                  token_type:
+                                    type: Identifier
+                                    identifier: b
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 74
+                                      line: 4
+                                      character: 14
+                                    end_position:
+                                      bytes: 75
+                                      line: 4
+                                      character: 15
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                          binop:
+                            Slash:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 75
+                                  line: 4
+                                  character: 15
+                                end_position:
+                                  bytes: 76
+                                  line: 4
+                                  character: 16
+                                token_type:
+                                  type: Symbol
+                                  symbol: /
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 76
+                                    line: 4
+                                    character: 16
+                                  end_position:
+                                    bytes: 77
+                                    line: 4
+                                    character: 17
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                          rhs:
+                            Number:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 77
+                                  line: 4
+                                  character: 17
+                                end_position:
+                                  bytes: 78
+                                  line: 4
+                                  character: 18
+                                token_type:
+                                  type: Number
+                                  text: "2"
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 78
+                                    line: 4
+                                    character: 18
+                                  end_position:
+                                    bytes: 79
+                                    line: 4
+                                    character: 19
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                      binop:
+                        Plus:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 79
+                              line: 4
+                              character: 19
+                            end_position:
+                              bytes: 80
+                              line: 4
+                              character: 20
+                            token_type:
+                              type: Symbol
+                              symbol: +
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 80
+                                line: 4
+                                character: 20
+                              end_position:
+                                bytes: 81
+                                line: 4
+                                character: 21
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      rhs:
+                        Number:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 81
+                              line: 4
+                              character: 21
+                            end_position:
+                              bytes: 82
+                              line: 4
+                              character: 22
+                            token_type:
+                              type: Number
+                              text: "1"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 82
+                                line: 4
+                                character: 22
+                              end_position:
+                                bytes: 83
+                                line: 4
+                                character: 22
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+    - ~
+  - - Assignment:
+        var_list:
+          pairs:
+            - End:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 83
+                      line: 5
+                      character: 1
+                    end_position:
+                      bytes: 84
+                      line: 5
+                      character: 2
+                    token_type:
+                      type: Identifier
+                      identifier: e
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 84
+                        line: 5
+                        character: 2
+                      end_position:
+                        bytes: 85
+                        line: 5
+                        character: 3
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 85
+              line: 5
+              character: 3
+            end_position:
+              bytes: 86
+              line: 5
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 86
+                line: 5
+                character: 4
+              end_position:
+                bytes: 87
+                line: 5
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 87
+                          line: 5
+                          character: 5
+                        end_position:
+                          bytes: 88
+                          line: 5
+                          character: 6
+                        token_type:
+                          type: Number
+                          text: "5"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 88
+                            line: 5
+                            character: 6
+                          end_position:
+                            bytes: 89
+                            line: 5
+                            character: 7
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  binop:
+                    Plus:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 89
+                          line: 5
+                          character: 7
+                        end_position:
+                          bytes: 90
+                          line: 5
+                          character: 8
+                        token_type:
+                          type: Symbol
+                          symbol: +
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 90
+                            line: 5
+                            character: 8
+                          end_position:
+                            bytes: 91
+                            line: 5
+                            character: 9
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    BinaryOperator:
+                      lhs:
+                        BinaryOperator:
+                          lhs:
+                            Var:
+                              Name:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 91
+                                    line: 5
+                                    character: 9
+                                  end_position:
+                                    bytes: 92
+                                    line: 5
+                                    character: 10
+                                  token_type:
+                                    type: Identifier
+                                    identifier: x
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 92
+                                      line: 5
+                                      character: 10
+                                    end_position:
+                                      bytes: 93
+                                      line: 5
+                                      character: 11
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                          binop:
+                            Caret:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 93
+                                  line: 5
+                                  character: 11
+                                end_position:
+                                  bytes: 94
+                                  line: 5
+                                  character: 12
+                                token_type:
+                                  type: Symbol
+                                  symbol: ^
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 94
+                                    line: 5
+                                    character: 12
+                                  end_position:
+                                    bytes: 95
+                                    line: 5
+                                    character: 13
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                          rhs:
+                            Number:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 95
+                                  line: 5
+                                  character: 13
+                                end_position:
+                                  bytes: 96
+                                  line: 5
+                                  character: 14
+                                token_type:
+                                  type: Number
+                                  text: "2"
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 96
+                                    line: 5
+                                    character: 14
+                                  end_position:
+                                    bytes: 97
+                                    line: 5
+                                    character: 15
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                      binop:
+                        Star:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 97
+                              line: 5
+                              character: 15
+                            end_position:
+                              bytes: 98
+                              line: 5
+                              character: 16
+                            token_type:
+                              type: Symbol
+                              symbol: "*"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 98
+                                line: 5
+                                character: 16
+                              end_position:
+                                bytes: 99
+                                line: 5
+                                character: 17
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      rhs:
+                        Number:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 99
+                              line: 5
+                              character: 17
+                            end_position:
+                              bytes: 100
+                              line: 5
+                              character: 18
+                            token_type:
+                              type: Number
+                              text: "8"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 100
+                                line: 5
+                                character: 18
+                              end_position:
+                                bytes: 101
+                                line: 5
+                                character: 18
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+    - ~
+  - - Assignment:
+        var_list:
+          pairs:
+            - End:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 101
+                      line: 6
+                      character: 1
+                    end_position:
+                      bytes: 102
+                      line: 6
+                      character: 2
+                    token_type:
+                      type: Identifier
+                      identifier: f
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 102
+                        line: 6
+                        character: 2
+                      end_position:
+                        bytes: 103
+                        line: 6
+                        character: 3
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 103
+              line: 6
+              character: 3
+            end_position:
+              bytes: 104
+              line: 6
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 104
+                line: 6
+                character: 4
+              end_position:
+                bytes: 105
+                line: 6
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    BinaryOperator:
+                      lhs:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 105
+                                line: 6
+                                character: 5
+                              end_position:
+                                bytes: 106
+                                line: 6
+                                character: 6
+                              token_type:
+                                type: Identifier
+                                identifier: a
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 106
+                                  line: 6
+                                  character: 6
+                                end_position:
+                                  bytes: 107
+                                  line: 6
+                                  character: 7
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      binop:
+                        LessThan:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 107
+                              line: 6
+                              character: 7
+                            end_position:
+                              bytes: 108
+                              line: 6
+                              character: 8
+                            token_type:
+                              type: Symbol
+                              symbol: "<"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 108
+                                line: 6
+                                character: 8
+                              end_position:
+                                bytes: 109
+                                line: 6
+                                character: 9
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      rhs:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 109
+                                line: 6
+                                character: 9
+                              end_position:
+                                bytes: 110
+                                line: 6
+                                character: 10
+                              token_type:
+                                type: Identifier
+                                identifier: y
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 110
+                                  line: 6
+                                  character: 10
+                                end_position:
+                                  bytes: 111
+                                  line: 6
+                                  character: 11
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                  binop:
+                    And:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 111
+                          line: 6
+                          character: 11
+                        end_position:
+                          bytes: 114
+                          line: 6
+                          character: 14
+                        token_type:
+                          type: Symbol
+                          symbol: and
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 114
+                            line: 6
+                            character: 14
+                          end_position:
+                            bytes: 115
+                            line: 6
+                            character: 15
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    BinaryOperator:
+                      lhs:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 115
+                                line: 6
+                                character: 15
+                              end_position:
+                                bytes: 116
+                                line: 6
+                                character: 16
+                              token_type:
+                                type: Identifier
+                                identifier: y
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 116
+                                  line: 6
+                                  character: 16
+                                end_position:
+                                  bytes: 117
+                                  line: 6
+                                  character: 17
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      binop:
+                        LessThanEqual:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 117
+                              line: 6
+                              character: 17
+                            end_position:
+                              bytes: 119
+                              line: 6
+                              character: 19
+                            token_type:
+                              type: Symbol
+                              symbol: "<="
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 119
+                                line: 6
+                                character: 19
+                              end_position:
+                                bytes: 120
+                                line: 6
+                                character: 20
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      rhs:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 120
+                                line: 6
+                                character: 20
+                              end_position:
+                                bytes: 121
+                                line: 6
+                                character: 21
+                              token_type:
+                                type: Identifier
+                                identifier: z
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 121
+                                  line: 6
+                                  character: 21
+                                end_position:
+                                  bytes: 122
+                                  line: 6
+                                  character: 21
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+    - ~
+  - - Assignment:
+        var_list:
+          pairs:
+            - End:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 122
+                      line: 7
+                      character: 1
+                    end_position:
+                      bytes: 123
+                      line: 7
+                      character: 2
+                    token_type:
+                      type: Identifier
+                      identifier: g
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 123
+                        line: 7
+                        character: 2
+                      end_position:
+                        bytes: 124
+                        line: 7
+                        character: 3
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 124
+              line: 7
+              character: 3
+            end_position:
+              bytes: 125
+              line: 7
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 125
+                line: 7
+                character: 4
+              end_position:
+                bytes: 126
+                line: 7
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                UnaryOperator:
+                  unop:
+                    Minus:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 126
+                          line: 7
+                          character: 5
+                        end_position:
+                          bytes: 127
+                          line: 7
+                          character: 6
+                        token_type:
+                          type: Symbol
+                          symbol: "-"
+                      trailing_trivia: []
+                  expression:
+                    BinaryOperator:
+                      lhs:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 127
+                                line: 7
+                                character: 6
+                              end_position:
+                                bytes: 128
+                                line: 7
+                                character: 7
+                              token_type:
+                                type: Identifier
+                                identifier: x
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 128
+                                  line: 7
+                                  character: 7
+                                end_position:
+                                  bytes: 129
+                                  line: 7
+                                  character: 8
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      binop:
+                        Caret:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 129
+                              line: 7
+                              character: 8
+                            end_position:
+                              bytes: 130
+                              line: 7
+                              character: 9
+                            token_type:
+                              type: Symbol
+                              symbol: ^
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 130
+                                line: 7
+                                character: 9
+                              end_position:
+                                bytes: 131
+                                line: 7
+                                character: 10
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      rhs:
+                        Number:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 131
+                              line: 7
+                              character: 10
+                            end_position:
+                              bytes: 132
+                              line: 7
+                              character: 11
+                            token_type:
+                              type: Number
+                              text: "2"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 132
+                                line: 7
+                                character: 11
+                              end_position:
+                                bytes: 133
+                                line: 7
+                                character: 11
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+    - ~
+  - - Assignment:
+        var_list:
+          pairs:
+            - End:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 133
+                      line: 8
+                      character: 1
+                    end_position:
+                      bytes: 134
+                      line: 8
+                      character: 2
+                    token_type:
+                      type: Identifier
+                      identifier: h
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 134
+                        line: 8
+                        character: 2
+                      end_position:
+                        bytes: 135
+                        line: 8
+                        character: 3
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 135
+              line: 8
+              character: 3
+            end_position:
+              bytes: 136
+              line: 8
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 136
+                line: 8
+                character: 4
+              end_position:
+                bytes: 137
+                line: 8
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 137
+                            line: 8
+                            character: 5
+                          end_position:
+                            bytes: 138
+                            line: 8
+                            character: 6
+                          token_type:
+                            type: Identifier
+                            identifier: x
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 138
+                              line: 8
+                              character: 6
+                            end_position:
+                              bytes: 139
+                              line: 8
+                              character: 7
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  binop:
+                    Caret:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 139
+                          line: 8
+                          character: 7
+                        end_position:
+                          bytes: 140
+                          line: 8
+                          character: 8
+                        token_type:
+                          type: Symbol
+                          symbol: ^
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 140
+                            line: 8
+                            character: 8
+                          end_position:
+                            bytes: 141
+                            line: 8
+                            character: 9
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    BinaryOperator:
+                      lhs:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 141
+                                line: 8
+                                character: 9
+                              end_position:
+                                bytes: 142
+                                line: 8
+                                character: 10
+                              token_type:
+                                type: Identifier
+                                identifier: y
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 142
+                                  line: 8
+                                  character: 10
+                                end_position:
+                                  bytes: 143
+                                  line: 8
+                                  character: 11
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      binop:
+                        Caret:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 143
+                              line: 8
+                              character: 11
+                            end_position:
+                              bytes: 144
+                              line: 8
+                              character: 12
+                            token_type:
+                              type: Symbol
+                              symbol: ^
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 144
+                                line: 8
+                                character: 12
+                              end_position:
+                                bytes: 145
+                                line: 8
+                                character: 13
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      rhs:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 145
+                                line: 8
+                                character: 13
+                              end_position:
+                                bytes: 146
+                                line: 8
+                                character: 14
+                              token_type:
+                                type: Identifier
+                                identifier: z
+                            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/binops/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/binops/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..5397e71ca3f52252f542990ea76bfc7eba1e4ad3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/binops/source.lua
@@ -0,0 +1,8 @@
+a = foo and bar
+b = foo and bar or baz
+c = 1 + 2 * 3 - 4 ^ 2
+d = a + i < b / 2 + 1
+e = 5 + x ^ 2 * 8
+f = a < y and y <= z
+g = -x ^ 2
+h = x ^ y ^ z
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/binops/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/binops/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7d0e52d38df8b68e31d50e142d0f4ecf7c0b3a53
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/binops/tokens.snap
@@ -0,0 +1,1425 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/binops
+
+---
+- 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: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: foo
+- 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: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: and
+- 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: 15
+    line: 1
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: bar
+- 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: 17
+    line: 2
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 17
+    line: 2
+    character: 2
+  end_position:
+    bytes: 18
+    line: 2
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 18
+    line: 2
+    character: 3
+  end_position:
+    bytes: 19
+    line: 2
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 19
+    line: 2
+    character: 4
+  end_position:
+    bytes: 20
+    line: 2
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 20
+    line: 2
+    character: 5
+  end_position:
+    bytes: 23
+    line: 2
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 23
+    line: 2
+    character: 8
+  end_position:
+    bytes: 24
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 24
+    line: 2
+    character: 9
+  end_position:
+    bytes: 27
+    line: 2
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: and
+- start_position:
+    bytes: 27
+    line: 2
+    character: 12
+  end_position:
+    bytes: 28
+    line: 2
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 28
+    line: 2
+    character: 13
+  end_position:
+    bytes: 31
+    line: 2
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 31
+    line: 2
+    character: 16
+  end_position:
+    bytes: 32
+    line: 2
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 32
+    line: 2
+    character: 17
+  end_position:
+    bytes: 34
+    line: 2
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: or
+- start_position:
+    bytes: 34
+    line: 2
+    character: 19
+  end_position:
+    bytes: 35
+    line: 2
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 35
+    line: 2
+    character: 20
+  end_position:
+    bytes: 38
+    line: 2
+    character: 23
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 38
+    line: 2
+    character: 23
+  end_position:
+    bytes: 39
+    line: 2
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 39
+    line: 3
+    character: 1
+  end_position:
+    bytes: 40
+    line: 3
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: c
+- start_position:
+    bytes: 40
+    line: 3
+    character: 2
+  end_position:
+    bytes: 41
+    line: 3
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 41
+    line: 3
+    character: 3
+  end_position:
+    bytes: 42
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 42
+    line: 3
+    character: 4
+  end_position:
+    bytes: 43
+    line: 3
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 43
+    line: 3
+    character: 5
+  end_position:
+    bytes: 44
+    line: 3
+    character: 6
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 44
+    line: 3
+    character: 6
+  end_position:
+    bytes: 45
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 45
+    line: 3
+    character: 7
+  end_position:
+    bytes: 46
+    line: 3
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 46
+    line: 3
+    character: 8
+  end_position:
+    bytes: 47
+    line: 3
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 47
+    line: 3
+    character: 9
+  end_position:
+    bytes: 48
+    line: 3
+    character: 10
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 48
+    line: 3
+    character: 10
+  end_position:
+    bytes: 49
+    line: 3
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 49
+    line: 3
+    character: 11
+  end_position:
+    bytes: 50
+    line: 3
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: "*"
+- start_position:
+    bytes: 50
+    line: 3
+    character: 12
+  end_position:
+    bytes: 51
+    line: 3
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 51
+    line: 3
+    character: 13
+  end_position:
+    bytes: 52
+    line: 3
+    character: 14
+  token_type:
+    type: Number
+    text: "3"
+- start_position:
+    bytes: 52
+    line: 3
+    character: 14
+  end_position:
+    bytes: 53
+    line: 3
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 53
+    line: 3
+    character: 15
+  end_position:
+    bytes: 54
+    line: 3
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 54
+    line: 3
+    character: 16
+  end_position:
+    bytes: 55
+    line: 3
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 55
+    line: 3
+    character: 17
+  end_position:
+    bytes: 56
+    line: 3
+    character: 18
+  token_type:
+    type: Number
+    text: "4"
+- start_position:
+    bytes: 56
+    line: 3
+    character: 18
+  end_position:
+    bytes: 57
+    line: 3
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 57
+    line: 3
+    character: 19
+  end_position:
+    bytes: 58
+    line: 3
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: ^
+- start_position:
+    bytes: 58
+    line: 3
+    character: 20
+  end_position:
+    bytes: 59
+    line: 3
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 59
+    line: 3
+    character: 21
+  end_position:
+    bytes: 60
+    line: 3
+    character: 22
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 60
+    line: 3
+    character: 22
+  end_position:
+    bytes: 61
+    line: 3
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 61
+    line: 4
+    character: 1
+  end_position:
+    bytes: 62
+    line: 4
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: d
+- start_position:
+    bytes: 62
+    line: 4
+    character: 2
+  end_position:
+    bytes: 63
+    line: 4
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 63
+    line: 4
+    character: 3
+  end_position:
+    bytes: 64
+    line: 4
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 64
+    line: 4
+    character: 4
+  end_position:
+    bytes: 65
+    line: 4
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 65
+    line: 4
+    character: 5
+  end_position:
+    bytes: 66
+    line: 4
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: a
+- start_position:
+    bytes: 66
+    line: 4
+    character: 6
+  end_position:
+    bytes: 67
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 67
+    line: 4
+    character: 7
+  end_position:
+    bytes: 68
+    line: 4
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 68
+    line: 4
+    character: 8
+  end_position:
+    bytes: 69
+    line: 4
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 69
+    line: 4
+    character: 9
+  end_position:
+    bytes: 70
+    line: 4
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: i
+- start_position:
+    bytes: 70
+    line: 4
+    character: 10
+  end_position:
+    bytes: 71
+    line: 4
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 71
+    line: 4
+    character: 11
+  end_position:
+    bytes: 72
+    line: 4
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: "<"
+- start_position:
+    bytes: 72
+    line: 4
+    character: 12
+  end_position:
+    bytes: 73
+    line: 4
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 73
+    line: 4
+    character: 13
+  end_position:
+    bytes: 74
+    line: 4
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 74
+    line: 4
+    character: 14
+  end_position:
+    bytes: 75
+    line: 4
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 75
+    line: 4
+    character: 15
+  end_position:
+    bytes: 76
+    line: 4
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: /
+- start_position:
+    bytes: 76
+    line: 4
+    character: 16
+  end_position:
+    bytes: 77
+    line: 4
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 77
+    line: 4
+    character: 17
+  end_position:
+    bytes: 78
+    line: 4
+    character: 18
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 78
+    line: 4
+    character: 18
+  end_position:
+    bytes: 79
+    line: 4
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 79
+    line: 4
+    character: 19
+  end_position:
+    bytes: 80
+    line: 4
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 80
+    line: 4
+    character: 20
+  end_position:
+    bytes: 81
+    line: 4
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 81
+    line: 4
+    character: 21
+  end_position:
+    bytes: 82
+    line: 4
+    character: 22
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 82
+    line: 4
+    character: 22
+  end_position:
+    bytes: 83
+    line: 4
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 83
+    line: 5
+    character: 1
+  end_position:
+    bytes: 84
+    line: 5
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: e
+- start_position:
+    bytes: 84
+    line: 5
+    character: 2
+  end_position:
+    bytes: 85
+    line: 5
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 85
+    line: 5
+    character: 3
+  end_position:
+    bytes: 86
+    line: 5
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 86
+    line: 5
+    character: 4
+  end_position:
+    bytes: 87
+    line: 5
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 87
+    line: 5
+    character: 5
+  end_position:
+    bytes: 88
+    line: 5
+    character: 6
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 88
+    line: 5
+    character: 6
+  end_position:
+    bytes: 89
+    line: 5
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 89
+    line: 5
+    character: 7
+  end_position:
+    bytes: 90
+    line: 5
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 90
+    line: 5
+    character: 8
+  end_position:
+    bytes: 91
+    line: 5
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 91
+    line: 5
+    character: 9
+  end_position:
+    bytes: 92
+    line: 5
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 92
+    line: 5
+    character: 10
+  end_position:
+    bytes: 93
+    line: 5
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 93
+    line: 5
+    character: 11
+  end_position:
+    bytes: 94
+    line: 5
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: ^
+- start_position:
+    bytes: 94
+    line: 5
+    character: 12
+  end_position:
+    bytes: 95
+    line: 5
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 95
+    line: 5
+    character: 13
+  end_position:
+    bytes: 96
+    line: 5
+    character: 14
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 96
+    line: 5
+    character: 14
+  end_position:
+    bytes: 97
+    line: 5
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 97
+    line: 5
+    character: 15
+  end_position:
+    bytes: 98
+    line: 5
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "*"
+- start_position:
+    bytes: 98
+    line: 5
+    character: 16
+  end_position:
+    bytes: 99
+    line: 5
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 99
+    line: 5
+    character: 17
+  end_position:
+    bytes: 100
+    line: 5
+    character: 18
+  token_type:
+    type: Number
+    text: "8"
+- start_position:
+    bytes: 100
+    line: 5
+    character: 18
+  end_position:
+    bytes: 101
+    line: 5
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 101
+    line: 6
+    character: 1
+  end_position:
+    bytes: 102
+    line: 6
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: f
+- start_position:
+    bytes: 102
+    line: 6
+    character: 2
+  end_position:
+    bytes: 103
+    line: 6
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 103
+    line: 6
+    character: 3
+  end_position:
+    bytes: 104
+    line: 6
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 104
+    line: 6
+    character: 4
+  end_position:
+    bytes: 105
+    line: 6
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 105
+    line: 6
+    character: 5
+  end_position:
+    bytes: 106
+    line: 6
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: a
+- start_position:
+    bytes: 106
+    line: 6
+    character: 6
+  end_position:
+    bytes: 107
+    line: 6
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 107
+    line: 6
+    character: 7
+  end_position:
+    bytes: 108
+    line: 6
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: "<"
+- start_position:
+    bytes: 108
+    line: 6
+    character: 8
+  end_position:
+    bytes: 109
+    line: 6
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 109
+    line: 6
+    character: 9
+  end_position:
+    bytes: 110
+    line: 6
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 110
+    line: 6
+    character: 10
+  end_position:
+    bytes: 111
+    line: 6
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 111
+    line: 6
+    character: 11
+  end_position:
+    bytes: 114
+    line: 6
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: and
+- start_position:
+    bytes: 114
+    line: 6
+    character: 14
+  end_position:
+    bytes: 115
+    line: 6
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 115
+    line: 6
+    character: 15
+  end_position:
+    bytes: 116
+    line: 6
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 116
+    line: 6
+    character: 16
+  end_position:
+    bytes: 117
+    line: 6
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 117
+    line: 6
+    character: 17
+  end_position:
+    bytes: 119
+    line: 6
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: "<="
+- start_position:
+    bytes: 119
+    line: 6
+    character: 19
+  end_position:
+    bytes: 120
+    line: 6
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 120
+    line: 6
+    character: 20
+  end_position:
+    bytes: 121
+    line: 6
+    character: 21
+  token_type:
+    type: Identifier
+    identifier: z
+- start_position:
+    bytes: 121
+    line: 6
+    character: 21
+  end_position:
+    bytes: 122
+    line: 6
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 122
+    line: 7
+    character: 1
+  end_position:
+    bytes: 123
+    line: 7
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: g
+- start_position:
+    bytes: 123
+    line: 7
+    character: 2
+  end_position:
+    bytes: 124
+    line: 7
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 124
+    line: 7
+    character: 3
+  end_position:
+    bytes: 125
+    line: 7
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 125
+    line: 7
+    character: 4
+  end_position:
+    bytes: 126
+    line: 7
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 126
+    line: 7
+    character: 5
+  end_position:
+    bytes: 127
+    line: 7
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 127
+    line: 7
+    character: 6
+  end_position:
+    bytes: 128
+    line: 7
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 128
+    line: 7
+    character: 7
+  end_position:
+    bytes: 129
+    line: 7
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 129
+    line: 7
+    character: 8
+  end_position:
+    bytes: 130
+    line: 7
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: ^
+- start_position:
+    bytes: 130
+    line: 7
+    character: 9
+  end_position:
+    bytes: 131
+    line: 7
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 131
+    line: 7
+    character: 10
+  end_position:
+    bytes: 132
+    line: 7
+    character: 11
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 132
+    line: 7
+    character: 11
+  end_position:
+    bytes: 133
+    line: 7
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 133
+    line: 8
+    character: 1
+  end_position:
+    bytes: 134
+    line: 8
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: h
+- start_position:
+    bytes: 134
+    line: 8
+    character: 2
+  end_position:
+    bytes: 135
+    line: 8
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 135
+    line: 8
+    character: 3
+  end_position:
+    bytes: 136
+    line: 8
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 136
+    line: 8
+    character: 4
+  end_position:
+    bytes: 137
+    line: 8
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 137
+    line: 8
+    character: 5
+  end_position:
+    bytes: 138
+    line: 8
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 138
+    line: 8
+    character: 6
+  end_position:
+    bytes: 139
+    line: 8
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 139
+    line: 8
+    character: 7
+  end_position:
+    bytes: 140
+    line: 8
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: ^
+- start_position:
+    bytes: 140
+    line: 8
+    character: 8
+  end_position:
+    bytes: 141
+    line: 8
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 141
+    line: 8
+    character: 9
+  end_position:
+    bytes: 142
+    line: 8
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 142
+    line: 8
+    character: 10
+  end_position:
+    bytes: 143
+    line: 8
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 143
+    line: 8
+    character: 11
+  end_position:
+    bytes: 144
+    line: 8
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: ^
+- start_position:
+    bytes: 144
+    line: 8
+    character: 12
+  end_position:
+    bytes: 145
+    line: 8
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 145
+    line: 8
+    character: 13
+  end_position:
+    bytes: 146
+    line: 8
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: z
+- start_position:
+    bytes: 146
+    line: 8
+    character: 14
+  end_position:
+    bytes: 146
+    line: 8
+    character: 14
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/body-with-spaces/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/body-with-spaces/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..46d33fda3558d53357ff7865cf888a586cb084c1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/pass/body-with-spaces/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/body-with-spaces/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..c0697c93e79c5121f4865f7cf3975d16f664d2e7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/body-with-spaces/source.lua
@@ -0,0 +1,3 @@
+do
+    
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/body-with-spaces/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/body-with-spaces/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..841093a4e3750a772830229b514b61bdd12d712e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/pass/call-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/call-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f2b812e74ac11f5bb7ba27d6518b0cc8ca977254
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/call-1/ast.snap
@@ -0,0 +1,265 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/call-1
+---
+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: 5
+                            line: 1
+                            character: 6
+                          end_position:
+                            bytes: 6
+                            line: 1
+                            character: 7
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 6
+                              line: 1
+                              character: 7
+                            end_position:
+                              bytes: 7
+                              line: 1
+                              character: 7
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 7
+                line: 2
+                character: 1
+              end_position:
+                bytes: 11
+                line: 2
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 11
+                            line: 2
+                            character: 5
+                          end_position:
+                            bytes: 12
+                            line: 2
+                            character: 6
+                          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:
+                          Number:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 12
+                                line: 2
+                                character: 6
+                              end_position:
+                                bytes: 13
+                                line: 2
+                                character: 7
+                              token_type:
+                                type: Number
+                                text: "1"
+                            trailing_trivia: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 15
+                line: 3
+                character: 1
+              end_position:
+                bytes: 19
+                line: 3
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 19
+                            line: 3
+                            character: 5
+                          end_position:
+                            bytes: 20
+                            line: 3
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 24
+                            line: 3
+                            character: 10
+                          end_position:
+                            bytes: 25
+                            line: 3
+                            character: 11
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia: []
+                  arguments:
+                    pairs:
+                      - Punctuated:
+                          - Number:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 20
+                                  line: 3
+                                  character: 6
+                                end_position:
+                                  bytes: 21
+                                  line: 3
+                                  character: 7
+                                token_type:
+                                  type: Number
+                                  text: "1"
+                              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:
+                              - start_position:
+                                  bytes: 22
+                                  line: 3
+                                  character: 8
+                                end_position:
+                                  bytes: 23
+                                  line: 3
+                                  character: 9
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      - End:
+                          Number:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 23
+                                line: 3
+                                character: 9
+                              end_position:
+                                bytes: 24
+                                line: 3
+                                character: 10
+                              token_type:
+                                type: Number
+                                text: "2"
+                            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/call-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/call-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..42e66348fe513093fd7ad696b19cbf1e611eaaa5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/call-1/source.lua
@@ -0,0 +1,3 @@
+call()
+call(1)
+call(1, 2)
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/call-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/call-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c0062d305767924a9fc6488f149fb1c78a548ea7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/call-1/tokens.snap
@@ -0,0 +1,193 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/call-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 7
+    line: 2
+    character: 1
+  end_position:
+    bytes: 11
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 11
+    line: 2
+    character: 5
+  end_position:
+    bytes: 12
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 12
+    line: 2
+    character: 6
+  end_position:
+    bytes: 13
+    line: 2
+    character: 7
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 13
+    line: 2
+    character: 7
+  end_position:
+    bytes: 14
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 14
+    line: 2
+    character: 8
+  end_position:
+    bytes: 15
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 3
+    character: 1
+  end_position:
+    bytes: 19
+    line: 3
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 19
+    line: 3
+    character: 5
+  end_position:
+    bytes: 20
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 20
+    line: 3
+    character: 6
+  end_position:
+    bytes: 21
+    line: 3
+    character: 7
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 21
+    line: 3
+    character: 7
+  end_position:
+    bytes: 22
+    line: 3
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 22
+    line: 3
+    character: 8
+  end_position:
+    bytes: 23
+    line: 3
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 23
+    line: 3
+    character: 9
+  end_position:
+    bytes: 24
+    line: 3
+    character: 10
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 24
+    line: 3
+    character: 10
+  end_position:
+    bytes: 25
+    line: 3
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 25
+    line: 3
+    character: 11
+  end_position:
+    bytes: 25
+    line: 3
+    character: 11
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/call-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/call-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f31d1a87458f5465c9dae744a9faded81eeabe33
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/call-2/ast.snap
@@ -0,0 +1,224 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/call-2
+---
+stmts:
+  - - FunctionCall:
+        prefix:
+          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: []
+        suffixes:
+          - Index:
+              Dot:
+                dot:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 1
+                      line: 1
+                      character: 2
+                    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: 3
+                      line: 1
+                      character: 4
+                    token_type:
+                      type: Identifier
+                      identifier: y
+                  trailing_trivia: []
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - 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: []
+                      - 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"
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 4
+                                line: 1
+                                character: 5
+                              end_position:
+                                bytes: 7
+                                line: 1
+                                character: 8
+                              token_type:
+                                type: StringLiteral
+                                literal: a
+                                quote_type: Double
+                            trailing_trivia: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 9
+                line: 2
+                character: 1
+              end_position:
+                bytes: 10
+                line: 2
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              MethodCall:
+                colon_token:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 10
+                      line: 2
+                      character: 2
+                    end_position:
+                      bytes: 11
+                      line: 2
+                      character: 3
+                    token_type:
+                      type: Symbol
+                      symbol: ":"
+                  trailing_trivia: []
+                name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 11
+                      line: 2
+                      character: 3
+                    end_position:
+                      bytes: 12
+                      line: 2
+                      character: 4
+                    token_type:
+                      type: Identifier
+                      identifier: y
+                  trailing_trivia: []
+                args:
+                  Parentheses:
+                    parentheses:
+                      tokens:
+                        - 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: []
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 16
+                              line: 2
+                              character: 8
+                            end_position:
+                              bytes: 17
+                              line: 2
+                              character: 9
+                            token_type:
+                              type: Symbol
+                              symbol: )
+                          trailing_trivia: []
+                    arguments:
+                      pairs:
+                        - End:
+                            String:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 13
+                                  line: 2
+                                  character: 5
+                                end_position:
+                                  bytes: 16
+                                  line: 2
+                                  character: 8
+                                token_type:
+                                  type: StringLiteral
+                                  literal: b
+                                  quote_type: Double
+                              trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/call-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/call-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..d65eca40075d346dbb1e1aa5b31efaa8d2602b07
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/call-2/source.lua
@@ -0,0 +1,2 @@
+x.y("a")
+x:y("b")
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/call-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/call-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e265844d1a3fcc5562652722b79aa4f3f5069313
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/call-2/tokens.snap
@@ -0,0 +1,162 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/call-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 1
+    line: 1
+    character: 2
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Identifier
+    identifier: y
+- 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: 7
+    line: 1
+    character: 8
+  token_type:
+    type: StringLiteral
+    literal: a
+    quote_type: Double
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: )
+- 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: 10
+    line: 2
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 10
+    line: 2
+    character: 2
+  end_position:
+    bytes: 11
+    line: 2
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 11
+    line: 2
+    character: 3
+  end_position:
+    bytes: 12
+    line: 2
+    character: 4
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 12
+    line: 2
+    character: 4
+  end_position:
+    bytes: 13
+    line: 2
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 13
+    line: 2
+    character: 5
+  end_position:
+    bytes: 16
+    line: 2
+    character: 8
+  token_type:
+    type: StringLiteral
+    literal: b
+    quote_type: Double
+- start_position:
+    bytes: 16
+    line: 2
+    character: 8
+  end_position:
+    bytes: 17
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 17
+    line: 2
+    character: 9
+  end_position:
+    bytes: 17
+    line: 2
+    character: 9
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/do/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/do/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..68979cf55f46c3488ed43102b9e1b78ea18de42e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/do/ast.snap
@@ -0,0 +1,129 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/do
+
+---
+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:
+                                    - start_position:
+                                        bytes: 10
+                                        line: 2
+                                        character: 8
+                                      end_position:
+                                        bytes: 11
+                                        line: 2
+                                        character: 8
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\n"
+                            arguments:
+                              pairs: []
+              - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 11
+              line: 3
+              character: 1
+            end_position:
+              bytes: 14
+              line: 3
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/do/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/do/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..634f506da21f2af245d13ad7af031bd5be45f55a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/do/source.lua
@@ -0,0 +1,3 @@
+do
+	call()
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/do/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/do/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..27870214b470fd8e121701cf7bbaa8414829db9e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/do/tokens.snap
@@ -0,0 +1,105 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/do
+
+---
+- 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: 4
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 4
+    line: 2
+    character: 2
+  end_position:
+    bytes: 8
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 8
+    line: 2
+    character: 6
+  end_position:
+    bytes: 9
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 9
+    line: 2
+    character: 7
+  end_position:
+    bytes: 10
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 10
+    line: 2
+    character: 8
+  end_position:
+    bytes: 11
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 11
+    line: 3
+    character: 1
+  end_position:
+    bytes: 14
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 14
+    line: 3
+    character: 4
+  end_position:
+    bytes: 14
+    line: 3
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/empty/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/empty/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3bc4ce6b5a343a04773dc7bd3c20550bb9d60c2a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/empty/ast.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/empty
+
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/empty/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/empty/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/empty/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/empty/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ede4fa88725e64d8b4e0a302f20ed2ac00dd9175
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/empty/tokens.snap
@@ -0,0 +1,17 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/empty
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 0
+    line: 1
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/exponents/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/exponents/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1fd0d77fedcab23aa30196e1f7523b1032bb930a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/exponents/ast.snap
@@ -0,0 +1,330 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/exponents
+---
+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: 9
+                    line: 1
+                    character: 10
+                  token_type:
+                    type: Identifier
+                    identifier: num
+                trailing_trivia:
+                  - start_position:
+                      bytes: 9
+                      line: 1
+                      character: 10
+                    end_position:
+                      bytes: 10
+                      line: 1
+                      character: 11
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 12
+                      line: 1
+                      character: 13
+                    end_position:
+                      bytes: 15
+                      line: 1
+                      character: 16
+                    token_type:
+                      type: Number
+                      text: "1e5"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 15
+                        line: 1
+                        character: 16
+                      end_position:
+                        bytes: 16
+                        line: 1
+                        character: 16
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 16
+              line: 2
+              character: 1
+            end_position:
+              bytes: 21
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 21
+                line: 2
+                character: 6
+              end_position:
+                bytes: 22
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 22
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 26
+                    line: 2
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: num2
+                trailing_trivia:
+                  - start_position:
+                      bytes: 26
+                      line: 2
+                      character: 11
+                    end_position:
+                      bytes: 27
+                      line: 2
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 29
+                      line: 2
+                      character: 14
+                    end_position:
+                      bytes: 33
+                      line: 2
+                      character: 18
+                    token_type:
+                      type: Number
+                      text: "1e-5"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 33
+                        line: 2
+                        character: 18
+                      end_position:
+                        bytes: 34
+                        line: 2
+                        character: 18
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 34
+              line: 3
+              character: 1
+            end_position:
+              bytes: 39
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 39
+                line: 3
+                character: 6
+              end_position:
+                bytes: 40
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 40
+                    line: 3
+                    character: 7
+                  end_position:
+                    bytes: 44
+                    line: 3
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: num3
+                trailing_trivia:
+                  - start_position:
+                      bytes: 44
+                      line: 3
+                      character: 11
+                    end_position:
+                      bytes: 45
+                      line: 3
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 45
+              line: 3
+              character: 12
+            end_position:
+              bytes: 46
+              line: 3
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 46
+                line: 3
+                character: 13
+              end_position:
+                bytes: 47
+                line: 3
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 47
+                      line: 3
+                      character: 14
+                    end_position:
+                      bytes: 51
+                      line: 3
+                      character: 18
+                    token_type:
+                      type: Number
+                      text: "1e+5"
+                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/exponents/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/exponents/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..c4300642107175b907dda77053c70174e40a9cc1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/exponents/source.lua
@@ -0,0 +1,3 @@
+local num = 1e5
+local num2 = 1e-5
+local num3 = 1e+5
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/exponents/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/exponents/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f1489769e7a66dc9485d8f666f17512840e0f0c2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/exponents/tokens.snap
@@ -0,0 +1,270 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/exponents
+
+---
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: num
+- 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: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 15
+    line: 1
+    character: 16
+  token_type:
+    type: Number
+    text: "1e5"
+- 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: 21
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 21
+    line: 2
+    character: 6
+  end_position:
+    bytes: 22
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 22
+    line: 2
+    character: 7
+  end_position:
+    bytes: 26
+    line: 2
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num2
+- start_position:
+    bytes: 26
+    line: 2
+    character: 11
+  end_position:
+    bytes: 27
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- 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: 33
+    line: 2
+    character: 18
+  token_type:
+    type: Number
+    text: "1e-5"
+- start_position:
+    bytes: 33
+    line: 2
+    character: 18
+  end_position:
+    bytes: 34
+    line: 2
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 34
+    line: 3
+    character: 1
+  end_position:
+    bytes: 39
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 39
+    line: 3
+    character: 6
+  end_position:
+    bytes: 40
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 40
+    line: 3
+    character: 7
+  end_position:
+    bytes: 44
+    line: 3
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num3
+- start_position:
+    bytes: 44
+    line: 3
+    character: 11
+  end_position:
+    bytes: 45
+    line: 3
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 45
+    line: 3
+    character: 12
+  end_position:
+    bytes: 46
+    line: 3
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 46
+    line: 3
+    character: 13
+  end_position:
+    bytes: 47
+    line: 3
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 47
+    line: 3
+    character: 14
+  end_position:
+    bytes: 51
+    line: 3
+    character: 18
+  token_type:
+    type: Number
+    text: "1e+5"
+- start_position:
+    bytes: 51
+    line: 3
+    character: 18
+  end_position:
+    bytes: 51
+    line: 3
+    character: 18
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/fractional-numbers/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/fractional-numbers/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..01570051e5c78df39bed155cdd0844324f8ec07f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/fractional-numbers/ast.snap
@@ -0,0 +1,563 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/fractional-numbers
+---
+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: 9
+                    line: 1
+                    character: 10
+                  token_type:
+                    type: Identifier
+                    identifier: num
+                trailing_trivia:
+                  - start_position:
+                      bytes: 9
+                      line: 1
+                      character: 10
+                    end_position:
+                      bytes: 10
+                      line: 1
+                      character: 11
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 12
+                      line: 1
+                      character: 13
+                    end_position:
+                      bytes: 15
+                      line: 1
+                      character: 16
+                    token_type:
+                      type: Number
+                      text: "0.5"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 15
+                        line: 1
+                        character: 16
+                      end_position:
+                        bytes: 16
+                        line: 1
+                        character: 16
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 16
+              line: 2
+              character: 1
+            end_position:
+              bytes: 21
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 21
+                line: 2
+                character: 6
+              end_position:
+                bytes: 22
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 22
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 26
+                    line: 2
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: num2
+                trailing_trivia:
+                  - start_position:
+                      bytes: 26
+                      line: 2
+                      character: 11
+                    end_position:
+                      bytes: 27
+                      line: 2
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 29
+                      line: 2
+                      character: 14
+                    end_position:
+                      bytes: 34
+                      line: 2
+                      character: 19
+                    token_type:
+                      type: Number
+                      text: "0.5e5"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 34
+                        line: 2
+                        character: 19
+                      end_position:
+                        bytes: 35
+                        line: 2
+                        character: 19
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          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: 45
+                    line: 3
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: num3
+                trailing_trivia:
+                  - start_position:
+                      bytes: 45
+                      line: 3
+                      character: 11
+                    end_position:
+                      bytes: 46
+                      line: 3
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 46
+              line: 3
+              character: 12
+            end_position:
+              bytes: 47
+              line: 3
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 47
+                line: 3
+                character: 13
+              end_position:
+                bytes: 48
+                line: 3
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 48
+                      line: 3
+                      character: 14
+                    end_position:
+                      bytes: 50
+                      line: 3
+                      character: 16
+                    token_type:
+                      type: Number
+                      text: ".5"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 50
+                        line: 3
+                        character: 16
+                      end_position:
+                        bytes: 51
+                        line: 3
+                        character: 16
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 51
+              line: 4
+              character: 1
+            end_position:
+              bytes: 56
+              line: 4
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 56
+                line: 4
+                character: 6
+              end_position:
+                bytes: 57
+                line: 4
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 57
+                    line: 4
+                    character: 7
+                  end_position:
+                    bytes: 61
+                    line: 4
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: num4
+                trailing_trivia:
+                  - start_position:
+                      bytes: 61
+                      line: 4
+                      character: 11
+                    end_position:
+                      bytes: 62
+                      line: 4
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 62
+              line: 4
+              character: 12
+            end_position:
+              bytes: 63
+              line: 4
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 63
+                line: 4
+                character: 13
+              end_position:
+                bytes: 64
+                line: 4
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 64
+                      line: 4
+                      character: 14
+                    end_position:
+                      bytes: 68
+                      line: 4
+                      character: 18
+                    token_type:
+                      type: Number
+                      text: ".5e5"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 68
+                        line: 4
+                        character: 18
+                      end_position:
+                        bytes: 69
+                        line: 4
+                        character: 18
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 69
+              line: 5
+              character: 1
+            end_position:
+              bytes: 74
+              line: 5
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 74
+                line: 5
+                character: 6
+              end_position:
+                bytes: 75
+                line: 5
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 75
+                    line: 5
+                    character: 7
+                  end_position:
+                    bytes: 79
+                    line: 5
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: num5
+                trailing_trivia:
+                  - start_position:
+                      bytes: 79
+                      line: 5
+                      character: 11
+                    end_position:
+                      bytes: 80
+                      line: 5
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 80
+              line: 5
+              character: 12
+            end_position:
+              bytes: 81
+              line: 5
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 81
+                line: 5
+                character: 13
+              end_position:
+                bytes: 82
+                line: 5
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 82
+                      line: 5
+                      character: 14
+                    end_position:
+                      bytes: 84
+                      line: 5
+                      character: 16
+                    token_type:
+                      type: Number
+                      text: "1."
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 84
+                        line: 5
+                        character: 16
+                      end_position:
+                        bytes: 85
+                        line: 5
+                        character: 16
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/fractional-numbers/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/fractional-numbers/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2b7574609527e43175ae0615aa8b076fafd2cc87
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/fractional-numbers/source.lua
@@ -0,0 +1,5 @@
+local num = 0.5
+local num2 = 0.5e5
+local num3 = .5
+local num4 = .5e5
+local num5 = 1.
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/fractional-numbers/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/fractional-numbers/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..dffd1e4875390b4e7ee4b7997474bd14682cd334
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/fractional-numbers/tokens.snap
@@ -0,0 +1,457 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/fractional-numbers
+
+---
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: num
+- 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: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 15
+    line: 1
+    character: 16
+  token_type:
+    type: Number
+    text: "0.5"
+- 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: 21
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 21
+    line: 2
+    character: 6
+  end_position:
+    bytes: 22
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 22
+    line: 2
+    character: 7
+  end_position:
+    bytes: 26
+    line: 2
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num2
+- start_position:
+    bytes: 26
+    line: 2
+    character: 11
+  end_position:
+    bytes: 27
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- 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: 34
+    line: 2
+    character: 19
+  token_type:
+    type: Number
+    text: "0.5e5"
+- start_position:
+    bytes: 34
+    line: 2
+    character: 19
+  end_position:
+    bytes: 35
+    line: 2
+    character: 19
+  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: 45
+    line: 3
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num3
+- start_position:
+    bytes: 45
+    line: 3
+    character: 11
+  end_position:
+    bytes: 46
+    line: 3
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 46
+    line: 3
+    character: 12
+  end_position:
+    bytes: 47
+    line: 3
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 47
+    line: 3
+    character: 13
+  end_position:
+    bytes: 48
+    line: 3
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 48
+    line: 3
+    character: 14
+  end_position:
+    bytes: 50
+    line: 3
+    character: 16
+  token_type:
+    type: Number
+    text: ".5"
+- start_position:
+    bytes: 50
+    line: 3
+    character: 16
+  end_position:
+    bytes: 51
+    line: 3
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 51
+    line: 4
+    character: 1
+  end_position:
+    bytes: 56
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 56
+    line: 4
+    character: 6
+  end_position:
+    bytes: 57
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 57
+    line: 4
+    character: 7
+  end_position:
+    bytes: 61
+    line: 4
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num4
+- start_position:
+    bytes: 61
+    line: 4
+    character: 11
+  end_position:
+    bytes: 62
+    line: 4
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 62
+    line: 4
+    character: 12
+  end_position:
+    bytes: 63
+    line: 4
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 63
+    line: 4
+    character: 13
+  end_position:
+    bytes: 64
+    line: 4
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 64
+    line: 4
+    character: 14
+  end_position:
+    bytes: 68
+    line: 4
+    character: 18
+  token_type:
+    type: Number
+    text: ".5e5"
+- start_position:
+    bytes: 68
+    line: 4
+    character: 18
+  end_position:
+    bytes: 69
+    line: 4
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 69
+    line: 5
+    character: 1
+  end_position:
+    bytes: 74
+    line: 5
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 74
+    line: 5
+    character: 6
+  end_position:
+    bytes: 75
+    line: 5
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 75
+    line: 5
+    character: 7
+  end_position:
+    bytes: 79
+    line: 5
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num5
+- start_position:
+    bytes: 79
+    line: 5
+    character: 11
+  end_position:
+    bytes: 80
+    line: 5
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 80
+    line: 5
+    character: 12
+  end_position:
+    bytes: 81
+    line: 5
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 81
+    line: 5
+    character: 13
+  end_position:
+    bytes: 82
+    line: 5
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 82
+    line: 5
+    character: 14
+  end_position:
+    bytes: 84
+    line: 5
+    character: 16
+  token_type:
+    type: Number
+    text: "1."
+- start_position:
+    bytes: 84
+    line: 5
+    character: 16
+  end_position:
+    bytes: 85
+    line: 5
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 85
+    line: 6
+    character: 1
+  end_position:
+    bytes: 85
+    line: 6
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5a8d4935473be5e07202ab087827ade3dcb09d0b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-1/ast.snap
@@ -0,0 +1,192 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/function-declaration-1
+
+---
+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:
+                  - start_position:
+                      bytes: 12
+                      line: 1
+                      character: 13
+                    end_position:
+                      bytes: 13
+                      line: 1
+                      character: 13
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+          parameters:
+            pairs: []
+          block:
+            stmts:
+              - - FunctionCall:
+                    prefix:
+                      Name:
+                        leading_trivia:
+                          - start_position:
+                              bytes: 13
+                              line: 2
+                              character: 1
+                            end_position:
+                              bytes: 14
+                              line: 2
+                              character: 2
+                            token_type:
+                              type: Whitespace
+                              characters: "\t"
+                        token:
+                          start_position:
+                            bytes: 14
+                            line: 2
+                            character: 2
+                          end_position:
+                            bytes: 18
+                            line: 2
+                            character: 6
+                          token_type:
+                            type: Identifier
+                            identifier: call
+                        trailing_trivia: []
+                    suffixes:
+                      - Call:
+                          AnonymousCall:
+                            Parentheses:
+                              parentheses:
+                                tokens:
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 18
+                                        line: 2
+                                        character: 6
+                                      end_position:
+                                        bytes: 19
+                                        line: 2
+                                        character: 7
+                                      token_type:
+                                        type: Symbol
+                                        symbol: (
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 19
+                                        line: 2
+                                        character: 7
+                                      end_position:
+                                        bytes: 20
+                                        line: 2
+                                        character: 8
+                                      token_type:
+                                        type: Symbol
+                                        symbol: )
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 20
+                                          line: 2
+                                          character: 8
+                                        end_position:
+                                          bytes: 21
+                                          line: 2
+                                          character: 8
+                                        token_type:
+                                          type: Whitespace
+                                          characters: "\n"
+                              arguments:
+                                pairs: []
+                - ~
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 21
+                line: 3
+                character: 1
+              end_position:
+                bytes: 24
+                line: 3
+                character: 4
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..a74feae4462f3510912990048f98f24b6210e5fa
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-1/source.lua
@@ -0,0 +1,3 @@
+function x()
+	call()
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7527c1627e223d14629a4cabfb1dbb95fcb22a3a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-1/tokens.snap
@@ -0,0 +1,149 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/function-declaration-1
+
+---
+- 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: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 13
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 13
+    line: 1
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 13
+    line: 2
+    character: 1
+  end_position:
+    bytes: 14
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 14
+    line: 2
+    character: 2
+  end_position:
+    bytes: 18
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 18
+    line: 2
+    character: 6
+  end_position:
+    bytes: 19
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 19
+    line: 2
+    character: 7
+  end_position:
+    bytes: 20
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 20
+    line: 2
+    character: 8
+  end_position:
+    bytes: 21
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 21
+    line: 3
+    character: 1
+  end_position:
+    bytes: 24
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 24
+    line: 3
+    character: 4
+  end_position:
+    bytes: 24
+    line: 3
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a3faef376476e98fd37733d50a6b51f50f6d0558
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-2/ast.snap
@@ -0,0 +1,173 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/function-declaration-2
+
+---
+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:
+              - Punctuated:
+                  - 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: []
+                  - 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: []
+              - End:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 11
+                      line: 1
+                      character: 12
+                    end_position:
+                      bytes: 12
+                      line: 1
+                      character: 13
+                    token_type:
+                      type: Identifier
+                      identifier: y
+                  trailing_trivia: []
+          colon_name:
+            - 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: Identifier
+                  identifier: z
+              trailing_trivia: []
+        body:
+          parameters_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: 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: " "
+          parameters:
+            pairs: []
+          block:
+            stmts: []
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 17
+                line: 1
+                character: 18
+              end_position:
+                bytes: 20
+                line: 1
+                character: 21
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..b5b1dbc6707d6b4ffdb8c1589f1082e2606be175
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-2/source.lua
@@ -0,0 +1 @@
+function x.y:z() end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3b0d54490b3c851e2d92ffc33e68d98e7b44eee2
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/function-declaration-2/tokens.snap
@@ -0,0 +1,138 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/function-declaration-2
+
+---
+- 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: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 13
+  token_type:
+    type: Identifier
+    identifier: y
+- 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: Identifier
+    identifier: z
+- 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: 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: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/function-shortcuts/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/function-shortcuts/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..07f5908d352dc8ab72e28973f8c021f90da6d5a7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/function-shortcuts/ast.snap
@@ -0,0 +1,224 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/function-shortcuts
+---
+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:
+              - start_position:
+                  bytes: 4
+                  line: 1
+                  character: 5
+                end_position:
+                  bytes: 5
+                  line: 1
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        suffixes:
+          - Call:
+              AnonymousCall:
+                TableConstructor:
+                  braces:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 5
+                            line: 1
+                            character: 6
+                          end_position:
+                            bytes: 6
+                            line: 1
+                            character: 7
+                          token_type:
+                            type: Symbol
+                            symbol: "{"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 6
+                              line: 1
+                              character: 7
+                            end_position:
+                              bytes: 7
+                              line: 1
+                              character: 8
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      - 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: 15
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  fields:
+                    pairs:
+                      - End:
+                          NameKey:
+                            key:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 7
+                                  line: 1
+                                  character: 8
+                                end_position:
+                                  bytes: 8
+                                  line: 1
+                                  character: 9
+                                token_type:
+                                  type: Identifier
+                                  identifier: x
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 8
+                                    line: 1
+                                    character: 9
+                                  end_position:
+                                    bytes: 9
+                                    line: 1
+                                    character: 10
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            equal:
+                              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: " "
+                            value:
+                              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: "1"
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 12
+                                      line: 1
+                                      character: 13
+                                    end_position:
+                                      bytes: 13
+                                      line: 1
+                                      character: 14
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 15
+                line: 2
+                character: 1
+              end_position:
+                bytes: 19
+                line: 2
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia:
+              - start_position:
+                  bytes: 19
+                  line: 2
+                  character: 5
+                end_position:
+                  bytes: 20
+                  line: 2
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        suffixes:
+          - Call:
+              AnonymousCall:
+                String:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 20
+                      line: 2
+                      character: 6
+                    end_position:
+                      bytes: 27
+                      line: 2
+                      character: 13
+                    token_type:
+                      type: StringLiteral
+                      literal: hello
+                      quote_type: Double
+                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/function-shortcuts/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/function-shortcuts/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..a41c8959f5ad3665143f5bd73920d3186ad4531b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/function-shortcuts/source.lua
@@ -0,0 +1,2 @@
+call { x = 1 }
+call "hello"
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/function-shortcuts/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/function-shortcuts/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..12032a0a36542d4aabf7a4ac610248ebac8ba459
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/function-shortcuts/tokens.snap
@@ -0,0 +1,183 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/function-shortcuts
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- 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: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: Number
+    text: "1"
+- 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: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 14
+    line: 1
+    character: 15
+  end_position:
+    bytes: 15
+    line: 1
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 2
+    character: 1
+  end_position:
+    bytes: 19
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 19
+    line: 2
+    character: 5
+  end_position:
+    bytes: 20
+    line: 2
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 20
+    line: 2
+    character: 6
+  end_position:
+    bytes: 27
+    line: 2
+    character: 13
+  token_type:
+    type: StringLiteral
+    literal: hello
+    quote_type: Double
+- start_position:
+    bytes: 27
+    line: 2
+    character: 13
+  end_position:
+    bytes: 27
+    line: 2
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0a09d51f51d6572386c5627605f40df3ff11b2ba
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-1/ast.snap
@@ -0,0 +1,392 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/generic-for-loop-1
+---
+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:
+            - Punctuated:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 4
+                      line: 1
+                      character: 5
+                    end_position:
+                      bytes: 9
+                      line: 1
+                      character: 10
+                    token_type:
+                      type: Identifier
+                      identifier: index
+                  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:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 11
+                    line: 1
+                    character: 12
+                  end_position:
+                    bytes: 16
+                    line: 1
+                    character: 17
+                  token_type:
+                    type: Identifier
+                    identifier: value
+                trailing_trivia:
+                  - start_position:
+                      bytes: 16
+                      line: 1
+                      character: 17
+                    end_position:
+                      bytes: 17
+                      line: 1
+                      character: 18
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        in_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 17
+              line: 1
+              character: 18
+            end_position:
+              bytes: 19
+              line: 1
+              character: 20
+            token_type:
+              type: Symbol
+              symbol: in
+          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:
+                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_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: 35
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        block:
+          stmts:
+            - - FunctionCall:
+                  prefix:
+                    Name:
+                      leading_trivia:
+                        - start_position:
+                            bytes: 35
+                            line: 2
+                            character: 1
+                          end_position:
+                            bytes: 36
+                            line: 2
+                            character: 2
+                          token_type:
+                            type: Whitespace
+                            characters: "\t"
+                      token:
+                        start_position:
+                          bytes: 36
+                          line: 2
+                          character: 2
+                        end_position:
+                          bytes: 40
+                          line: 2
+                          character: 6
+                        token_type:
+                          type: Identifier
+                          identifier: call
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        AnonymousCall:
+                          Parentheses:
+                            parentheses:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 40
+                                      line: 2
+                                      character: 6
+                                    end_position:
+                                      bytes: 41
+                                      line: 2
+                                      character: 7
+                                    token_type:
+                                      type: Symbol
+                                      symbol: (
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 53
+                                      line: 2
+                                      character: 19
+                                    end_position:
+                                      bytes: 54
+                                      line: 2
+                                      character: 20
+                                    token_type:
+                                      type: Symbol
+                                      symbol: )
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 54
+                                        line: 2
+                                        character: 20
+                                      end_position:
+                                        bytes: 55
+                                        line: 2
+                                        character: 20
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\n"
+                            arguments:
+                              pairs:
+                                - Punctuated:
+                                    - Var:
+                                        Name:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 41
+                                              line: 2
+                                              character: 7
+                                            end_position:
+                                              bytes: 46
+                                              line: 2
+                                              character: 12
+                                            token_type:
+                                              type: Identifier
+                                              identifier: index
+                                          trailing_trivia: []
+                                    - leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 46
+                                          line: 2
+                                          character: 12
+                                        end_position:
+                                          bytes: 47
+                                          line: 2
+                                          character: 13
+                                        token_type:
+                                          type: Symbol
+                                          symbol: ","
+                                      trailing_trivia:
+                                        - start_position:
+                                            bytes: 47
+                                            line: 2
+                                            character: 13
+                                          end_position:
+                                            bytes: 48
+                                            line: 2
+                                            character: 14
+                                          token_type:
+                                            type: Whitespace
+                                            characters: " "
+                                - End:
+                                    Var:
+                                      Name:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 48
+                                            line: 2
+                                            character: 14
+                                          end_position:
+                                            bytes: 53
+                                            line: 2
+                                            character: 19
+                                          token_type:
+                                            type: Identifier
+                                            identifier: value
+                                        trailing_trivia: []
+              - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 55
+              line: 3
+              character: 1
+            end_position:
+              bytes: 58
+              line: 3
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2838ff25df97b1b8b6d9c5c3e88e3851f8d0c542
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-1/source.lua
@@ -0,0 +1,3 @@
+for index, value in pairs(list) do
+	call(index, value)
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..28a515bace1226528ebf9a93de7acbc1c0cf3eb3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-1/tokens.snap
@@ -0,0 +1,303 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/generic-for-loop-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: index
+- 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: value
+- 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: 19
+    line: 1
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: in
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 25
+    line: 1
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: pairs
+- 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: 30
+    line: 1
+    character: 31
+  token_type:
+    type: Identifier
+    identifier: list
+- start_position:
+    bytes: 30
+    line: 1
+    character: 31
+  end_position:
+    bytes: 31
+    line: 1
+    character: 32
+  token_type:
+    type: Symbol
+    symbol: )
+- 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: do
+- start_position:
+    bytes: 34
+    line: 1
+    character: 35
+  end_position:
+    bytes: 35
+    line: 1
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 35
+    line: 2
+    character: 1
+  end_position:
+    bytes: 36
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 36
+    line: 2
+    character: 2
+  end_position:
+    bytes: 40
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 40
+    line: 2
+    character: 6
+  end_position:
+    bytes: 41
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 41
+    line: 2
+    character: 7
+  end_position:
+    bytes: 46
+    line: 2
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: index
+- start_position:
+    bytes: 46
+    line: 2
+    character: 12
+  end_position:
+    bytes: 47
+    line: 2
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 47
+    line: 2
+    character: 13
+  end_position:
+    bytes: 48
+    line: 2
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 48
+    line: 2
+    character: 14
+  end_position:
+    bytes: 53
+    line: 2
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: value
+- start_position:
+    bytes: 53
+    line: 2
+    character: 19
+  end_position:
+    bytes: 54
+    line: 2
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 54
+    line: 2
+    character: 20
+  end_position:
+    bytes: 55
+    line: 2
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 55
+    line: 3
+    character: 1
+  end_position:
+    bytes: 58
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 58
+    line: 3
+    character: 4
+  end_position:
+    bytes: 58
+    line: 3
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5f58a2c809aa9f3006134b24335d3cf0734a803e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-2/ast.snap
@@ -0,0 +1,380 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/generic-for-loop-2
+---
+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:
+            - Punctuated:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 4
+                      line: 1
+                      character: 5
+                    end_position:
+                      bytes: 9
+                      line: 1
+                      character: 10
+                    token_type:
+                      type: Identifier
+                      identifier: index
+                  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:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 11
+                    line: 1
+                    character: 12
+                  end_position:
+                    bytes: 16
+                    line: 1
+                    character: 17
+                  token_type:
+                    type: Identifier
+                    identifier: value
+                trailing_trivia:
+                  - start_position:
+                      bytes: 16
+                      line: 1
+                      character: 17
+                    end_position:
+                      bytes: 17
+                      line: 1
+                      character: 18
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        in_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 17
+              line: 1
+              character: 18
+            end_position:
+              bytes: 19
+              line: 1
+              character: 20
+            token_type:
+              type: Symbol
+              symbol: in
+          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:
+            - Punctuated:
+                - Var:
+                    Name:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 20
+                          line: 1
+                          character: 21
+                        end_position:
+                          bytes: 24
+                          line: 1
+                          character: 25
+                        token_type:
+                          type: Identifier
+                          identifier: next
+                      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: 27
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - 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:
+                      - start_position:
+                          bytes: 30
+                          line: 1
+                          character: 31
+                        end_position:
+                          bytes: 31
+                          line: 1
+                          character: 32
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+        do_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 31
+              line: 1
+              character: 32
+            end_position:
+              bytes: 33
+              line: 1
+              character: 34
+            token_type:
+              type: Symbol
+              symbol: do
+          trailing_trivia:
+            - start_position:
+                bytes: 33
+                line: 1
+                character: 34
+              end_position:
+                bytes: 34
+                line: 1
+                character: 34
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        block:
+          stmts:
+            - - FunctionCall:
+                  prefix:
+                    Name:
+                      leading_trivia:
+                        - start_position:
+                            bytes: 34
+                            line: 2
+                            character: 1
+                          end_position:
+                            bytes: 35
+                            line: 2
+                            character: 2
+                          token_type:
+                            type: Whitespace
+                            characters: "\t"
+                      token:
+                        start_position:
+                          bytes: 35
+                          line: 2
+                          character: 2
+                        end_position:
+                          bytes: 39
+                          line: 2
+                          character: 6
+                        token_type:
+                          type: Identifier
+                          identifier: call
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        AnonymousCall:
+                          Parentheses:
+                            parentheses:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 39
+                                      line: 2
+                                      character: 6
+                                    end_position:
+                                      bytes: 40
+                                      line: 2
+                                      character: 7
+                                    token_type:
+                                      type: Symbol
+                                      symbol: (
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 52
+                                      line: 2
+                                      character: 19
+                                    end_position:
+                                      bytes: 53
+                                      line: 2
+                                      character: 20
+                                    token_type:
+                                      type: Symbol
+                                      symbol: )
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 53
+                                        line: 2
+                                        character: 20
+                                      end_position:
+                                        bytes: 54
+                                        line: 2
+                                        character: 20
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\n"
+                            arguments:
+                              pairs:
+                                - Punctuated:
+                                    - Var:
+                                        Name:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 40
+                                              line: 2
+                                              character: 7
+                                            end_position:
+                                              bytes: 45
+                                              line: 2
+                                              character: 12
+                                            token_type:
+                                              type: Identifier
+                                              identifier: index
+                                          trailing_trivia: []
+                                    - leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 45
+                                          line: 2
+                                          character: 12
+                                        end_position:
+                                          bytes: 46
+                                          line: 2
+                                          character: 13
+                                        token_type:
+                                          type: Symbol
+                                          symbol: ","
+                                      trailing_trivia:
+                                        - start_position:
+                                            bytes: 46
+                                            line: 2
+                                            character: 13
+                                          end_position:
+                                            bytes: 47
+                                            line: 2
+                                            character: 14
+                                          token_type:
+                                            type: Whitespace
+                                            characters: " "
+                                - End:
+                                    Var:
+                                      Name:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 47
+                                            line: 2
+                                            character: 14
+                                          end_position:
+                                            bytes: 52
+                                            line: 2
+                                            character: 19
+                                          token_type:
+                                            type: Identifier
+                                            identifier: value
+                                        trailing_trivia: []
+              - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 54
+              line: 3
+              character: 1
+            end_position:
+              bytes: 57
+              line: 3
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2ddbbb6a02921f691ca17e9ec948a499005895d9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-2/source.lua
@@ -0,0 +1,3 @@
+for index, value in next, list do
+	call(index, value)
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9e07f1b1437586c592bc6f0d492da30d95941b76
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/generic-for-loop-2/tokens.snap
@@ -0,0 +1,303 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/generic-for-loop-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: index
+- 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: value
+- 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: 19
+    line: 1
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: in
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 24
+    line: 1
+    character: 25
+  token_type:
+    type: Identifier
+    identifier: next
+- 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: 30
+    line: 1
+    character: 31
+  token_type:
+    type: Identifier
+    identifier: list
+- start_position:
+    bytes: 30
+    line: 1
+    character: 31
+  end_position:
+    bytes: 31
+    line: 1
+    character: 32
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 31
+    line: 1
+    character: 32
+  end_position:
+    bytes: 33
+    line: 1
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: do
+- 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: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 35
+    line: 2
+    character: 2
+  end_position:
+    bytes: 39
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 39
+    line: 2
+    character: 6
+  end_position:
+    bytes: 40
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 40
+    line: 2
+    character: 7
+  end_position:
+    bytes: 45
+    line: 2
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: index
+- start_position:
+    bytes: 45
+    line: 2
+    character: 12
+  end_position:
+    bytes: 46
+    line: 2
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 46
+    line: 2
+    character: 13
+  end_position:
+    bytes: 47
+    line: 2
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 47
+    line: 2
+    character: 14
+  end_position:
+    bytes: 52
+    line: 2
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: value
+- start_position:
+    bytes: 52
+    line: 2
+    character: 19
+  end_position:
+    bytes: 53
+    line: 2
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 53
+    line: 2
+    character: 20
+  end_position:
+    bytes: 54
+    line: 2
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 54
+    line: 3
+    character: 1
+  end_position:
+    bytes: 57
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 57
+    line: 3
+    character: 4
+  end_position:
+    bytes: 57
+    line: 3
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/goto-as-identifier/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/goto-as-identifier/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..59278e6044173812e88588dc5bed1ba54abae926
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/goto-as-identifier/ast.snap
@@ -0,0 +1,133 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/goto-as-identifier
+---
+stmts:
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia:
+              - start_position:
+                  bytes: 0
+                  line: 1
+                  character: 1
+                end_position:
+                  bytes: 48
+                  line: 1
+                  character: 49
+                token_type:
+                  type: SingleLineComment
+                  comment: " goto as an identifier is permitted in lua 5.1"
+              - start_position:
+                  bytes: 48
+                  line: 1
+                  character: 49
+                end_position:
+                  bytes: 49
+                  line: 1
+                  character: 49
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+            token:
+              start_position:
+                bytes: 49
+                line: 2
+                character: 1
+              end_position:
+                bytes: 53
+                line: 2
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: self
+            trailing_trivia: []
+        suffixes:
+          - Index:
+              Dot:
+                dot:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 53
+                      line: 2
+                      character: 5
+                    end_position:
+                      bytes: 54
+                      line: 2
+                      character: 6
+                    token_type:
+                      type: Symbol
+                      symbol: "."
+                  trailing_trivia: []
+                name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 54
+                      line: 2
+                      character: 6
+                    end_position:
+                      bytes: 58
+                      line: 2
+                      character: 10
+                    token_type:
+                      type: Identifier
+                      identifier: goto
+                  trailing_trivia: []
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 58
+                            line: 2
+                            character: 10
+                          end_position:
+                            bytes: 59
+                            line: 2
+                            character: 11
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 64
+                            line: 2
+                            character: 16
+                          end_position:
+                            bytes: 65
+                            line: 2
+                            character: 17
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia: []
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 59
+                                line: 2
+                                character: 11
+                              end_position:
+                                bytes: 64
+                                line: 2
+                                character: 16
+                              token_type:
+                                type: StringLiteral
+                                literal: foo
+                                quote_type: Double
+                            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/goto-as-identifier/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/goto-as-identifier/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..4a6afecf5b602012e68e4fdbd72340eca7334f1e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/goto-as-identifier/source.lua
@@ -0,0 +1,2 @@
+-- goto as an identifier is permitted in lua 5.1
+self.goto("foo")
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/goto-as-identifier/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/goto-as-identifier/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..793591ea2a192dba63cc58cf45d493afbb39c1fb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/goto-as-identifier/tokens.snap
@@ -0,0 +1,105 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 48
+    line: 1
+    character: 49
+  token_type:
+    type: SingleLineComment
+    comment: " goto as an identifier is permitted in lua 5.1"
+- start_position:
+    bytes: 48
+    line: 1
+    character: 49
+  end_position:
+    bytes: 49
+    line: 1
+    character: 49
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 49
+    line: 2
+    character: 1
+  end_position:
+    bytes: 53
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: self
+- start_position:
+    bytes: 53
+    line: 2
+    character: 5
+  end_position:
+    bytes: 54
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 54
+    line: 2
+    character: 6
+  end_position:
+    bytes: 58
+    line: 2
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: goto
+- start_position:
+    bytes: 58
+    line: 2
+    character: 10
+  end_position:
+    bytes: 59
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 59
+    line: 2
+    character: 11
+  end_position:
+    bytes: 64
+    line: 2
+    character: 16
+  token_type:
+    type: StringLiteral
+    literal: foo
+    quote_type: Double
+- start_position:
+    bytes: 64
+    line: 2
+    character: 16
+  end_position:
+    bytes: 65
+    line: 2
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 65
+    line: 2
+    character: 17
+  end_position:
+    bytes: 65
+    line: 2
+    character: 17
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/gt-lt/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/gt-lt/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c93c7d18aef1473d521c16e5ec7a2b4c7ceafd59
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/gt-lt/ast.snap
@@ -0,0 +1,684 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/gt-lt
+---
+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: 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"
+                  arguments:
+                    pairs:
+                      - End:
+                          BinaryOperator:
+                            lhs:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 5
+                                    line: 1
+                                    character: 6
+                                  end_position:
+                                    bytes: 6
+                                    line: 1
+                                    character: 7
+                                  token_type:
+                                    type: Number
+                                    text: "1"
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 6
+                                      line: 1
+                                      character: 7
+                                    end_position:
+                                      bytes: 7
+                                      line: 1
+                                      character: 8
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                            binop:
+                              LessThan:
+                                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: " "
+                            rhs:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 9
+                                    line: 1
+                                    character: 10
+                                  end_position:
+                                    bytes: 10
+                                    line: 1
+                                    character: 11
+                                  token_type:
+                                    type: Number
+                                    text: "2"
+                                trailing_trivia: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 12
+                line: 2
+                character: 1
+              end_position:
+                bytes: 16
+                line: 2
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 16
+                            line: 2
+                            character: 5
+                          end_position:
+                            bytes: 17
+                            line: 2
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 23
+                            line: 2
+                            character: 12
+                          end_position:
+                            bytes: 24
+                            line: 2
+                            character: 13
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 24
+                              line: 2
+                              character: 13
+                            end_position:
+                              bytes: 25
+                              line: 2
+                              character: 13
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs:
+                      - End:
+                          BinaryOperator:
+                            lhs:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 17
+                                    line: 2
+                                    character: 6
+                                  end_position:
+                                    bytes: 18
+                                    line: 2
+                                    character: 7
+                                  token_type:
+                                    type: Number
+                                    text: "1"
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 18
+                                      line: 2
+                                      character: 7
+                                    end_position:
+                                      bytes: 19
+                                      line: 2
+                                      character: 8
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                            binop:
+                              LessThanEqual:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 19
+                                    line: 2
+                                    character: 8
+                                  end_position:
+                                    bytes: 21
+                                    line: 2
+                                    character: 10
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "<="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 21
+                                      line: 2
+                                      character: 10
+                                    end_position:
+                                      bytes: 22
+                                      line: 2
+                                      character: 11
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                            rhs:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 22
+                                    line: 2
+                                    character: 11
+                                  end_position:
+                                    bytes: 23
+                                    line: 2
+                                    character: 12
+                                  token_type:
+                                    type: Number
+                                    text: "2"
+                                trailing_trivia: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 25
+                line: 3
+                character: 1
+              end_position:
+                bytes: 29
+                line: 3
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 29
+                            line: 3
+                            character: 5
+                          end_position:
+                            bytes: 30
+                            line: 3
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 35
+                            line: 3
+                            character: 11
+                          end_position:
+                            bytes: 36
+                            line: 3
+                            character: 12
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 36
+                              line: 3
+                              character: 12
+                            end_position:
+                              bytes: 37
+                              line: 3
+                              character: 12
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs:
+                      - End:
+                          BinaryOperator:
+                            lhs:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 30
+                                    line: 3
+                                    character: 6
+                                  end_position:
+                                    bytes: 31
+                                    line: 3
+                                    character: 7
+                                  token_type:
+                                    type: Number
+                                    text: "2"
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 31
+                                      line: 3
+                                      character: 7
+                                    end_position:
+                                      bytes: 32
+                                      line: 3
+                                      character: 8
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                            binop:
+                              GreaterThan:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 32
+                                    line: 3
+                                    character: 8
+                                  end_position:
+                                    bytes: 33
+                                    line: 3
+                                    character: 9
+                                  token_type:
+                                    type: Symbol
+                                    symbol: ">"
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 33
+                                      line: 3
+                                      character: 9
+                                    end_position:
+                                      bytes: 34
+                                      line: 3
+                                      character: 10
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                            rhs:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 34
+                                    line: 3
+                                    character: 10
+                                  end_position:
+                                    bytes: 35
+                                    line: 3
+                                    character: 11
+                                  token_type:
+                                    type: Number
+                                    text: "1"
+                                trailing_trivia: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 37
+                line: 4
+                character: 1
+              end_position:
+                bytes: 41
+                line: 4
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 41
+                            line: 4
+                            character: 5
+                          end_position:
+                            bytes: 42
+                            line: 4
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 48
+                            line: 4
+                            character: 12
+                          end_position:
+                            bytes: 49
+                            line: 4
+                            character: 13
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 49
+                              line: 4
+                              character: 13
+                            end_position:
+                              bytes: 50
+                              line: 4
+                              character: 13
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs:
+                      - End:
+                          BinaryOperator:
+                            lhs:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 42
+                                    line: 4
+                                    character: 6
+                                  end_position:
+                                    bytes: 43
+                                    line: 4
+                                    character: 7
+                                  token_type:
+                                    type: Number
+                                    text: "2"
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 43
+                                      line: 4
+                                      character: 7
+                                    end_position:
+                                      bytes: 44
+                                      line: 4
+                                      character: 8
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                            binop:
+                              GreaterThanEqual:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 44
+                                    line: 4
+                                    character: 8
+                                  end_position:
+                                    bytes: 46
+                                    line: 4
+                                    character: 10
+                                  token_type:
+                                    type: Symbol
+                                    symbol: ">="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 46
+                                      line: 4
+                                      character: 10
+                                    end_position:
+                                      bytes: 47
+                                      line: 4
+                                      character: 11
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                            rhs:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 47
+                                    line: 4
+                                    character: 11
+                                  end_position:
+                                    bytes: 48
+                                    line: 4
+                                    character: 12
+                                  token_type:
+                                    type: Number
+                                    text: "1"
+                                trailing_trivia: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 50
+                line: 5
+                character: 1
+              end_position:
+                bytes: 54
+                line: 5
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 54
+                            line: 5
+                            character: 5
+                          end_position:
+                            bytes: 55
+                            line: 5
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 61
+                            line: 5
+                            character: 12
+                          end_position:
+                            bytes: 62
+                            line: 5
+                            character: 13
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia: []
+                  arguments:
+                    pairs:
+                      - End:
+                          BinaryOperator:
+                            lhs:
+                              Var:
+                                Name:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 55
+                                      line: 5
+                                      character: 6
+                                    end_position:
+                                      bytes: 56
+                                      line: 5
+                                      character: 7
+                                    token_type:
+                                      type: Identifier
+                                      identifier: x
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 56
+                                        line: 5
+                                        character: 7
+                                      end_position:
+                                        bytes: 57
+                                        line: 5
+                                        character: 8
+                                      token_type:
+                                        type: Whitespace
+                                        characters: " "
+                            binop:
+                              GreaterThanEqual:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 57
+                                    line: 5
+                                    character: 8
+                                  end_position:
+                                    bytes: 59
+                                    line: 5
+                                    character: 10
+                                  token_type:
+                                    type: Symbol
+                                    symbol: ">="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 59
+                                      line: 5
+                                      character: 10
+                                    end_position:
+                                      bytes: 60
+                                      line: 5
+                                      character: 11
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                            rhs:
+                              Var:
+                                Name:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 60
+                                      line: 5
+                                      character: 11
+                                    end_position:
+                                      bytes: 61
+                                      line: 5
+                                      character: 12
+                                    token_type:
+                                      type: Identifier
+                                      identifier: y
+                                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/gt-lt/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/gt-lt/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..54e1cf52e4a0ea211f53a3cb0a4db37d9126c8e7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/gt-lt/source.lua
@@ -0,0 +1,5 @@
+call(1 < 2)
+call(1 <= 2)
+call(2 > 1)
+call(2 >= 1)
+call(x >= y)
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/gt-lt/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/gt-lt/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..df669f6a1b7db2ad905fc915887f339ea4b979b7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/gt-lt/tokens.snap
@@ -0,0 +1,501 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/gt-lt
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "<"
+- 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: Number
+    text: "2"
+- 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: 16
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 16
+    line: 2
+    character: 5
+  end_position:
+    bytes: 17
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 17
+    line: 2
+    character: 6
+  end_position:
+    bytes: 18
+    line: 2
+    character: 7
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 18
+    line: 2
+    character: 7
+  end_position:
+    bytes: 19
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 19
+    line: 2
+    character: 8
+  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: 23
+    line: 2
+    character: 12
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 23
+    line: 2
+    character: 12
+  end_position:
+    bytes: 24
+    line: 2
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 24
+    line: 2
+    character: 13
+  end_position:
+    bytes: 25
+    line: 2
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 25
+    line: 3
+    character: 1
+  end_position:
+    bytes: 29
+    line: 3
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 29
+    line: 3
+    character: 5
+  end_position:
+    bytes: 30
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 30
+    line: 3
+    character: 6
+  end_position:
+    bytes: 31
+    line: 3
+    character: 7
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 31
+    line: 3
+    character: 7
+  end_position:
+    bytes: 32
+    line: 3
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 32
+    line: 3
+    character: 8
+  end_position:
+    bytes: 33
+    line: 3
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: ">"
+- start_position:
+    bytes: 33
+    line: 3
+    character: 9
+  end_position:
+    bytes: 34
+    line: 3
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 34
+    line: 3
+    character: 10
+  end_position:
+    bytes: 35
+    line: 3
+    character: 11
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 35
+    line: 3
+    character: 11
+  end_position:
+    bytes: 36
+    line: 3
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 36
+    line: 3
+    character: 12
+  end_position:
+    bytes: 37
+    line: 3
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 37
+    line: 4
+    character: 1
+  end_position:
+    bytes: 41
+    line: 4
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 41
+    line: 4
+    character: 5
+  end_position:
+    bytes: 42
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 42
+    line: 4
+    character: 6
+  end_position:
+    bytes: 43
+    line: 4
+    character: 7
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 43
+    line: 4
+    character: 7
+  end_position:
+    bytes: 44
+    line: 4
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 44
+    line: 4
+    character: 8
+  end_position:
+    bytes: 46
+    line: 4
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: ">="
+- start_position:
+    bytes: 46
+    line: 4
+    character: 10
+  end_position:
+    bytes: 47
+    line: 4
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 47
+    line: 4
+    character: 11
+  end_position:
+    bytes: 48
+    line: 4
+    character: 12
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 48
+    line: 4
+    character: 12
+  end_position:
+    bytes: 49
+    line: 4
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 49
+    line: 4
+    character: 13
+  end_position:
+    bytes: 50
+    line: 4
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 50
+    line: 5
+    character: 1
+  end_position:
+    bytes: 54
+    line: 5
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 54
+    line: 5
+    character: 5
+  end_position:
+    bytes: 55
+    line: 5
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 55
+    line: 5
+    character: 6
+  end_position:
+    bytes: 56
+    line: 5
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 56
+    line: 5
+    character: 7
+  end_position:
+    bytes: 57
+    line: 5
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 57
+    line: 5
+    character: 8
+  end_position:
+    bytes: 59
+    line: 5
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: ">="
+- start_position:
+    bytes: 59
+    line: 5
+    character: 10
+  end_position:
+    bytes: 60
+    line: 5
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 60
+    line: 5
+    character: 11
+  end_position:
+    bytes: 61
+    line: 5
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 61
+    line: 5
+    character: 12
+  end_position:
+    bytes: 62
+    line: 5
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 62
+    line: 5
+    character: 13
+  end_position:
+    bytes: 62
+    line: 5
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/if-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1102488e3477cdf9a51327ca6f0c17a54737ad7a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-1/ast.snap
@@ -0,0 +1,186 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/if-1
+---
+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: 15
+                          line: 2
+                          character: 6
+                        token_type:
+                          type: Identifier
+                          identifier: call
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        AnonymousCall:
+                          Parentheses:
+                            parentheses:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 15
+                                      line: 2
+                                      character: 6
+                                    end_position:
+                                      bytes: 16
+                                      line: 2
+                                      character: 7
+                                    token_type:
+                                      type: Symbol
+                                      symbol: (
+                                  trailing_trivia: []
+                                - 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:
+                                    - start_position:
+                                        bytes: 17
+                                        line: 2
+                                        character: 8
+                                      end_position:
+                                        bytes: 18
+                                        line: 2
+                                        character: 8
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\n"
+                            arguments:
+                              pairs: []
+              - ~
+        else_if: ~
+        else_token: ~
+        else: ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 18
+              line: 3
+              character: 1
+            end_position:
+              bytes: 21
+              line: 3
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/if-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..9211c9664417b8cc4d085b38d9a26e604b335b63
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-1/source.lua
@@ -0,0 +1,3 @@
+if x then
+	call()
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/if-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8b7f14767c5ba5847ecade7b4e61412f937deefa
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-1/tokens.snap
@@ -0,0 +1,149 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/if-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: then
+- 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: 11
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 11
+    line: 2
+    character: 2
+  end_position:
+    bytes: 15
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 15
+    line: 2
+    character: 6
+  end_position:
+    bytes: 16
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 16
+    line: 2
+    character: 7
+  end_position:
+    bytes: 17
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 17
+    line: 2
+    character: 8
+  end_position:
+    bytes: 18
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 18
+    line: 3
+    character: 1
+  end_position:
+    bytes: 21
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 21
+    line: 3
+    character: 4
+  end_position:
+    bytes: 21
+    line: 3
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/if-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c11da4fe5bb80246b69886b45c228bec03411f85
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-2/ast.snap
@@ -0,0 +1,288 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/if-2
+---
+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: 14
+                          line: 2
+                          character: 5
+                        token_type:
+                          type: Identifier
+                          identifier: foo
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        AnonymousCall:
+                          Parentheses:
+                            parentheses:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 14
+                                      line: 2
+                                      character: 5
+                                    end_position:
+                                      bytes: 15
+                                      line: 2
+                                      character: 6
+                                    token_type:
+                                      type: Symbol
+                                      symbol: (
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 15
+                                      line: 2
+                                      character: 6
+                                    end_position:
+                                      bytes: 16
+                                      line: 2
+                                      character: 7
+                                    token_type:
+                                      type: Symbol
+                                      symbol: )
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 16
+                                        line: 2
+                                        character: 7
+                                      end_position:
+                                        bytes: 17
+                                        line: 2
+                                        character: 7
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\n"
+                            arguments:
+                              pairs: []
+              - ~
+        else_if: ~
+        else_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 17
+              line: 3
+              character: 1
+            end_position:
+              bytes: 21
+              line: 3
+              character: 5
+            token_type:
+              type: Symbol
+              symbol: else
+          trailing_trivia:
+            - start_position:
+                bytes: 21
+                line: 3
+                character: 5
+              end_position:
+                bytes: 22
+                line: 3
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        else:
+          stmts:
+            - - FunctionCall:
+                  prefix:
+                    Name:
+                      leading_trivia:
+                        - start_position:
+                            bytes: 22
+                            line: 4
+                            character: 1
+                          end_position:
+                            bytes: 23
+                            line: 4
+                            character: 2
+                          token_type:
+                            type: Whitespace
+                            characters: "\t"
+                      token:
+                        start_position:
+                          bytes: 23
+                          line: 4
+                          character: 2
+                        end_position:
+                          bytes: 26
+                          line: 4
+                          character: 5
+                        token_type:
+                          type: Identifier
+                          identifier: bar
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        AnonymousCall:
+                          Parentheses:
+                            parentheses:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 26
+                                      line: 4
+                                      character: 5
+                                    end_position:
+                                      bytes: 27
+                                      line: 4
+                                      character: 6
+                                    token_type:
+                                      type: Symbol
+                                      symbol: (
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 27
+                                      line: 4
+                                      character: 6
+                                    end_position:
+                                      bytes: 28
+                                      line: 4
+                                      character: 7
+                                    token_type:
+                                      type: Symbol
+                                      symbol: )
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 28
+                                        line: 4
+                                        character: 7
+                                      end_position:
+                                        bytes: 29
+                                        line: 4
+                                        character: 7
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\n"
+                            arguments:
+                              pairs: []
+              - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 29
+              line: 5
+              character: 1
+            end_position:
+              bytes: 32
+              line: 5
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/if-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..faf9ce59d2d86ce8971dd30060b2a2ab27039706
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-2/source.lua
@@ -0,0 +1,5 @@
+if x then
+	foo()
+else
+	bar()
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/if-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3824b1b932581dd28886efe70b017494be6514be
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-2/tokens.snap
@@ -0,0 +1,226 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/if-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: then
+- 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: 11
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 11
+    line: 2
+    character: 2
+  end_position:
+    bytes: 14
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 14
+    line: 2
+    character: 5
+  end_position:
+    bytes: 15
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 15
+    line: 2
+    character: 6
+  end_position:
+    bytes: 16
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 16
+    line: 2
+    character: 7
+  end_position:
+    bytes: 17
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 17
+    line: 3
+    character: 1
+  end_position:
+    bytes: 21
+    line: 3
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 21
+    line: 3
+    character: 5
+  end_position:
+    bytes: 22
+    line: 3
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 22
+    line: 4
+    character: 1
+  end_position:
+    bytes: 23
+    line: 4
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 23
+    line: 4
+    character: 2
+  end_position:
+    bytes: 26
+    line: 4
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 26
+    line: 4
+    character: 5
+  end_position:
+    bytes: 27
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 27
+    line: 4
+    character: 6
+  end_position:
+    bytes: 28
+    line: 4
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 28
+    line: 4
+    character: 7
+  end_position:
+    bytes: 29
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 29
+    line: 5
+    character: 1
+  end_position:
+    bytes: 32
+    line: 5
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 32
+    line: 5
+    character: 4
+  end_position:
+    bytes: 32
+    line: 5
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/if-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d439a602c19352968a559ed67222d6aab08a6f53
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-3/ast.snap
@@ -0,0 +1,344 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/if-3
+---
+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: 14
+                          line: 2
+                          character: 5
+                        token_type:
+                          type: Identifier
+                          identifier: foo
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        AnonymousCall:
+                          Parentheses:
+                            parentheses:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 14
+                                      line: 2
+                                      character: 5
+                                    end_position:
+                                      bytes: 15
+                                      line: 2
+                                      character: 6
+                                    token_type:
+                                      type: Symbol
+                                      symbol: (
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 15
+                                      line: 2
+                                      character: 6
+                                    end_position:
+                                      bytes: 16
+                                      line: 2
+                                      character: 7
+                                    token_type:
+                                      type: Symbol
+                                      symbol: )
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 16
+                                        line: 2
+                                        character: 7
+                                      end_position:
+                                        bytes: 17
+                                        line: 2
+                                        character: 7
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\n"
+                            arguments:
+                              pairs: []
+              - ~
+        else_if:
+          - else_if_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 17
+                  line: 3
+                  character: 1
+                end_position:
+                  bytes: 23
+                  line: 3
+                  character: 7
+                token_type:
+                  type: Symbol
+                  symbol: elseif
+              trailing_trivia:
+                - start_position:
+                    bytes: 23
+                    line: 3
+                    character: 7
+                  end_position:
+                    bytes: 24
+                    line: 3
+                    character: 8
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            condition:
+              Var:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 24
+                      line: 3
+                      character: 8
+                    end_position:
+                      bytes: 25
+                      line: 3
+                      character: 9
+                    token_type:
+                      type: Identifier
+                      identifier: y
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 25
+                        line: 3
+                        character: 9
+                      end_position:
+                        bytes: 26
+                        line: 3
+                        character: 10
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            then_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 26
+                  line: 3
+                  character: 10
+                end_position:
+                  bytes: 30
+                  line: 3
+                  character: 14
+                token_type:
+                  type: Symbol
+                  symbol: then
+              trailing_trivia:
+                - start_position:
+                    bytes: 30
+                    line: 3
+                    character: 14
+                  end_position:
+                    bytes: 31
+                    line: 3
+                    character: 14
+                  token_type:
+                    type: Whitespace
+                    characters: "\n"
+            block:
+              stmts:
+                - - FunctionCall:
+                      prefix:
+                        Name:
+                          leading_trivia:
+                            - start_position:
+                                bytes: 31
+                                line: 4
+                                character: 1
+                              end_position:
+                                bytes: 32
+                                line: 4
+                                character: 2
+                              token_type:
+                                type: Whitespace
+                                characters: "\t"
+                          token:
+                            start_position:
+                              bytes: 32
+                              line: 4
+                              character: 2
+                            end_position:
+                              bytes: 35
+                              line: 4
+                              character: 5
+                            token_type:
+                              type: Identifier
+                              identifier: bar
+                          trailing_trivia: []
+                      suffixes:
+                        - Call:
+                            AnonymousCall:
+                              Parentheses:
+                                parentheses:
+                                  tokens:
+                                    - leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 35
+                                          line: 4
+                                          character: 5
+                                        end_position:
+                                          bytes: 36
+                                          line: 4
+                                          character: 6
+                                        token_type:
+                                          type: Symbol
+                                          symbol: (
+                                      trailing_trivia: []
+                                    - leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 36
+                                          line: 4
+                                          character: 6
+                                        end_position:
+                                          bytes: 37
+                                          line: 4
+                                          character: 7
+                                        token_type:
+                                          type: Symbol
+                                          symbol: )
+                                      trailing_trivia:
+                                        - start_position:
+                                            bytes: 37
+                                            line: 4
+                                            character: 7
+                                          end_position:
+                                            bytes: 38
+                                            line: 4
+                                            character: 7
+                                          token_type:
+                                            type: Whitespace
+                                            characters: "\n"
+                                arguments:
+                                  pairs: []
+                  - ~
+        else_token: ~
+        else: ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 38
+              line: 5
+              character: 1
+            end_position:
+              bytes: 41
+              line: 5
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/if-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..6dd9718d23dcc747242d6f639c1837af75378c20
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-3/source.lua
@@ -0,0 +1,5 @@
+if x then
+	foo()
+elseif y then
+	bar()
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/if-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0e16a5d780a5cc57439661f6e7ebec0e258b3970
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-3/tokens.snap
@@ -0,0 +1,270 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/if-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: then
+- 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: 11
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 11
+    line: 2
+    character: 2
+  end_position:
+    bytes: 14
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 14
+    line: 2
+    character: 5
+  end_position:
+    bytes: 15
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 15
+    line: 2
+    character: 6
+  end_position:
+    bytes: 16
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 16
+    line: 2
+    character: 7
+  end_position:
+    bytes: 17
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 17
+    line: 3
+    character: 1
+  end_position:
+    bytes: 23
+    line: 3
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: elseif
+- start_position:
+    bytes: 23
+    line: 3
+    character: 7
+  end_position:
+    bytes: 24
+    line: 3
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 24
+    line: 3
+    character: 8
+  end_position:
+    bytes: 25
+    line: 3
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 25
+    line: 3
+    character: 9
+  end_position:
+    bytes: 26
+    line: 3
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 26
+    line: 3
+    character: 10
+  end_position:
+    bytes: 30
+    line: 3
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 30
+    line: 3
+    character: 14
+  end_position:
+    bytes: 31
+    line: 3
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 31
+    line: 4
+    character: 1
+  end_position:
+    bytes: 32
+    line: 4
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 32
+    line: 4
+    character: 2
+  end_position:
+    bytes: 35
+    line: 4
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 35
+    line: 4
+    character: 5
+  end_position:
+    bytes: 36
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 36
+    line: 4
+    character: 6
+  end_position:
+    bytes: 37
+    line: 4
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 37
+    line: 4
+    character: 7
+  end_position:
+    bytes: 38
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 38
+    line: 5
+    character: 1
+  end_position:
+    bytes: 41
+    line: 5
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 41
+    line: 5
+    character: 4
+  end_position:
+    bytes: 41
+    line: 5
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/if-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8af517ba8db83c2c60104ad236c09ac484a705b0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-4/ast.snap
@@ -0,0 +1,446 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/if-4
+---
+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: 14
+                          line: 2
+                          character: 5
+                        token_type:
+                          type: Identifier
+                          identifier: foo
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        AnonymousCall:
+                          Parentheses:
+                            parentheses:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 14
+                                      line: 2
+                                      character: 5
+                                    end_position:
+                                      bytes: 15
+                                      line: 2
+                                      character: 6
+                                    token_type:
+                                      type: Symbol
+                                      symbol: (
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 15
+                                      line: 2
+                                      character: 6
+                                    end_position:
+                                      bytes: 16
+                                      line: 2
+                                      character: 7
+                                    token_type:
+                                      type: Symbol
+                                      symbol: )
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 16
+                                        line: 2
+                                        character: 7
+                                      end_position:
+                                        bytes: 17
+                                        line: 2
+                                        character: 7
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\n"
+                            arguments:
+                              pairs: []
+              - ~
+        else_if:
+          - else_if_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 17
+                  line: 3
+                  character: 1
+                end_position:
+                  bytes: 23
+                  line: 3
+                  character: 7
+                token_type:
+                  type: Symbol
+                  symbol: elseif
+              trailing_trivia:
+                - start_position:
+                    bytes: 23
+                    line: 3
+                    character: 7
+                  end_position:
+                    bytes: 24
+                    line: 3
+                    character: 8
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            condition:
+              Var:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 24
+                      line: 3
+                      character: 8
+                    end_position:
+                      bytes: 25
+                      line: 3
+                      character: 9
+                    token_type:
+                      type: Identifier
+                      identifier: y
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 25
+                        line: 3
+                        character: 9
+                      end_position:
+                        bytes: 26
+                        line: 3
+                        character: 10
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            then_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 26
+                  line: 3
+                  character: 10
+                end_position:
+                  bytes: 30
+                  line: 3
+                  character: 14
+                token_type:
+                  type: Symbol
+                  symbol: then
+              trailing_trivia:
+                - start_position:
+                    bytes: 30
+                    line: 3
+                    character: 14
+                  end_position:
+                    bytes: 31
+                    line: 3
+                    character: 14
+                  token_type:
+                    type: Whitespace
+                    characters: "\n"
+            block:
+              stmts:
+                - - FunctionCall:
+                      prefix:
+                        Name:
+                          leading_trivia:
+                            - start_position:
+                                bytes: 31
+                                line: 4
+                                character: 1
+                              end_position:
+                                bytes: 32
+                                line: 4
+                                character: 2
+                              token_type:
+                                type: Whitespace
+                                characters: "\t"
+                          token:
+                            start_position:
+                              bytes: 32
+                              line: 4
+                              character: 2
+                            end_position:
+                              bytes: 35
+                              line: 4
+                              character: 5
+                            token_type:
+                              type: Identifier
+                              identifier: bar
+                          trailing_trivia: []
+                      suffixes:
+                        - Call:
+                            AnonymousCall:
+                              Parentheses:
+                                parentheses:
+                                  tokens:
+                                    - leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 35
+                                          line: 4
+                                          character: 5
+                                        end_position:
+                                          bytes: 36
+                                          line: 4
+                                          character: 6
+                                        token_type:
+                                          type: Symbol
+                                          symbol: (
+                                      trailing_trivia: []
+                                    - leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 36
+                                          line: 4
+                                          character: 6
+                                        end_position:
+                                          bytes: 37
+                                          line: 4
+                                          character: 7
+                                        token_type:
+                                          type: Symbol
+                                          symbol: )
+                                      trailing_trivia:
+                                        - start_position:
+                                            bytes: 37
+                                            line: 4
+                                            character: 7
+                                          end_position:
+                                            bytes: 38
+                                            line: 4
+                                            character: 7
+                                          token_type:
+                                            type: Whitespace
+                                            characters: "\n"
+                                arguments:
+                                  pairs: []
+                  - ~
+        else_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 38
+              line: 5
+              character: 1
+            end_position:
+              bytes: 42
+              line: 5
+              character: 5
+            token_type:
+              type: Symbol
+              symbol: else
+          trailing_trivia:
+            - start_position:
+                bytes: 42
+                line: 5
+                character: 5
+              end_position:
+                bytes: 43
+                line: 5
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        else:
+          stmts:
+            - - FunctionCall:
+                  prefix:
+                    Name:
+                      leading_trivia:
+                        - start_position:
+                            bytes: 43
+                            line: 6
+                            character: 1
+                          end_position:
+                            bytes: 44
+                            line: 6
+                            character: 2
+                          token_type:
+                            type: Whitespace
+                            characters: "\t"
+                      token:
+                        start_position:
+                          bytes: 44
+                          line: 6
+                          character: 2
+                        end_position:
+                          bytes: 47
+                          line: 6
+                          character: 5
+                        token_type:
+                          type: Identifier
+                          identifier: baz
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        AnonymousCall:
+                          Parentheses:
+                            parentheses:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 47
+                                      line: 6
+                                      character: 5
+                                    end_position:
+                                      bytes: 48
+                                      line: 6
+                                      character: 6
+                                    token_type:
+                                      type: Symbol
+                                      symbol: (
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 48
+                                      line: 6
+                                      character: 6
+                                    end_position:
+                                      bytes: 49
+                                      line: 6
+                                      character: 7
+                                    token_type:
+                                      type: Symbol
+                                      symbol: )
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 49
+                                        line: 6
+                                        character: 7
+                                      end_position:
+                                        bytes: 50
+                                        line: 6
+                                        character: 7
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\n"
+                            arguments:
+                              pairs: []
+              - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 50
+              line: 7
+              character: 1
+            end_position:
+              bytes: 53
+              line: 7
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/if-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f710ef9a1c0544667a0331f2adc94fcc6a86c539
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-4/source.lua
@@ -0,0 +1,7 @@
+if x then
+	foo()
+elseif y then
+	bar()
+else
+	baz()
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/if-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/if-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..daa96296acaa16eee118c52372ca538b482be865
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/if-4/tokens.snap
@@ -0,0 +1,347 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/if-4
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 3
+    line: 1
+    character: 4
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: then
+- 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: 11
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 11
+    line: 2
+    character: 2
+  end_position:
+    bytes: 14
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 14
+    line: 2
+    character: 5
+  end_position:
+    bytes: 15
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 15
+    line: 2
+    character: 6
+  end_position:
+    bytes: 16
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 16
+    line: 2
+    character: 7
+  end_position:
+    bytes: 17
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 17
+    line: 3
+    character: 1
+  end_position:
+    bytes: 23
+    line: 3
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: elseif
+- start_position:
+    bytes: 23
+    line: 3
+    character: 7
+  end_position:
+    bytes: 24
+    line: 3
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 24
+    line: 3
+    character: 8
+  end_position:
+    bytes: 25
+    line: 3
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 25
+    line: 3
+    character: 9
+  end_position:
+    bytes: 26
+    line: 3
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 26
+    line: 3
+    character: 10
+  end_position:
+    bytes: 30
+    line: 3
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 30
+    line: 3
+    character: 14
+  end_position:
+    bytes: 31
+    line: 3
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 31
+    line: 4
+    character: 1
+  end_position:
+    bytes: 32
+    line: 4
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 32
+    line: 4
+    character: 2
+  end_position:
+    bytes: 35
+    line: 4
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 35
+    line: 4
+    character: 5
+  end_position:
+    bytes: 36
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 36
+    line: 4
+    character: 6
+  end_position:
+    bytes: 37
+    line: 4
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 37
+    line: 4
+    character: 7
+  end_position:
+    bytes: 38
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 38
+    line: 5
+    character: 1
+  end_position:
+    bytes: 42
+    line: 5
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 42
+    line: 5
+    character: 5
+  end_position:
+    bytes: 43
+    line: 5
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 43
+    line: 6
+    character: 1
+  end_position:
+    bytes: 44
+    line: 6
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 44
+    line: 6
+    character: 2
+  end_position:
+    bytes: 47
+    line: 6
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 47
+    line: 6
+    character: 5
+  end_position:
+    bytes: 48
+    line: 6
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 48
+    line: 6
+    character: 6
+  end_position:
+    bytes: 49
+    line: 6
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 49
+    line: 6
+    character: 7
+  end_position:
+    bytes: 50
+    line: 6
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 50
+    line: 7
+    character: 1
+  end_position:
+    bytes: 53
+    line: 7
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 53
+    line: 7
+    character: 4
+  end_position:
+    bytes: 53
+    line: 7
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/index-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/index-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..80575bcd02dde824d124c356bc8e0cfd6765a4ab
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/index-1/ast.snap
@@ -0,0 +1,176 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/index-1
+---
+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:
+                Var:
+                  Expression:
+                    prefix:
+                      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: a
+                        trailing_trivia: []
+                    suffixes:
+                      - Index:
+                          Dot:
+                            dot:
+                              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: 13
+                                  line: 1
+                                  character: 14
+                                token_type:
+                                  type: Identifier
+                                  identifier: b
+                              trailing_trivia: []
+                      - Index:
+                          Dot:
+                            dot:
+                              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: []
+                            name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 14
+                                  line: 1
+                                  character: 15
+                                end_position:
+                                  bytes: 15
+                                  line: 1
+                                  character: 16
+                                token_type:
+                                  type: Identifier
+                                  identifier: c
+                              trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/index-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/index-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..81c84820ca1cf81fd4f71ac4012b070f0ce945de
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/index-1/source.lua
@@ -0,0 +1 @@
+local x = a.b.c
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/index-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/index-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e077e506ae42f3f236efbe82cb2fafa1fb8a0499
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/index-1/tokens.snap
@@ -0,0 +1,138 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/index-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: 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: Identifier
+    identifier: a
+- 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: Identifier
+    identifier: b
+- 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: Identifier
+    identifier: c
+- start_position:
+    bytes: 15
+    line: 1
+    character: 16
+  end_position:
+    bytes: 15
+    line: 1
+    character: 16
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/index-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/index-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ec946cc34f20ee79ef25ddafdaadec5872070ae5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/index-2/ast.snap
@@ -0,0 +1,196 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/index-2
+---
+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:
+                Var:
+                  Expression:
+                    prefix:
+                      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: call
+                        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: 18
+                                        line: 1
+                                        character: 19
+                                      end_position:
+                                        bytes: 19
+                                        line: 1
+                                        character: 20
+                                      token_type:
+                                        type: Symbol
+                                        symbol: )
+                                    trailing_trivia: []
+                              arguments:
+                                pairs:
+                                  - End:
+                                      String:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 15
+                                            line: 1
+                                            character: 16
+                                          end_position:
+                                            bytes: 18
+                                            line: 1
+                                            character: 19
+                                          token_type:
+                                            type: StringLiteral
+                                            literal: a
+                                            quote_type: Double
+                                        trailing_trivia: []
+                      - Index:
+                          Dot:
+                            dot:
+                              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: []
+                            name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 20
+                                  line: 1
+                                  character: 21
+                                end_position:
+                                  bytes: 21
+                                  line: 1
+                                  character: 22
+                                token_type:
+                                  type: Identifier
+                                  identifier: b
+                              trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/index-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/index-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..1db46c3ba797399b80b98da9b29b6465a80b9ff4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/index-2/source.lua
@@ -0,0 +1 @@
+local x = call("a").b
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/index-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/index-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..fc7c3722a8db16be5ad12904ff388ab4bb90f461
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/index-2/tokens.snap
@@ -0,0 +1,150 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/index-2
+
+---
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: call
+- 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: 18
+    line: 1
+    character: 19
+  token_type:
+    type: StringLiteral
+    literal: a
+    quote_type: Double
+- 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: Symbol
+    symbol: "."
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 21
+    line: 1
+    character: 22
+  end_position:
+    bytes: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8c25f01a6457e25836701738f8756adaed37aea6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-1/ast.snap
@@ -0,0 +1,56 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/local-assignment-1
+
+---
+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: []
+        equal_token: ~
+        expr_list:
+          pairs: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..da0c326a0e960916b67031a1f397e6f00e685f76
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-1/source.lua
@@ -0,0 +1 @@
+local x
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..770c65511db99e60fa407ea2a528527c0faf2e8d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-1/tokens.snap
@@ -0,0 +1,50 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/local-assignment-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: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..fadcf3e2aa4ff1690a92ca0fa901661ae3147d09
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-2/ast.snap
@@ -0,0 +1,108 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/local-assignment-2
+---
+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: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..aa28c09f74d7dd7b5dd57bb5919c2c335043b776
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-2/source.lua
@@ -0,0 +1 @@
+local x = 1
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7f0e22c0b0a94e2684f8ab2a86cfba5c2eab2486
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-2/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/local-assignment-2
+
+---
+- 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: Number
+    text: "1"
+- start_position:
+    bytes: 11
+    line: 1
+    character: 12
+  end_position:
+    bytes: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9f61423cb44bfede37fe7ce246a30e5da8dc4ce9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-3/ast.snap
@@ -0,0 +1,573 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/local-assignment-3
+---
+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:
+            - Punctuated:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 6
+                      line: 1
+                      character: 7
+                    end_position:
+                      bytes: 7
+                      line: 1
+                      character: 8
+                    token_type:
+                      type: Identifier
+                      identifier: a
+                  trailing_trivia: []
+                - 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: " "
+            - 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: b
+                trailing_trivia:
+                  - start_position:
+                      bytes: 10
+                      line: 1
+                      character: 11
+                    end_position:
+                      bytes: 11
+                      line: 1
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        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: " "
+        expr_list:
+          pairs:
+            - Punctuated:
+                - Number:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 13
+                        line: 1
+                        character: 14
+                      end_position:
+                        bytes: 14
+                        line: 1
+                        character: 15
+                      token_type:
+                        type: Number
+                        text: "1"
+                    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: " "
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 16
+                      line: 1
+                      character: 17
+                    end_position:
+                      bytes: 17
+                      line: 1
+                      character: 18
+                    token_type:
+                      type: Number
+                      text: "2"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 17
+                        line: 1
+                        character: 18
+                      end_position:
+                        bytes: 18
+                        line: 1
+                        character: 18
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 18
+              line: 2
+              character: 1
+            end_position:
+              bytes: 23
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 23
+                line: 2
+                character: 6
+              end_position:
+                bytes: 24
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - Punctuated:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 24
+                      line: 2
+                      character: 7
+                    end_position:
+                      bytes: 25
+                      line: 2
+                      character: 8
+                    token_type:
+                      type: Identifier
+                      identifier: c
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 25
+                      line: 2
+                      character: 8
+                    end_position:
+                      bytes: 26
+                      line: 2
+                      character: 9
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 26
+                        line: 2
+                        character: 9
+                      end_position:
+                        bytes: 27
+                        line: 2
+                        character: 10
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 27
+                    line: 2
+                    character: 10
+                  end_position:
+                    bytes: 28
+                    line: 2
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: d
+                trailing_trivia:
+                  - start_position:
+                      bytes: 28
+                      line: 2
+                      character: 11
+                    end_position:
+                      bytes: 29
+                      line: 2
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 29
+              line: 2
+              character: 12
+            end_position:
+              bytes: 30
+              line: 2
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 30
+                line: 2
+                character: 13
+              end_position:
+                bytes: 31
+                line: 2
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - Punctuated:
+                - Number:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 31
+                        line: 2
+                        character: 14
+                      end_position:
+                        bytes: 32
+                        line: 2
+                        character: 15
+                      token_type:
+                        type: Number
+                        text: "3"
+                    trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 32
+                      line: 2
+                      character: 15
+                    end_position:
+                      bytes: 33
+                      line: 2
+                      character: 16
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 33
+                        line: 2
+                        character: 16
+                      end_position:
+                        bytes: 34
+                        line: 2
+                        character: 17
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 34
+                      line: 2
+                      character: 17
+                    end_position:
+                      bytes: 35
+                      line: 2
+                      character: 18
+                    token_type:
+                      type: Number
+                      text: "4"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 35
+                        line: 2
+                        character: 18
+                      end_position:
+                        bytes: 36
+                        line: 2
+                        character: 18
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 36
+              line: 3
+              character: 1
+            end_position:
+              bytes: 41
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 41
+                line: 3
+                character: 6
+              end_position:
+                bytes: 42
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - Punctuated:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 42
+                      line: 3
+                      character: 7
+                    end_position:
+                      bytes: 43
+                      line: 3
+                      character: 8
+                    token_type:
+                      type: Identifier
+                      identifier: e
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 43
+                      line: 3
+                      character: 8
+                    end_position:
+                      bytes: 44
+                      line: 3
+                      character: 9
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 44
+                        line: 3
+                        character: 9
+                      end_position:
+                        bytes: 45
+                        line: 3
+                        character: 10
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 45
+                    line: 3
+                    character: 10
+                  end_position:
+                    bytes: 46
+                    line: 3
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: f
+                trailing_trivia:
+                  - start_position:
+                      bytes: 46
+                      line: 3
+                      character: 11
+                    end_position:
+                      bytes: 47
+                      line: 3
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 47
+              line: 3
+              character: 12
+            end_position:
+              bytes: 48
+              line: 3
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 48
+                line: 3
+                character: 13
+              end_position:
+                bytes: 49
+                line: 3
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - Punctuated:
+                - Number:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 49
+                        line: 3
+                        character: 14
+                      end_position:
+                        bytes: 50
+                        line: 3
+                        character: 15
+                      token_type:
+                        type: Number
+                        text: "5"
+                    trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 50
+                      line: 3
+                      character: 15
+                    end_position:
+                      bytes: 51
+                      line: 3
+                      character: 16
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 51
+                        line: 3
+                        character: 16
+                      end_position:
+                        bytes: 52
+                        line: 3
+                        character: 17
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 52
+                      line: 3
+                      character: 17
+                    end_position:
+                      bytes: 53
+                      line: 3
+                      character: 18
+                    token_type:
+                      type: Number
+                      text: "6"
+                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..74c0ed4795ba31bb1294e44130e068acbf68da2a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-3/source.lua
@@ -0,0 +1,3 @@
+local a, b = 1, 2
+local c, d = 3, 4
+local e, f = 5, 6
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1ebb9f19a83211458031ada711587a2c24bff35d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-3/tokens.snap
@@ -0,0 +1,468 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/local-assignment-3
+
+---
+- 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: a
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: ","
+- 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: Identifier
+    identifier: b
+- 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: Number
+    text: "1"
+- 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: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 17
+    line: 1
+    character: 18
+  end_position:
+    bytes: 18
+    line: 1
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 18
+    line: 2
+    character: 1
+  end_position:
+    bytes: 23
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 23
+    line: 2
+    character: 6
+  end_position:
+    bytes: 24
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 24
+    line: 2
+    character: 7
+  end_position:
+    bytes: 25
+    line: 2
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: c
+- start_position:
+    bytes: 25
+    line: 2
+    character: 8
+  end_position:
+    bytes: 26
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 26
+    line: 2
+    character: 9
+  end_position:
+    bytes: 27
+    line: 2
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 27
+    line: 2
+    character: 10
+  end_position:
+    bytes: 28
+    line: 2
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: d
+- start_position:
+    bytes: 28
+    line: 2
+    character: 11
+  end_position:
+    bytes: 29
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 29
+    line: 2
+    character: 12
+  end_position:
+    bytes: 30
+    line: 2
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 30
+    line: 2
+    character: 13
+  end_position:
+    bytes: 31
+    line: 2
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 31
+    line: 2
+    character: 14
+  end_position:
+    bytes: 32
+    line: 2
+    character: 15
+  token_type:
+    type: Number
+    text: "3"
+- start_position:
+    bytes: 32
+    line: 2
+    character: 15
+  end_position:
+    bytes: 33
+    line: 2
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 33
+    line: 2
+    character: 16
+  end_position:
+    bytes: 34
+    line: 2
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 34
+    line: 2
+    character: 17
+  end_position:
+    bytes: 35
+    line: 2
+    character: 18
+  token_type:
+    type: Number
+    text: "4"
+- start_position:
+    bytes: 35
+    line: 2
+    character: 18
+  end_position:
+    bytes: 36
+    line: 2
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 36
+    line: 3
+    character: 1
+  end_position:
+    bytes: 41
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 41
+    line: 3
+    character: 6
+  end_position:
+    bytes: 42
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 42
+    line: 3
+    character: 7
+  end_position:
+    bytes: 43
+    line: 3
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: e
+- start_position:
+    bytes: 43
+    line: 3
+    character: 8
+  end_position:
+    bytes: 44
+    line: 3
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 44
+    line: 3
+    character: 9
+  end_position:
+    bytes: 45
+    line: 3
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 45
+    line: 3
+    character: 10
+  end_position:
+    bytes: 46
+    line: 3
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: f
+- start_position:
+    bytes: 46
+    line: 3
+    character: 11
+  end_position:
+    bytes: 47
+    line: 3
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 47
+    line: 3
+    character: 12
+  end_position:
+    bytes: 48
+    line: 3
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 48
+    line: 3
+    character: 13
+  end_position:
+    bytes: 49
+    line: 3
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 49
+    line: 3
+    character: 14
+  end_position:
+    bytes: 50
+    line: 3
+    character: 15
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 50
+    line: 3
+    character: 15
+  end_position:
+    bytes: 51
+    line: 3
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 51
+    line: 3
+    character: 16
+  end_position:
+    bytes: 52
+    line: 3
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 52
+    line: 3
+    character: 17
+  end_position:
+    bytes: 53
+    line: 3
+    character: 18
+  token_type:
+    type: Number
+    text: "6"
+- start_position:
+    bytes: 53
+    line: 3
+    character: 18
+  end_position:
+    bytes: 53
+    line: 3
+    character: 18
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..90c44c12c4cecc80164744985bdc808a6f147f6b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-4/ast.snap
@@ -0,0 +1,96 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/local-assignment-4
+
+---
+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:
+            - Punctuated:
+                - 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: []
+                - 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: " "
+            - 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: y
+                trailing_trivia: []
+        equal_token: ~
+        expr_list:
+          pairs: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..43ae25449dce13558c423eae60ce54300c96c47d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-4/source.lua
@@ -0,0 +1 @@
+local x, y
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1748c54146afadf7d52fa54feb3732e3a1f0fe44
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-4/tokens.snap
@@ -0,0 +1,83 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/local-assignment-4
+
+---
+- 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: Symbol
+    symbol: ","
+- 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: Identifier
+    identifier: y
+- start_position:
+    bytes: 10
+    line: 1
+    character: 11
+  end_position:
+    bytes: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0e5be5214a305dd608147e9f3e601f3a1cc9d8ad
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-5/ast.snap
@@ -0,0 +1,252 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/local-assignment-5
+---
+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:
+                    - start_position:
+                        bytes: 11
+                        line: 1
+                        character: 12
+                      end_position:
+                        bytes: 12
+                        line: 1
+                        character: 12
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 12
+                line: 2
+                character: 1
+              end_position:
+                bytes: 29
+                line: 2
+                character: 18
+              token_type:
+                type: SingleLineComment
+                comment: " Then a comment"
+            - start_position:
+                bytes: 29
+                line: 2
+                character: 18
+              end_position:
+                bytes: 30
+                line: 2
+                character: 18
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 30
+              line: 3
+              character: 1
+            end_position:
+              bytes: 35
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 35
+                line: 3
+                character: 6
+              end_position:
+                bytes: 36
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 36
+                    line: 3
+                    character: 7
+                  end_position:
+                    bytes: 37
+                    line: 3
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: y
+                trailing_trivia:
+                  - start_position:
+                      bytes: 37
+                      line: 3
+                      character: 8
+                    end_position:
+                      bytes: 38
+                      line: 3
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 38
+              line: 3
+              character: 9
+            end_position:
+              bytes: 39
+              line: 3
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 39
+                line: 3
+                character: 10
+              end_position:
+                bytes: 40
+                line: 3
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 40
+                      line: 3
+                      character: 11
+                    end_position:
+                      bytes: 41
+                      line: 3
+                      character: 12
+                    token_type:
+                      type: Number
+                      text: "1"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 41
+                        line: 3
+                        character: 12
+                      end_position:
+                        bytes: 42
+                        line: 3
+                        character: 12
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..53d943cc7295f3e11bca6c5ab2875c4b41722b37
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-5/source.lua
@@ -0,0 +1,3 @@
+local x = 1
+-- Then a comment
+local y = 1
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c74b7be604e1ba80f449c1024484abff689fe725
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-assignment-5/tokens.snap
@@ -0,0 +1,215 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/local-assignment-5
+
+---
+- 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: Number
+    text: "1"
+- 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: 29
+    line: 2
+    character: 18
+  token_type:
+    type: SingleLineComment
+    comment: " Then a comment"
+- start_position:
+    bytes: 29
+    line: 2
+    character: 18
+  end_position:
+    bytes: 30
+    line: 2
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 30
+    line: 3
+    character: 1
+  end_position:
+    bytes: 35
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 35
+    line: 3
+    character: 6
+  end_position:
+    bytes: 36
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 36
+    line: 3
+    character: 7
+  end_position:
+    bytes: 37
+    line: 3
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 37
+    line: 3
+    character: 8
+  end_position:
+    bytes: 38
+    line: 3
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 38
+    line: 3
+    character: 9
+  end_position:
+    bytes: 39
+    line: 3
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 39
+    line: 3
+    character: 10
+  end_position:
+    bytes: 40
+    line: 3
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 40
+    line: 3
+    character: 11
+  end_position:
+    bytes: 41
+    line: 3
+    character: 12
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 41
+    line: 3
+    character: 12
+  end_position:
+    bytes: 42
+    line: 3
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 42
+    line: 4
+    character: 1
+  end_position:
+    bytes: 42
+    line: 4
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-function-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..04393d9f28cddcf660f9550a04a1d866696b7cf1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-1/ast.snap
@@ -0,0 +1,241 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/local-function-1
+---
+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: 26
+                                        line: 2
+                                        character: 8
+                                      end_position:
+                                        bytes: 27
+                                        line: 2
+                                        character: 9
+                                      token_type:
+                                        type: Symbol
+                                        symbol: )
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 27
+                                          line: 2
+                                          character: 9
+                                        end_position:
+                                          bytes: 28
+                                          line: 2
+                                          character: 9
+                                        token_type:
+                                          type: Whitespace
+                                          characters: "\n"
+                              arguments:
+                                pairs:
+                                  - End:
+                                      Number:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 25
+                                            line: 2
+                                            character: 7
+                                          end_position:
+                                            bytes: 26
+                                            line: 2
+                                            character: 8
+                                          token_type:
+                                            type: Number
+                                            text: "1"
+                                        trailing_trivia: []
+                - ~
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 28
+                line: 3
+                character: 1
+              end_position:
+                bytes: 31
+                line: 3
+                character: 4
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia:
+              - start_position:
+                  bytes: 31
+                  line: 3
+                  character: 4
+                end_position:
+                  bytes: 32
+                  line: 3
+                  character: 4
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-function-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..fbbbdc20f8fb4481dd90cd69d5ce1928900eff69
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-1/source.lua
@@ -0,0 +1,3 @@
+local function x()
+	call(1)
+end
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-function-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b813f3bd7778109795cabf4e7009a7c95a1cd716
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-1/tokens.snap
@@ -0,0 +1,193 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/local-function-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: 24
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 24
+    line: 2
+    character: 6
+  end_position:
+    bytes: 25
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 25
+    line: 2
+    character: 7
+  end_position:
+    bytes: 26
+    line: 2
+    character: 8
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 26
+    line: 2
+    character: 8
+  end_position:
+    bytes: 27
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 27
+    line: 2
+    character: 9
+  end_position:
+    bytes: 28
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 28
+    line: 3
+    character: 1
+  end_position:
+    bytes: 31
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 31
+    line: 3
+    character: 4
+  end_position:
+    bytes: 32
+    line: 3
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 32
+    line: 4
+    character: 1
+  end_position:
+    bytes: 32
+    line: 4
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-function-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b1ab1c0eb020b0defb9bfbcb911aee355081a0c1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-2/ast.snap
@@ -0,0 +1,590 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.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: 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: " "
+          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: a
+                      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: b
+                    trailing_trivia: []
+          block:
+            stmts: []
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 25
+                line: 1
+                character: 26
+              end_position:
+                bytes: 28
+                line: 1
+                character: 29
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia:
+              - start_position:
+                  bytes: 28
+                  line: 1
+                  character: 29
+                end_position:
+                  bytes: 29
+                  line: 1
+                  character: 29
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - LocalFunction:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 29
+              line: 2
+              character: 1
+            end_position:
+              bytes: 34
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 34
+                line: 2
+                character: 6
+              end_position:
+                bytes: 35
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        function_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 35
+              line: 2
+              character: 7
+            end_position:
+              bytes: 43
+              line: 2
+              character: 15
+            token_type:
+              type: Symbol
+              symbol: function
+          trailing_trivia:
+            - start_position:
+                bytes: 43
+                line: 2
+                character: 15
+              end_position:
+                bytes: 44
+                line: 2
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        name:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 44
+              line: 2
+              character: 16
+            end_position:
+              bytes: 47
+              line: 2
+              character: 19
+            token_type:
+              type: Identifier
+              identifier: bar
+          trailing_trivia: []
+        body:
+          parameters_parentheses:
+            tokens:
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 47
+                    line: 2
+                    character: 19
+                  end_position:
+                    bytes: 48
+                    line: 2
+                    character: 20
+                  token_type:
+                    type: Symbol
+                    symbol: (
+                trailing_trivia: []
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 51
+                    line: 2
+                    character: 23
+                  end_position:
+                    bytes: 52
+                    line: 2
+                    character: 24
+                  token_type:
+                    type: Symbol
+                    symbol: )
+                trailing_trivia:
+                  - start_position:
+                      bytes: 52
+                      line: 2
+                      character: 24
+                    end_position:
+                      bytes: 53
+                      line: 2
+                      character: 25
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+          parameters:
+            pairs:
+              - End:
+                  Ellipse:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 48
+                        line: 2
+                        character: 20
+                      end_position:
+                        bytes: 51
+                        line: 2
+                        character: 23
+                      token_type:
+                        type: Symbol
+                        symbol: "..."
+                    trailing_trivia: []
+          block:
+            stmts: []
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 53
+                line: 2
+                character: 25
+              end_position:
+                bytes: 56
+                line: 2
+                character: 28
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia:
+              - start_position:
+                  bytes: 56
+                  line: 2
+                  character: 28
+                end_position:
+                  bytes: 57
+                  line: 2
+                  character: 28
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - LocalFunction:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 57
+              line: 3
+              character: 1
+            end_position:
+              bytes: 62
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 62
+                line: 3
+                character: 6
+              end_position:
+                bytes: 63
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        function_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 63
+              line: 3
+              character: 7
+            end_position:
+              bytes: 71
+              line: 3
+              character: 15
+            token_type:
+              type: Symbol
+              symbol: function
+          trailing_trivia:
+            - start_position:
+                bytes: 71
+                line: 3
+                character: 15
+              end_position:
+                bytes: 72
+                line: 3
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        name:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 72
+              line: 3
+              character: 16
+            end_position:
+              bytes: 75
+              line: 3
+              character: 19
+            token_type:
+              type: Identifier
+              identifier: baz
+          trailing_trivia: []
+        body:
+          parameters_parentheses:
+            tokens:
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 75
+                    line: 3
+                    character: 19
+                  end_position:
+                    bytes: 76
+                    line: 3
+                    character: 20
+                  token_type:
+                    type: Symbol
+                    symbol: (
+                trailing_trivia: []
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 85
+                    line: 3
+                    character: 29
+                  end_position:
+                    bytes: 86
+                    line: 3
+                    character: 30
+                  token_type:
+                    type: Symbol
+                    symbol: )
+                trailing_trivia:
+                  - start_position:
+                      bytes: 86
+                      line: 3
+                      character: 30
+                    end_position:
+                      bytes: 87
+                      line: 3
+                      character: 31
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+          parameters:
+            pairs:
+              - Punctuated:
+                  - Name:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 76
+                          line: 3
+                          character: 20
+                        end_position:
+                          bytes: 77
+                          line: 3
+                          character: 21
+                        token_type:
+                          type: Identifier
+                          identifier: a
+                      trailing_trivia: []
+                  - leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 77
+                        line: 3
+                        character: 21
+                      end_position:
+                        bytes: 78
+                        line: 3
+                        character: 22
+                      token_type:
+                        type: Symbol
+                        symbol: ","
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 78
+                          line: 3
+                          character: 22
+                        end_position:
+                          bytes: 79
+                          line: 3
+                          character: 23
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+              - Punctuated:
+                  - Name:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 79
+                          line: 3
+                          character: 23
+                        end_position:
+                          bytes: 80
+                          line: 3
+                          character: 24
+                        token_type:
+                          type: Identifier
+                          identifier: b
+                      trailing_trivia: []
+                  - leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 80
+                        line: 3
+                        character: 24
+                      end_position:
+                        bytes: 81
+                        line: 3
+                        character: 25
+                      token_type:
+                        type: Symbol
+                        symbol: ","
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 81
+                          line: 3
+                          character: 25
+                        end_position:
+                          bytes: 82
+                          line: 3
+                          character: 26
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+              - End:
+                  Ellipse:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 82
+                        line: 3
+                        character: 26
+                      end_position:
+                        bytes: 85
+                        line: 3
+                        character: 29
+                      token_type:
+                        type: Symbol
+                        symbol: "..."
+                    trailing_trivia: []
+          block:
+            stmts: []
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 87
+                line: 3
+                character: 31
+              end_position:
+                bytes: 90
+                line: 3
+                character: 34
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-function-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..a17fbee1dfc532c679e6b3336f616685a2441654
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-2/source.lua
@@ -0,0 +1,3 @@
+local function foo(a, b) end
+local function bar(...) end
+local function baz(a, b, ...) end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/local-function-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..13cbe42855484fcad4d34e8d785f490190359257
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/local-function-2/tokens.snap
@@ -0,0 +1,468 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/local-function-2
+
+---
+- 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: a
+- 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: b
+- 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: 28
+    line: 1
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 28
+    line: 1
+    character: 29
+  end_position:
+    bytes: 29
+    line: 1
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 29
+    line: 2
+    character: 1
+  end_position:
+    bytes: 34
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 34
+    line: 2
+    character: 6
+  end_position:
+    bytes: 35
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 35
+    line: 2
+    character: 7
+  end_position:
+    bytes: 43
+    line: 2
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: function
+- start_position:
+    bytes: 43
+    line: 2
+    character: 15
+  end_position:
+    bytes: 44
+    line: 2
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 44
+    line: 2
+    character: 16
+  end_position:
+    bytes: 47
+    line: 2
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 47
+    line: 2
+    character: 19
+  end_position:
+    bytes: 48
+    line: 2
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 48
+    line: 2
+    character: 20
+  end_position:
+    bytes: 51
+    line: 2
+    character: 23
+  token_type:
+    type: Symbol
+    symbol: "..."
+- start_position:
+    bytes: 51
+    line: 2
+    character: 23
+  end_position:
+    bytes: 52
+    line: 2
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 52
+    line: 2
+    character: 24
+  end_position:
+    bytes: 53
+    line: 2
+    character: 25
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 53
+    line: 2
+    character: 25
+  end_position:
+    bytes: 56
+    line: 2
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 56
+    line: 2
+    character: 28
+  end_position:
+    bytes: 57
+    line: 2
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 57
+    line: 3
+    character: 1
+  end_position:
+    bytes: 62
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 62
+    line: 3
+    character: 6
+  end_position:
+    bytes: 63
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 63
+    line: 3
+    character: 7
+  end_position:
+    bytes: 71
+    line: 3
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: function
+- start_position:
+    bytes: 71
+    line: 3
+    character: 15
+  end_position:
+    bytes: 72
+    line: 3
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 72
+    line: 3
+    character: 16
+  end_position:
+    bytes: 75
+    line: 3
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 75
+    line: 3
+    character: 19
+  end_position:
+    bytes: 76
+    line: 3
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 76
+    line: 3
+    character: 20
+  end_position:
+    bytes: 77
+    line: 3
+    character: 21
+  token_type:
+    type: Identifier
+    identifier: a
+- start_position:
+    bytes: 77
+    line: 3
+    character: 21
+  end_position:
+    bytes: 78
+    line: 3
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 78
+    line: 3
+    character: 22
+  end_position:
+    bytes: 79
+    line: 3
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 79
+    line: 3
+    character: 23
+  end_position:
+    bytes: 80
+    line: 3
+    character: 24
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 80
+    line: 3
+    character: 24
+  end_position:
+    bytes: 81
+    line: 3
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 81
+    line: 3
+    character: 25
+  end_position:
+    bytes: 82
+    line: 3
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 82
+    line: 3
+    character: 26
+  end_position:
+    bytes: 85
+    line: 3
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: "..."
+- start_position:
+    bytes: 85
+    line: 3
+    character: 29
+  end_position:
+    bytes: 86
+    line: 3
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 86
+    line: 3
+    character: 30
+  end_position:
+    bytes: 87
+    line: 3
+    character: 31
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 87
+    line: 3
+    character: 31
+  end_position:
+    bytes: 90
+    line: 3
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 90
+    line: 3
+    character: 34
+  end_position:
+    bytes: 90
+    line: 3
+    character: 34
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/mixed-indented-comments/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/mixed-indented-comments/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7750c7873a074e0ec4c3b00dfed0221938130e3e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/mixed-indented-comments/ast.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/mixed-indented-comments
+
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/mixed-indented-comments/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/mixed-indented-comments/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..23c37db1896b4cf0eab9e7ca54bfb45117ceb9e8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/mixed-indented-comments/source.lua
@@ -0,0 +1,4 @@
+	-- Indented single line
+	--[[
+		Indented multi line
+	]]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/mixed-indented-comments/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/mixed-indented-comments/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..78d7f720ee6e92b12b53ab81bae86d2e17f62ccb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/mixed-indented-comments/tokens.snap
@@ -0,0 +1,73 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/mixed-indented-comments
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 1
+    line: 1
+    character: 2
+  end_position:
+    bytes: 24
+    line: 1
+    character: 25
+  token_type:
+    type: SingleLineComment
+    comment: " Indented single line"
+- 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: 56
+    line: 4
+    character: 4
+  token_type:
+    type: MultiLineComment
+    blocks: 0
+    comment: "\n\t\tIndented multi line\n\t"
+- start_position:
+    bytes: 56
+    line: 4
+    character: 4
+  end_position:
+    bytes: 56
+    line: 4
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..31b6ed8eb75b9814cb85c06a4fbf0c209a4eb76c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-1/ast.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/multi-line-comments-1
+
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..5a8bf75e61862f096ebf24388e3a26b7ddab7bfa
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-1/source.lua
@@ -0,0 +1,5 @@
+--[[
+	such comments
+	much lines
+	wow
+]]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5920d2c93f97d89b6d30a34c5523260465e9a46a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-1/tokens.snap
@@ -0,0 +1,29 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/multi-line-comments-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 39
+    line: 5
+    character: 3
+  token_type:
+    type: MultiLineComment
+    blocks: 0
+    comment: "\n\tsuch comments\n\tmuch lines\n\twow\n"
+- start_position:
+    bytes: 39
+    line: 5
+    character: 3
+  end_position:
+    bytes: 39
+    line: 5
+    character: 3
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..95de1b460c8bf1c5e133fe61595d0e663961d7d0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-2/ast.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/multi-line-comments-2
+
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..56291f7fd0c41bfe8017a753d3f2fa23c4841f71
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-2/source.lua
@@ -0,0 +1,4 @@
+--[=[
+	never have i used these weird equals signs comments
+	but im sure someone does
+]=]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9ae8494d583655c25ff51445ce23f1be11dab9cd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-2/tokens.snap
@@ -0,0 +1,29 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/multi-line-comments-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 88
+    line: 4
+    character: 4
+  token_type:
+    type: MultiLineComment
+    blocks: 1
+    comment: "\n\tnever have i used these weird equals signs comments\n\tbut im sure someone does\n"
+- start_position:
+    bytes: 88
+    line: 4
+    character: 4
+  end_position:
+    bytes: 88
+    line: 4
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3d31018e599136f5bb8dea0054156b499adc2ce1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-3/ast.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/multi-line-comments-3
+
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..977869da56a74f8519ca7ef99a1e477014d599ae
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-3/source.lua
@@ -0,0 +1,3 @@
+--[=[
+--[[
+]=]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6cb4728f8aca14cd9534b22ea6730de7ad50ed0a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-3/tokens.snap
@@ -0,0 +1,29 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/multi-line-comments-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 14
+    line: 3
+    character: 4
+  token_type:
+    type: MultiLineComment
+    blocks: 1
+    comment: "\n--[[\n"
+- start_position:
+    bytes: 14
+    line: 3
+    character: 4
+  end_position:
+    bytes: 14
+    line: 3
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e5cbdd6ee413b455061cbf67b7168d3a27e9558a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-4/ast.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/multi-line-comments-4
+
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..72b48afcd64f56ccc7faeeafb58fa60caed15117
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-4/source.lua
@@ -0,0 +1,5 @@
+--[=====[
+	lua be like
+]====]
+	still going
+]=====]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cbc8ac6619153db82acc9030538675addbe218c0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-4/tokens.snap
@@ -0,0 +1,29 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/multi-line-comments-4
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 50
+    line: 5
+    character: 8
+  token_type:
+    type: MultiLineComment
+    blocks: 5
+    comment: "\n\tlua be like\n]====]\n\tstill going\n"
+- start_position:
+    bytes: 50
+    line: 5
+    character: 8
+  end_position:
+    bytes: 50
+    line: 5
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b52c100bb6c1b2c4d499f44d7c0592bd5ee8fdce
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-5/ast.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/multi-line-comments-5
+
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..116f6fb0327dc640384ba9f3e95f6ba1056d4a66
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-5/source.lua
@@ -0,0 +1,6 @@
+--[[
+local emotes = {
+	[":thinking:"] = "http://www.roblox.com/asset/?id=643340245",
+	[":bug:"] = "http://www.roblox.com/asset/?id=860037275"
+}
+]]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cac4f568b5a9ae3f0478e3cf09f31f8d5e091c32
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-5/tokens.snap
@@ -0,0 +1,29 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/multi-line-comments-5
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 146
+    line: 6
+    character: 3
+  token_type:
+    type: MultiLineComment
+    blocks: 0
+    comment: "\nlocal emotes = {\n\t[\":thinking:\"] = \"http://www.roblox.com/asset/?id=643340245\",\n\t[\":bug:\"] = \"http://www.roblox.com/asset/?id=860037275\"\n}\n"
+- start_position:
+    bytes: 146
+    line: 6
+    character: 3
+  end_position:
+    bytes: 146
+    line: 6
+    character: 3
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-6/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-6/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2b3b7063b53c47011406958cbc6d72d098fc4a2a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-6/ast.snap
@@ -0,0 +1,165 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.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: 38
+                    line: 1
+                    character: 39
+                  end_position:
+                    bytes: 39
+                    line: 1
+                    character: 40
+                  token_type:
+                    type: Symbol
+                    symbol: )
+                trailing_trivia:
+                  - start_position:
+                      bytes: 39
+                      line: 1
+                      character: 40
+                    end_position:
+                      bytes: 40
+                      line: 1
+                      character: 40
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+          parameters:
+            pairs:
+              - End:
+                  Ellipse:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 17
+                        line: 1
+                        character: 18
+                      end_position:
+                        bytes: 20
+                        line: 1
+                        character: 21
+                      token_type:
+                        type: Symbol
+                        symbol: "..."
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 20
+                          line: 1
+                          character: 21
+                        end_position:
+                          bytes: 38
+                          line: 1
+                          character: 39
+                        token_type:
+                          type: MultiLineComment
+                          blocks: 0
+                          comment: comment here
+          block:
+            stmts: []
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 40
+                line: 2
+                character: 1
+              end_position:
+                bytes: 43
+                line: 2
+                character: 4
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-6/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-6/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..e5f7405cf0649caa632cc72b6efbd7786e802a3c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-6/source.lua
@@ -0,0 +1,2 @@
+local function x(...--[[comment here]])
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-6/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-6/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..36675a2e736dae6bec94c22e8ed12eb10173d5c9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-6/tokens.snap
@@ -0,0 +1,139 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/multi-line-comments-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: 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: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: "..."
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 38
+    line: 1
+    character: 39
+  token_type:
+    type: MultiLineComment
+    blocks: 0
+    comment: comment here
+- start_position:
+    bytes: 38
+    line: 1
+    character: 39
+  end_position:
+    bytes: 39
+    line: 1
+    character: 40
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 39
+    line: 1
+    character: 40
+  end_position:
+    bytes: 40
+    line: 1
+    character: 40
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 40
+    line: 2
+    character: 1
+  end_position:
+    bytes: 43
+    line: 2
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 43
+    line: 2
+    character: 4
+  end_position:
+    bytes: 43
+    line: 2
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-7/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-7/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d4bf0738b38e777d55493d1c41bc0f68d870b2bb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-7/ast.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/multi-line-comments-7
+
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-7/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-7/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..946434aa9f209527031d0c5281d2373de63ab242
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-7/source.lua
@@ -0,0 +1,3 @@
+--[=[ μέλλον ]=]
+
+-- some text here
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-7/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-7/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..276b2eccce6ba5fc386ef99f9db7632e29d5adb8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-7/tokens.snap
@@ -0,0 +1,73 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/multi-line-comments-7
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 22
+    line: 1
+    character: 17
+  token_type:
+    type: MultiLineComment
+    blocks: 1
+    comment: " μέλλον "
+- start_position:
+    bytes: 22
+    line: 1
+    character: 17
+  end_position:
+    bytes: 23
+    line: 1
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 23
+    line: 2
+    character: 1
+  end_position:
+    bytes: 24
+    line: 2
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 24
+    line: 3
+    character: 1
+  end_position:
+    bytes: 41
+    line: 3
+    character: 18
+  token_type:
+    type: SingleLineComment
+    comment: " some text here"
+- start_position:
+    bytes: 41
+    line: 3
+    character: 18
+  end_position:
+    bytes: 42
+    line: 3
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 42
+    line: 4
+    character: 1
+  end_position:
+    bytes: 42
+    line: 4
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-8/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-8/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b3b3fb27254e1e42ca82e64f9b60d04928bf7617
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-8/ast.snap
@@ -0,0 +1,143 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/multi-line-comments-8
+---
+stmts:
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 0
+                line: 1
+                character: 1
+              end_position:
+                bytes: 21
+                line: 1
+                character: 11
+              token_type:
+                type: MultiLineComment
+                blocks: 0
+                comment: 👨🏾‍💻
+            - start_position:
+                bytes: 21
+                line: 1
+                character: 11
+              end_position:
+                bytes: 22
+                line: 1
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 22
+              line: 2
+              character: 1
+            end_position:
+              bytes: 27
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 27
+                line: 2
+                character: 6
+              end_position:
+                bytes: 28
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 28
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 37
+                    line: 2
+                    character: 16
+                  token_type:
+                    type: Identifier
+                    identifier: more_code
+                trailing_trivia:
+                  - start_position:
+                      bytes: 37
+                      line: 2
+                      character: 16
+                    end_position:
+                      bytes: 38
+                      line: 2
+                      character: 17
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 38
+              line: 2
+              character: 17
+            end_position:
+              bytes: 39
+              line: 2
+              character: 18
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 39
+                line: 2
+                character: 18
+              end_position:
+                bytes: 40
+                line: 2
+                character: 19
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Var:
+                  Name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 40
+                        line: 2
+                        character: 19
+                      end_position:
+                        bytes: 44
+                        line: 2
+                        character: 23
+                      token_type:
+                        type: Identifier
+                        identifier: here
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 44
+                          line: 2
+                          character: 23
+                        end_position:
+                          bytes: 45
+                          line: 2
+                          character: 23
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-8/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-8/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..048d07117a9909cb4991f7720c6cb6a4f3cbb974
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-8/source.lua
@@ -0,0 +1,2 @@
+--[[👨🏾‍💻]]
+local more_code = here
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-8/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-8/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3eafa0cc4bc2e6bdbf3c4b29343c86f5fb1c5ee0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-8/tokens.snap
@@ -0,0 +1,128 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/multi-line-comments-8
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 21
+    line: 1
+    character: 11
+  token_type:
+    type: MultiLineComment
+    blocks: 0
+    comment: 👨🏾‍💻
+- start_position:
+    bytes: 21
+    line: 1
+    character: 11
+  end_position:
+    bytes: 22
+    line: 1
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 22
+    line: 2
+    character: 1
+  end_position:
+    bytes: 27
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 27
+    line: 2
+    character: 6
+  end_position:
+    bytes: 28
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 28
+    line: 2
+    character: 7
+  end_position:
+    bytes: 37
+    line: 2
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: more_code
+- start_position:
+    bytes: 37
+    line: 2
+    character: 16
+  end_position:
+    bytes: 38
+    line: 2
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 38
+    line: 2
+    character: 17
+  end_position:
+    bytes: 39
+    line: 2
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 39
+    line: 2
+    character: 18
+  end_position:
+    bytes: 40
+    line: 2
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 40
+    line: 2
+    character: 19
+  end_position:
+    bytes: 44
+    line: 2
+    character: 23
+  token_type:
+    type: Identifier
+    identifier: here
+- start_position:
+    bytes: 44
+    line: 2
+    character: 23
+  end_position:
+    bytes: 45
+    line: 2
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 45
+    line: 3
+    character: 1
+  end_position:
+    bytes: 45
+    line: 3
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-9/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-9/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6e1d3d1aab858bc8ed7c2942cad4bfd2762342f4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-9/ast.snap
@@ -0,0 +1,6 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-9/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-9/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..5ef37535229369675b8358f7afc2b02c4a03a256
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-9/source.lua
@@ -0,0 +1,21 @@
+--[=[
+
+	This description starts one line down,
+
+	And has a line in the middle, followed by trailing lines.
+
+	```lua
+	function test()
+		print("indentation")
+
+		do
+			print("more indented")
+		end
+	end
+	```
+
+
+	@class indentation
+
+
+]=]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-9/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-9/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3385af38dec2b9ecf5be252ba0ebef5ff06ad91d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-comments-9/tokens.snap
@@ -0,0 +1,27 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 231
+    line: 21
+    character: 4
+  token_type:
+    type: MultiLineComment
+    blocks: 1
+    comment: "\n\n\tThis description starts one line down,\n\n\tAnd has a line in the middle, followed by trailing lines.\n\n\t```lua\n\tfunction test()\n\t\tprint(\"indentation\")\n\n\t\tdo\n\t\t\tprint(\"more indented\")\n\t\tend\n\tend\n\t```\n\n\n\t@class indentation\n\n\n"
+- start_position:
+    bytes: 231
+    line: 21
+    character: 4
+  end_position:
+    bytes: 231
+    line: 21
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..56c703f600185757aa64679b648f1b140055e637
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-1/ast.snap
@@ -0,0 +1,107 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: 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: 48
+                      line: 4
+                      character: 13
+                    token_type:
+                      type: StringLiteral
+                      literal: "Full Moon\nis a\nlossless\nLua parser"
+                      quote_type: Brackets
+                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..1cb9d1965066af3020305aa4c395d5e55fab6b77
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-1/source.lua
@@ -0,0 +1,4 @@
+local x = [[Full Moon
+is a
+lossless
+Lua parser]]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cdb29fb380bf29b22557d546d4baef5a646c7f7f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-1/tokens.snap
@@ -0,0 +1,93 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- 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: 48
+    line: 4
+    character: 13
+  token_type:
+    type: StringLiteral
+    literal: "Full Moon\nis a\nlossless\nLua parser"
+    quote_type: Brackets
+- start_position:
+    bytes: 48
+    line: 4
+    character: 13
+  end_position:
+    bytes: 48
+    line: 4
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e0c6de1e151a88b5c162bb93b26851cbb19a6fea
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-2/ast.snap
@@ -0,0 +1,108 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: 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: 43
+                      line: 3
+                      character: 9
+                    token_type:
+                      type: StringLiteral
+                      literal: "This is\nseveral equal\nsigns"
+                      multi_line_depth: 1
+                      quote_type: Brackets
+                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8e6c09ebd2b19e51dcc5bd528d63eb23b78ee937
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-2/source.lua
@@ -0,0 +1,3 @@
+local x = [=[This is
+several equal
+signs]=]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9254ab6340d62c395da0c2fcef06e131dffab289
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-2/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- 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: 43
+    line: 3
+    character: 9
+  token_type:
+    type: StringLiteral
+    literal: "This is\nseveral equal\nsigns"
+    multi_line_depth: 1
+    quote_type: Brackets
+- start_position:
+    bytes: 43
+    line: 3
+    character: 9
+  end_position:
+    bytes: 43
+    line: 3
+    character: 9
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c71df3ec8d7f284bd50edbbfd8fa38157d60fe14
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-3/ast.snap
@@ -0,0 +1,107 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: 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: 154
+                      line: 6
+                      character: 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"
+                      quote_type: Brackets
+                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0856c4d25d099a2b1d532dc9ca49db91dd151431
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-3/source.lua
@@ -0,0 +1,6 @@
+local x = [[
+local emotes = {
+	[":thinking:"] = "http://www.roblox.com/asset/?id=643340245",
+	[":bug:"] = "http://www.roblox.com/asset/?id=860037275"
+}
+]]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ec9dc2950c24762bd35462b11fa52e93220cda11
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-3/tokens.snap
@@ -0,0 +1,93 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- 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: 154
+    line: 6
+    character: 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"
+    quote_type: Brackets
+- start_position:
+    bytes: 154
+    line: 6
+    character: 3
+  end_position:
+    bytes: 154
+    line: 6
+    character: 3
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..af33a16f090bb31972b457fe95293d6393e1696d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-4/ast.snap
@@ -0,0 +1,77 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.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: 13
+                            line: 1
+                            character: 14
+                          end_position:
+                            bytes: 14
+                            line: 1
+                            character: 15
+                          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: 13
+                                line: 1
+                                character: 14
+                              token_type:
+                                type: StringLiteral
+                                literal: doge
+                                quote_type: Brackets
+                            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..12a0b783029356c6c4b43ba661b5b2542244a920
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-4/source.lua
@@ -0,0 +1 @@
+call([[doge]])
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cf929dfdc5fa734a170676b0411815de190d337e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-4/tokens.snap
@@ -0,0 +1,60 @@
+---
+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: call
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 13
+    line: 1
+    character: 14
+  token_type:
+    type: StringLiteral
+    literal: doge
+    quote_type: Brackets
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3f3efe1ec17fbe213c03ae455c903aa59ce5f0ac
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-5/ast.snap
@@ -0,0 +1,230 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: 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: 11
+                    line: 1
+                    character: 12
+                  token_type:
+                    type: Identifier
+                    identifier: emoji
+                trailing_trivia:
+                  - start_position:
+                      bytes: 11
+                      line: 1
+                      character: 12
+                    end_position:
+                      bytes: 12
+                      line: 1
+                      character: 13
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        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: " "
+        expr_list:
+          pairs:
+            - End:
+                String:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 14
+                      line: 1
+                      character: 15
+                    end_position:
+                      bytes: 26
+                      line: 1
+                      character: 21
+                    token_type:
+                      type: StringLiteral
+                      literal: 🧓🏽
+                      quote_type: Brackets
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 26
+                        line: 1
+                        character: 21
+                      end_position:
+                        bytes: 27
+                        line: 1
+                        character: 21
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 27
+              line: 2
+              character: 1
+            end_position:
+              bytes: 32
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 32
+                line: 2
+                character: 6
+              end_position:
+                bytes: 33
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 33
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 42
+                    line: 2
+                    character: 16
+                  token_type:
+                    type: Identifier
+                    identifier: more_code
+                trailing_trivia:
+                  - start_position:
+                      bytes: 42
+                      line: 2
+                      character: 16
+                    end_position:
+                      bytes: 43
+                      line: 2
+                      character: 17
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 43
+              line: 2
+              character: 17
+            end_position:
+              bytes: 44
+              line: 2
+              character: 18
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 44
+                line: 2
+                character: 18
+              end_position:
+                bytes: 45
+                line: 2
+                character: 19
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Var:
+                  Name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 45
+                        line: 2
+                        character: 19
+                      end_position:
+                        bytes: 49
+                        line: 2
+                        character: 23
+                      token_type:
+                        type: Identifier
+                        identifier: here
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 49
+                          line: 2
+                          character: 23
+                        end_position:
+                          bytes: 50
+                          line: 2
+                          character: 23
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..4780d5f2382549bdb58010c7647b556d80aaee55
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-5/source.lua
@@ -0,0 +1,2 @@
+local emoji = [[🧓🏽]]
+local more_code = here
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..034d5f0c4e1a39b9ca8548e2e49fa1b5c2b5f775
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-5/tokens.snap
@@ -0,0 +1,192 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- 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: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: emoji
+- 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: 26
+    line: 1
+    character: 21
+  token_type:
+    type: StringLiteral
+    literal: 🧓🏽
+    quote_type: Brackets
+- start_position:
+    bytes: 26
+    line: 1
+    character: 21
+  end_position:
+    bytes: 27
+    line: 1
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 27
+    line: 2
+    character: 1
+  end_position:
+    bytes: 32
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 32
+    line: 2
+    character: 6
+  end_position:
+    bytes: 33
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 33
+    line: 2
+    character: 7
+  end_position:
+    bytes: 42
+    line: 2
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: more_code
+- start_position:
+    bytes: 42
+    line: 2
+    character: 16
+  end_position:
+    bytes: 43
+    line: 2
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 43
+    line: 2
+    character: 17
+  end_position:
+    bytes: 44
+    line: 2
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 44
+    line: 2
+    character: 18
+  end_position:
+    bytes: 45
+    line: 2
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 45
+    line: 2
+    character: 19
+  end_position:
+    bytes: 49
+    line: 2
+    character: 23
+  token_type:
+    type: Identifier
+    identifier: here
+- start_position:
+    bytes: 49
+    line: 2
+    character: 23
+  end_position:
+    bytes: 50
+    line: 2
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 50
+    line: 3
+    character: 1
+  end_position:
+    bytes: 50
+    line: 3
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-6/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-6/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e389a6fcfe6c003a4e90f0f1aa5426212237bf46
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-6/ast.snap
@@ -0,0 +1,120 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/multi-line-string-6
+---
+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: 9
+                    line: 1
+                    character: 10
+                  token_type:
+                    type: Identifier
+                    identifier: foo
+                trailing_trivia:
+                  - start_position:
+                      bytes: 9
+                      line: 1
+                      character: 10
+                    end_position:
+                      bytes: 10
+                      line: 1
+                      character: 11
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                String:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 12
+                      line: 1
+                      character: 13
+                    end_position:
+                      bytes: 22
+                      line: 2
+                      character: 5
+                    token_type:
+                      type: StringLiteral
+                      literal: "bar\\\nbaz"
+                      quote_type: Double
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 22
+                        line: 2
+                        character: 5
+                      end_position:
+                        bytes: 23
+                        line: 2
+                        character: 5
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-6/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-6/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f090ebd0df8ab036ddd4b9e72a250843b170305b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-6/source.lua
@@ -0,0 +1,2 @@
+local foo = "bar\
+baz"
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-6/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-6/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d89312a4c20910f6d75eb00e31cc23778697002b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-6/tokens.snap
@@ -0,0 +1,106 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/multi-line-string-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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: foo
+- 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: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 22
+    line: 2
+    character: 5
+  token_type:
+    type: StringLiteral
+    literal: "bar\\\nbaz"
+    quote_type: Double
+- start_position:
+    bytes: 22
+    line: 2
+    character: 5
+  end_position:
+    bytes: 23
+    line: 2
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 23
+    line: 3
+    character: 1
+  end_position:
+    bytes: 23
+    line: 3
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-7/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-7/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5fd0d30fa08b1e9a89d2fc09fb452993ae0fe29a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-7/ast.snap
@@ -0,0 +1,108 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: 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: a
+                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: 20
+                      line: 1
+                      character: 21
+                    token_type:
+                      type: StringLiteral
+                      literal: "[%s]"
+                      multi_line_depth: 1
+                      quote_type: Brackets
+                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-7/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-7/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..902027fc65b97de765cc6f2d93c26b80efd7ae22
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-7/source.lua
@@ -0,0 +1 @@
+local a = [=[[%s]]=]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-7/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-7/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3babacfa372ec1629fac5b58b7ed6102be23560e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-7/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- 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: a
+- 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: StringLiteral
+    literal: "[%s]"
+    multi_line_depth: 1
+    quote_type: Brackets
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-8/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-8/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a89e03a8509a7a6849e176830027f1740288d1cf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-8/ast.snap
@@ -0,0 +1,108 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: 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: 68
+                      line: 1
+                      character: 69
+                    token_type:
+                      type: StringLiteral
+                      literal: "\\v<((do|load)file|require)\\s*\\(?['\"]\\zs[^'\"]+\\ze['\"]"
+                      multi_line_depth: 1
+                      quote_type: Brackets
+                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-8/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-8/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..93ec4d942d7da09c17d7ab29046f9e0f075307f4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-8/source.lua
@@ -0,0 +1 @@
+local x = [=[\v<((do|load)file|require)\s*\(?['"]\zs[^'"]+\ze['"]]=]
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-8/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-8/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..eefcaa224c6be0a97296b9cba1fd61e9163c7783
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/multi-line-string-8/tokens.snap
@@ -0,0 +1,94 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- 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: 68
+    line: 1
+    character: 69
+  token_type:
+    type: StringLiteral
+    literal: "\\v<((do|load)file|require)\\s*\\(?['\"]\\zs[^'\"]+\\ze['\"]"
+    multi_line_depth: 1
+    quote_type: Brackets
+- start_position:
+    bytes: 68
+    line: 1
+    character: 69
+  end_position:
+    bytes: 68
+    line: 1
+    character: 69
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/negative-numbers/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/negative-numbers/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4315cf3060e64dbb4cb460fa1db3b82c5a5417b6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/negative-numbers/ast.snap
@@ -0,0 +1,595 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/negative-numbers
+---
+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: 9
+                    line: 1
+                    character: 10
+                  token_type:
+                    type: Identifier
+                    identifier: foo
+                trailing_trivia:
+                  - start_position:
+                      bytes: 9
+                      line: 1
+                      character: 10
+                    end_position:
+                      bytes: 10
+                      line: 1
+                      character: 11
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    Var:
+                      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: x
+                        trailing_trivia: []
+                  binop:
+                    Minus:
+                      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: []
+                  rhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 14
+                          line: 1
+                          character: 15
+                        end_position:
+                          bytes: 15
+                          line: 1
+                          character: 16
+                        token_type:
+                          type: Number
+                          text: "1"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 15
+                            line: 1
+                            character: 16
+                          end_position:
+                            bytes: 16
+                            line: 1
+                            character: 16
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 16
+              line: 2
+              character: 1
+            end_position:
+              bytes: 21
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 21
+                line: 2
+                character: 6
+              end_position:
+                bytes: 22
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 22
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 25
+                    line: 2
+                    character: 10
+                  token_type:
+                    type: Identifier
+                    identifier: foo
+                trailing_trivia:
+                  - start_position:
+                      bytes: 25
+                      line: 2
+                      character: 10
+                    end_position:
+                      bytes: 26
+                      line: 2
+                      character: 11
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 26
+              line: 2
+              character: 11
+            end_position:
+              bytes: 27
+              line: 2
+              character: 12
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 27
+                line: 2
+                character: 12
+              end_position:
+                bytes: 28
+                line: 2
+                character: 13
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 28
+                            line: 2
+                            character: 13
+                          end_position:
+                            bytes: 29
+                            line: 2
+                            character: 14
+                          token_type:
+                            type: Identifier
+                            identifier: x
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 29
+                              line: 2
+                              character: 14
+                            end_position:
+                              bytes: 30
+                              line: 2
+                              character: 15
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  binop:
+                    Minus:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 30
+                          line: 2
+                          character: 15
+                        end_position:
+                          bytes: 31
+                          line: 2
+                          character: 16
+                        token_type:
+                          type: Symbol
+                          symbol: "-"
+                      trailing_trivia: []
+                  rhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 31
+                          line: 2
+                          character: 16
+                        end_position:
+                          bytes: 32
+                          line: 2
+                          character: 17
+                        token_type:
+                          type: Number
+                          text: "1"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 32
+                            line: 2
+                            character: 17
+                          end_position:
+                            bytes: 33
+                            line: 2
+                            character: 17
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 33
+                line: 3
+                character: 1
+              end_position:
+                bytes: 38
+                line: 3
+                character: 6
+              token_type:
+                type: Identifier
+                identifier: print
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 38
+                            line: 3
+                            character: 6
+                          end_position:
+                            bytes: 39
+                            line: 3
+                            character: 7
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 43
+                            line: 3
+                            character: 11
+                          end_position:
+                            bytes: 44
+                            line: 3
+                            character: 12
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 44
+                              line: 3
+                              character: 12
+                            end_position:
+                              bytes: 45
+                              line: 3
+                              character: 12
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs:
+                      - End:
+                          BinaryOperator:
+                            lhs:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 39
+                                    line: 3
+                                    character: 7
+                                  end_position:
+                                    bytes: 40
+                                    line: 3
+                                    character: 8
+                                  token_type:
+                                    type: Number
+                                    text: "1"
+                                trailing_trivia: []
+                            binop:
+                              Plus:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 40
+                                    line: 3
+                                    character: 8
+                                  end_position:
+                                    bytes: 41
+                                    line: 3
+                                    character: 9
+                                  token_type:
+                                    type: Symbol
+                                    symbol: +
+                                trailing_trivia: []
+                            rhs:
+                              UnaryOperator:
+                                unop:
+                                  Minus:
+                                    leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 41
+                                        line: 3
+                                        character: 9
+                                      end_position:
+                                        bytes: 42
+                                        line: 3
+                                        character: 10
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "-"
+                                    trailing_trivia: []
+                                expression:
+                                  Number:
+                                    leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 42
+                                        line: 3
+                                        character: 10
+                                      end_position:
+                                        bytes: 43
+                                        line: 3
+                                        character: 11
+                                      token_type:
+                                        type: Number
+                                        text: "3"
+                                    trailing_trivia: []
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 45
+              line: 4
+              character: 1
+            end_position:
+              bytes: 50
+              line: 4
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 50
+                line: 4
+                character: 6
+              end_position:
+                bytes: 51
+                line: 4
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 51
+                    line: 4
+                    character: 7
+                  end_position:
+                    bytes: 54
+                    line: 4
+                    character: 10
+                  token_type:
+                    type: Identifier
+                    identifier: foo
+                trailing_trivia:
+                  - start_position:
+                      bytes: 54
+                      line: 4
+                      character: 10
+                    end_position:
+                      bytes: 55
+                      line: 4
+                      character: 11
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 55
+              line: 4
+              character: 11
+            end_position:
+              bytes: 56
+              line: 4
+              character: 12
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 56
+                line: 4
+                character: 12
+              end_position:
+                bytes: 57
+                line: 4
+                character: 13
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    UnaryOperator:
+                      unop:
+                        Minus:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 57
+                              line: 4
+                              character: 13
+                            end_position:
+                              bytes: 58
+                              line: 4
+                              character: 14
+                            token_type:
+                              type: Symbol
+                              symbol: "-"
+                          trailing_trivia: []
+                      expression:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 58
+                                line: 4
+                                character: 14
+                              end_position:
+                                bytes: 59
+                                line: 4
+                                character: 15
+                              token_type:
+                                type: Identifier
+                                identifier: x
+                            trailing_trivia: []
+                  binop:
+                    Plus:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 59
+                          line: 4
+                          character: 15
+                        end_position:
+                          bytes: 60
+                          line: 4
+                          character: 16
+                        token_type:
+                          type: Symbol
+                          symbol: +
+                      trailing_trivia: []
+                  rhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 60
+                          line: 4
+                          character: 16
+                        end_position:
+                          bytes: 61
+                          line: 4
+                          character: 17
+                        token_type:
+                          type: Number
+                          text: "1"
+                      trailing_trivia: []
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/negative-numbers/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/negative-numbers/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..3b7ccd7726e36138646ff3efced56944573a57f9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/negative-numbers/source.lua
@@ -0,0 +1,4 @@
+local foo = x-1
+local foo = x -1
+print(1+-3)
+local foo = -x+1
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/negative-numbers/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/negative-numbers/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ab3ba56a21fccca5059b4b5755dcbbdc551e30ef
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/negative-numbers/tokens.snap
@@ -0,0 +1,444 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/negative-numbers
+---
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: foo
+- 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: 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: Identifier
+    identifier: x
+- 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: Number
+    text: "1"
+- 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: 21
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 21
+    line: 2
+    character: 6
+  end_position:
+    bytes: 22
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 22
+    line: 2
+    character: 7
+  end_position:
+    bytes: 25
+    line: 2
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 25
+    line: 2
+    character: 10
+  end_position:
+    bytes: 26
+    line: 2
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 26
+    line: 2
+    character: 11
+  end_position:
+    bytes: 27
+    line: 2
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 27
+    line: 2
+    character: 12
+  end_position:
+    bytes: 28
+    line: 2
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 28
+    line: 2
+    character: 13
+  end_position:
+    bytes: 29
+    line: 2
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 29
+    line: 2
+    character: 14
+  end_position:
+    bytes: 30
+    line: 2
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 30
+    line: 2
+    character: 15
+  end_position:
+    bytes: 31
+    line: 2
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 31
+    line: 2
+    character: 16
+  end_position:
+    bytes: 32
+    line: 2
+    character: 17
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 32
+    line: 2
+    character: 17
+  end_position:
+    bytes: 33
+    line: 2
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 33
+    line: 3
+    character: 1
+  end_position:
+    bytes: 38
+    line: 3
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: print
+- start_position:
+    bytes: 38
+    line: 3
+    character: 6
+  end_position:
+    bytes: 39
+    line: 3
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 39
+    line: 3
+    character: 7
+  end_position:
+    bytes: 40
+    line: 3
+    character: 8
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 40
+    line: 3
+    character: 8
+  end_position:
+    bytes: 41
+    line: 3
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 41
+    line: 3
+    character: 9
+  end_position:
+    bytes: 42
+    line: 3
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 42
+    line: 3
+    character: 10
+  end_position:
+    bytes: 43
+    line: 3
+    character: 11
+  token_type:
+    type: Number
+    text: "3"
+- start_position:
+    bytes: 43
+    line: 3
+    character: 11
+  end_position:
+    bytes: 44
+    line: 3
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 44
+    line: 3
+    character: 12
+  end_position:
+    bytes: 45
+    line: 3
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 45
+    line: 4
+    character: 1
+  end_position:
+    bytes: 50
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 50
+    line: 4
+    character: 6
+  end_position:
+    bytes: 51
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 51
+    line: 4
+    character: 7
+  end_position:
+    bytes: 54
+    line: 4
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 54
+    line: 4
+    character: 10
+  end_position:
+    bytes: 55
+    line: 4
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 55
+    line: 4
+    character: 11
+  end_position:
+    bytes: 56
+    line: 4
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 56
+    line: 4
+    character: 12
+  end_position:
+    bytes: 57
+    line: 4
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 57
+    line: 4
+    character: 13
+  end_position:
+    bytes: 58
+    line: 4
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 58
+    line: 4
+    character: 14
+  end_position:
+    bytes: 59
+    line: 4
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 59
+    line: 4
+    character: 15
+  end_position:
+    bytes: 60
+    line: 4
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 60
+    line: 4
+    character: 16
+  end_position:
+    bytes: 61
+    line: 4
+    character: 17
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 61
+    line: 4
+    character: 17
+  end_position:
+    bytes: 61
+    line: 4
+    character: 17
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/numbers-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/numbers-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..af82c9c12545d5af7799d1ce7c306230627cd615
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/pass/numbers-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/numbers-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..71e00d7f067f71424eb6d3efaf9b0639ac3251a5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/numbers-1/source.lua
@@ -0,0 +1 @@
+_ = 0x02
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/numbers-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/numbers-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6abe86fabf4c18e1fe237860bac63b31d83bfbe5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/cases/pass/numeric-for-loop/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/numeric-for-loop/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8d1cb626099dc9571c8d6565672299bc167c4cf8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/numeric-for-loop/ast.snap
@@ -0,0 +1,736 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/numeric-for-loop
+---
+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: 9
+              line: 1
+              character: 10
+            token_type:
+              type: Identifier
+              identifier: index
+          trailing_trivia:
+            - start_position:
+                bytes: 9
+                line: 1
+                character: 10
+              end_position:
+                bytes: 10
+                line: 1
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          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: " "
+        start:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 12
+                line: 1
+                character: 13
+              end_position:
+                bytes: 13
+                line: 1
+                character: 14
+              token_type:
+                type: Number
+                text: "1"
+            trailing_trivia: []
+        start_end_comma:
+          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:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 15
+                line: 1
+                character: 16
+              end_position:
+                bytes: 17
+                line: 1
+                character: 18
+              token_type:
+                type: Number
+                text: "10"
+            trailing_trivia:
+              - start_position:
+                  bytes: 17
+                  line: 1
+                  character: 18
+                end_position:
+                  bytes: 18
+                  line: 1
+                  character: 19
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        end_step_comma: ~
+        step: ~
+        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:
+            - - FunctionCall:
+                  prefix:
+                    Name:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 21
+                          line: 1
+                          character: 22
+                        end_position:
+                          bytes: 25
+                          line: 1
+                          character: 26
+                        token_type:
+                          type: Identifier
+                          identifier: call
+                      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: 31
+                                      line: 1
+                                      character: 32
+                                    end_position:
+                                      bytes: 32
+                                      line: 1
+                                      character: 33
+                                    token_type:
+                                      type: Symbol
+                                      symbol: )
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 32
+                                        line: 1
+                                        character: 33
+                                      end_position:
+                                        bytes: 33
+                                        line: 1
+                                        character: 34
+                                      token_type:
+                                        type: Whitespace
+                                        characters: " "
+                            arguments:
+                              pairs:
+                                - End:
+                                    Var:
+                                      Name:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 26
+                                            line: 1
+                                            character: 27
+                                          end_position:
+                                            bytes: 31
+                                            line: 1
+                                            character: 32
+                                          token_type:
+                                            type: Identifier
+                                            identifier: index
+                                        trailing_trivia: []
+              - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 33
+              line: 1
+              character: 34
+            end_position:
+              bytes: 36
+              line: 1
+              character: 37
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 36
+                line: 1
+                character: 37
+              end_position:
+                bytes: 37
+                line: 1
+                character: 37
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
+  - - NumericFor:
+        for_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: for
+          trailing_trivia:
+            - start_position:
+                bytes: 40
+                line: 2
+                character: 4
+              end_position:
+                bytes: 41
+                line: 2
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        index_variable:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 41
+              line: 2
+              character: 5
+            end_position:
+              bytes: 42
+              line: 2
+              character: 6
+            token_type:
+              type: Identifier
+              identifier: _
+          trailing_trivia:
+            - start_position:
+                bytes: 42
+                line: 2
+                character: 6
+              end_position:
+                bytes: 43
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 43
+              line: 2
+              character: 7
+            end_position:
+              bytes: 44
+              line: 2
+              character: 8
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 44
+                line: 2
+                character: 8
+              end_position:
+                bytes: 45
+                line: 2
+                character: 9
+              token_type:
+                type: Whitespace
+                characters: " "
+        start:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 45
+                  line: 2
+                  character: 9
+                end_position:
+                  bytes: 50
+                  line: 2
+                  character: 14
+                token_type:
+                  type: Identifier
+                  identifier: start
+              trailing_trivia: []
+        start_end_comma:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 50
+              line: 2
+              character: 14
+            end_position:
+              bytes: 51
+              line: 2
+              character: 15
+            token_type:
+              type: Symbol
+              symbol: ","
+          trailing_trivia:
+            - start_position:
+                bytes: 51
+                line: 2
+                character: 15
+              end_position:
+                bytes: 52
+                line: 2
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        end:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 52
+                  line: 2
+                  character: 16
+                end_position:
+                  bytes: 57
+                  line: 2
+                  character: 21
+                token_type:
+                  type: Identifier
+                  identifier: final
+              trailing_trivia:
+                - start_position:
+                    bytes: 57
+                    line: 2
+                    character: 21
+                  end_position:
+                    bytes: 58
+                    line: 2
+                    character: 22
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+        end_step_comma: ~
+        step: ~
+        do_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 58
+              line: 2
+              character: 22
+            end_position:
+              bytes: 60
+              line: 2
+              character: 24
+            token_type:
+              type: Symbol
+              symbol: do
+          trailing_trivia:
+            - start_position:
+                bytes: 60
+                line: 2
+                character: 24
+              end_position:
+                bytes: 61
+                line: 2
+                character: 25
+              token_type:
+                type: Whitespace
+                characters: " "
+        block:
+          stmts: []
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 61
+              line: 2
+              character: 25
+            end_position:
+              bytes: 64
+              line: 2
+              character: 28
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 64
+                line: 2
+                character: 28
+              end_position:
+                bytes: 65
+                line: 2
+                character: 28
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
+  - - NumericFor:
+        for_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 65
+              line: 3
+              character: 1
+            end_position:
+              bytes: 68
+              line: 3
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: for
+          trailing_trivia:
+            - start_position:
+                bytes: 68
+                line: 3
+                character: 4
+              end_position:
+                bytes: 69
+                line: 3
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        index_variable:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 69
+              line: 3
+              character: 5
+            end_position:
+              bytes: 70
+              line: 3
+              character: 6
+            token_type:
+              type: Identifier
+              identifier: _
+          trailing_trivia:
+            - start_position:
+                bytes: 70
+                line: 3
+                character: 6
+              end_position:
+                bytes: 71
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 71
+              line: 3
+              character: 7
+            end_position:
+              bytes: 72
+              line: 3
+              character: 8
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 72
+                line: 3
+                character: 8
+              end_position:
+                bytes: 73
+                line: 3
+                character: 9
+              token_type:
+                type: Whitespace
+                characters: " "
+        start:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 73
+                line: 3
+                character: 9
+              end_position:
+                bytes: 74
+                line: 3
+                character: 10
+              token_type:
+                type: Number
+                text: "1"
+            trailing_trivia: []
+        start_end_comma:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 74
+              line: 3
+              character: 10
+            end_position:
+              bytes: 75
+              line: 3
+              character: 11
+            token_type:
+              type: Symbol
+              symbol: ","
+          trailing_trivia:
+            - start_position:
+                bytes: 75
+                line: 3
+                character: 11
+              end_position:
+                bytes: 76
+                line: 3
+                character: 12
+              token_type:
+                type: Whitespace
+                characters: " "
+        end:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 76
+                line: 3
+                character: 12
+              end_position:
+                bytes: 78
+                line: 3
+                character: 14
+              token_type:
+                type: Number
+                text: "10"
+            trailing_trivia: []
+        end_step_comma:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 78
+              line: 3
+              character: 14
+            end_position:
+              bytes: 79
+              line: 3
+              character: 15
+            token_type:
+              type: Symbol
+              symbol: ","
+          trailing_trivia:
+            - start_position:
+                bytes: 79
+                line: 3
+                character: 15
+              end_position:
+                bytes: 80
+                line: 3
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        step:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 80
+                line: 3
+                character: 16
+              end_position:
+                bytes: 81
+                line: 3
+                character: 17
+              token_type:
+                type: Number
+                text: "2"
+            trailing_trivia:
+              - start_position:
+                  bytes: 81
+                  line: 3
+                  character: 17
+                end_position:
+                  bytes: 82
+                  line: 3
+                  character: 18
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        do_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 82
+              line: 3
+              character: 18
+            end_position:
+              bytes: 84
+              line: 3
+              character: 20
+            token_type:
+              type: Symbol
+              symbol: do
+          trailing_trivia:
+            - start_position:
+                bytes: 84
+                line: 3
+                character: 20
+              end_position:
+                bytes: 85
+                line: 3
+                character: 21
+              token_type:
+                type: Whitespace
+                characters: " "
+        block:
+          stmts: []
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 85
+              line: 3
+              character: 21
+            end_position:
+              bytes: 88
+              line: 3
+              character: 24
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/numeric-for-loop/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/numeric-for-loop/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..7d940114bf1fdb9a5d14aa85472c1787d93ab400
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/numeric-for-loop/source.lua
@@ -0,0 +1,3 @@
+for index = 1, 10 do call(index) end
+for _ = start, final do end
+for _ = 1, 10, 2 do end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/numeric-for-loop/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/numeric-for-loop/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8abf9e6e295bd5b31231791944df17a3907294a8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/numeric-for-loop/tokens.snap
@@ -0,0 +1,589 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/numeric-for-loop
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: index
+- 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: 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: Number
+    text: "1"
+- 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: Number
+    text: "10"
+- 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: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 21
+    line: 1
+    character: 22
+  end_position:
+    bytes: 25
+    line: 1
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: call
+- 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: 31
+    line: 1
+    character: 32
+  token_type:
+    type: Identifier
+    identifier: index
+- start_position:
+    bytes: 31
+    line: 1
+    character: 32
+  end_position:
+    bytes: 32
+    line: 1
+    character: 33
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 32
+    line: 1
+    character: 33
+  end_position:
+    bytes: 33
+    line: 1
+    character: 34
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 33
+    line: 1
+    character: 34
+  end_position:
+    bytes: 36
+    line: 1
+    character: 37
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 36
+    line: 1
+    character: 37
+  end_position:
+    bytes: 37
+    line: 1
+    character: 37
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 37
+    line: 2
+    character: 1
+  end_position:
+    bytes: 40
+    line: 2
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- start_position:
+    bytes: 40
+    line: 2
+    character: 4
+  end_position:
+    bytes: 41
+    line: 2
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 41
+    line: 2
+    character: 5
+  end_position:
+    bytes: 42
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: _
+- start_position:
+    bytes: 42
+    line: 2
+    character: 6
+  end_position:
+    bytes: 43
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 43
+    line: 2
+    character: 7
+  end_position:
+    bytes: 44
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 44
+    line: 2
+    character: 8
+  end_position:
+    bytes: 45
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 45
+    line: 2
+    character: 9
+  end_position:
+    bytes: 50
+    line: 2
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: start
+- start_position:
+    bytes: 50
+    line: 2
+    character: 14
+  end_position:
+    bytes: 51
+    line: 2
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 51
+    line: 2
+    character: 15
+  end_position:
+    bytes: 52
+    line: 2
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 52
+    line: 2
+    character: 16
+  end_position:
+    bytes: 57
+    line: 2
+    character: 21
+  token_type:
+    type: Identifier
+    identifier: final
+- start_position:
+    bytes: 57
+    line: 2
+    character: 21
+  end_position:
+    bytes: 58
+    line: 2
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 58
+    line: 2
+    character: 22
+  end_position:
+    bytes: 60
+    line: 2
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 60
+    line: 2
+    character: 24
+  end_position:
+    bytes: 61
+    line: 2
+    character: 25
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 61
+    line: 2
+    character: 25
+  end_position:
+    bytes: 64
+    line: 2
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 64
+    line: 2
+    character: 28
+  end_position:
+    bytes: 65
+    line: 2
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 65
+    line: 3
+    character: 1
+  end_position:
+    bytes: 68
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- start_position:
+    bytes: 68
+    line: 3
+    character: 4
+  end_position:
+    bytes: 69
+    line: 3
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 69
+    line: 3
+    character: 5
+  end_position:
+    bytes: 70
+    line: 3
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: _
+- start_position:
+    bytes: 70
+    line: 3
+    character: 6
+  end_position:
+    bytes: 71
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 71
+    line: 3
+    character: 7
+  end_position:
+    bytes: 72
+    line: 3
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 72
+    line: 3
+    character: 8
+  end_position:
+    bytes: 73
+    line: 3
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 73
+    line: 3
+    character: 9
+  end_position:
+    bytes: 74
+    line: 3
+    character: 10
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 74
+    line: 3
+    character: 10
+  end_position:
+    bytes: 75
+    line: 3
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 75
+    line: 3
+    character: 11
+  end_position:
+    bytes: 76
+    line: 3
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 76
+    line: 3
+    character: 12
+  end_position:
+    bytes: 78
+    line: 3
+    character: 14
+  token_type:
+    type: Number
+    text: "10"
+- start_position:
+    bytes: 78
+    line: 3
+    character: 14
+  end_position:
+    bytes: 79
+    line: 3
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 79
+    line: 3
+    character: 15
+  end_position:
+    bytes: 80
+    line: 3
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 80
+    line: 3
+    character: 16
+  end_position:
+    bytes: 81
+    line: 3
+    character: 17
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 81
+    line: 3
+    character: 17
+  end_position:
+    bytes: 82
+    line: 3
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 82
+    line: 3
+    character: 18
+  end_position:
+    bytes: 84
+    line: 3
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 84
+    line: 3
+    character: 20
+  end_position:
+    bytes: 85
+    line: 3
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 85
+    line: 3
+    character: 21
+  end_position:
+    bytes: 88
+    line: 3
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 88
+    line: 3
+    character: 24
+  end_position:
+    bytes: 88
+    line: 3
+    character: 24
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/paren-expressions/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/paren-expressions/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3da56a49ab45fa2eb4c96dec3013e83cd377c301
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/paren-expressions/ast.snap
@@ -0,0 +1,252 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/paren-expressions
+---
+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:
+                BinaryOperator:
+                  lhs:
+                    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:
+                        - start_position:
+                            bytes: 11
+                            line: 1
+                            character: 12
+                          end_position:
+                            bytes: 12
+                            line: 1
+                            character: 13
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  binop:
+                    Plus:
+                      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: " "
+                  rhs:
+                    Parentheses:
+                      contained:
+                        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: 20
+                                line: 1
+                                character: 21
+                              end_position:
+                                bytes: 21
+                                line: 1
+                                character: 22
+                              token_type:
+                                type: Symbol
+                                symbol: )
+                            trailing_trivia: []
+                      expression:
+                        BinaryOperator:
+                          lhs:
+                            Number:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 15
+                                  line: 1
+                                  character: 16
+                                end_position:
+                                  bytes: 16
+                                  line: 1
+                                  character: 17
+                                token_type:
+                                  type: Number
+                                  text: "2"
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 16
+                                    line: 1
+                                    character: 17
+                                  end_position:
+                                    bytes: 17
+                                    line: 1
+                                    character: 18
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                          binop:
+                            Minus:
+                              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: " "
+                          rhs:
+                            Number:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 19
+                                  line: 1
+                                  character: 20
+                                end_position:
+                                  bytes: 20
+                                  line: 1
+                                  character: 21
+                                token_type:
+                                  type: Number
+                                  text: "3"
+                              trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/paren-expressions/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/paren-expressions/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..58013466ec37f5a50f181e33f332c25dd240d764
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/paren-expressions/source.lua
@@ -0,0 +1 @@
+local x = 1 + (2 - 3)
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/paren-expressions/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/paren-expressions/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..93d1a56d6ee03dbc7f29e9d5e247e632c012c122
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/paren-expressions/tokens.snap
@@ -0,0 +1,204 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/paren-expressions
+
+---
+- 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: Number
+    text: "1"
+- 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: 17
+  token_type:
+    type: Number
+    text: "2"
+- 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: 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: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Number
+    text: "3"
+- 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: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/repeat-until/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/repeat-until/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..119545d9581c2184ee4315d3430f400022cc8395
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/repeat-until/ast.snap
@@ -0,0 +1,157 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/repeat-until
+---
+stmts:
+  - - Repeat:
+        repeat_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: repeat
+          trailing_trivia:
+            - start_position:
+                bytes: 6
+                line: 1
+                character: 7
+              end_position:
+                bytes: 7
+                line: 1
+                character: 7
+              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: []
+              - ~
+        until_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 15
+              line: 3
+              character: 1
+            end_position:
+              bytes: 20
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: until
+          trailing_trivia:
+            - start_position:
+                bytes: 20
+                line: 3
+                character: 6
+              end_position:
+                bytes: 21
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        until:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 21
+                  line: 3
+                  character: 7
+                end_position:
+                  bytes: 30
+                  line: 3
+                  character: 16
+                token_type:
+                  type: Identifier
+                  identifier: condition
+              trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/repeat-until/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/repeat-until/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..e9b8e59278e2201a515311ae791e0d1119663f01
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/repeat-until/source.lua
@@ -0,0 +1,3 @@
+repeat
+	call()
+until condition
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/repeat-until/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/repeat-until/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6a469aeb1c8537f2fa100f3007822176410fd25f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/repeat-until/tokens.snap
@@ -0,0 +1,127 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/repeat-until
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: repeat
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 7
+    line: 2
+    character: 1
+  end_position:
+    bytes: 8
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 8
+    line: 2
+    character: 2
+  end_position:
+    bytes: 12
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 12
+    line: 2
+    character: 6
+  end_position:
+    bytes: 13
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 13
+    line: 2
+    character: 7
+  end_position:
+    bytes: 14
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 14
+    line: 2
+    character: 8
+  end_position:
+    bytes: 15
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 3
+    character: 1
+  end_position:
+    bytes: 20
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: until
+- start_position:
+    bytes: 20
+    line: 3
+    character: 6
+  end_position:
+    bytes: 21
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 21
+    line: 3
+    character: 7
+  end_position:
+    bytes: 30
+    line: 3
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: condition
+- start_position:
+    bytes: 30
+    line: 3
+    character: 16
+  end_position:
+    bytes: 30
+    line: 3
+    character: 16
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/return-break/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/return-break/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..eddce61d7f190e22e25a123791b2f8a9e30c7e61
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/return-break/ast.snap
@@ -0,0 +1,346 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/return-break
+---
+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: []
+          last_stmt:
+            - Return:
+                token:
+                  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: 10
+                      line: 2
+                      character: 8
+                    token_type:
+                      type: Symbol
+                      symbol: return
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 10
+                        line: 2
+                        character: 8
+                      end_position:
+                        bytes: 11
+                        line: 2
+                        character: 9
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+                returns:
+                  pairs:
+                    - End:
+                        Number:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 11
+                              line: 2
+                              character: 9
+                            end_position:
+                              bytes: 12
+                              line: 2
+                              character: 10
+                            token_type:
+                              type: Number
+                              text: "1"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 12
+                                line: 2
+                                character: 10
+                              end_position:
+                                bytes: 13
+                                line: 2
+                                character: 10
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+            - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 13
+              line: 3
+              character: 1
+            end_position:
+              bytes: 16
+              line: 3
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 16
+                line: 3
+                character: 4
+              end_position:
+                bytes: 17
+                line: 3
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
+  - - Do:
+        do_token:
+          leading_trivia:
+            - start_position:
+                bytes: 17
+                line: 4
+                character: 1
+              end_position:
+                bytes: 18
+                line: 4
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 18
+              line: 5
+              character: 1
+            end_position:
+              bytes: 20
+              line: 5
+              character: 3
+            token_type:
+              type: Symbol
+              symbol: do
+          trailing_trivia:
+            - start_position:
+                bytes: 20
+                line: 5
+                character: 3
+              end_position:
+                bytes: 21
+                line: 5
+                character: 3
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        block:
+          stmts: []
+          last_stmt:
+            - Break:
+                leading_trivia:
+                  - start_position:
+                      bytes: 21
+                      line: 6
+                      character: 1
+                    end_position:
+                      bytes: 22
+                      line: 6
+                      character: 2
+                    token_type:
+                      type: Whitespace
+                      characters: "\t"
+                token:
+                  start_position:
+                    bytes: 22
+                    line: 6
+                    character: 2
+                  end_position:
+                    bytes: 27
+                    line: 6
+                    character: 7
+                  token_type:
+                    type: Symbol
+                    symbol: break
+                trailing_trivia:
+                  - start_position:
+                      bytes: 27
+                      line: 6
+                      character: 7
+                    end_position:
+                      bytes: 28
+                      line: 6
+                      character: 7
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+            - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 28
+              line: 7
+              character: 1
+            end_position:
+              bytes: 31
+              line: 7
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 31
+                line: 7
+                character: 4
+              end_position:
+                bytes: 32
+                line: 7
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
+last_stmt:
+  - Return:
+      token:
+        leading_trivia:
+          - start_position:
+              bytes: 32
+              line: 8
+              character: 1
+            end_position:
+              bytes: 33
+              line: 8
+              character: 1
+            token_type:
+              type: Whitespace
+              characters: "\n"
+        token:
+          start_position:
+            bytes: 33
+            line: 9
+            character: 1
+          end_position:
+            bytes: 39
+            line: 9
+            character: 7
+          token_type:
+            type: Symbol
+            symbol: return
+        trailing_trivia:
+          - start_position:
+              bytes: 39
+              line: 9
+              character: 7
+            end_position:
+              bytes: 40
+              line: 9
+              character: 8
+            token_type:
+              type: Whitespace
+              characters: " "
+      returns:
+        pairs:
+          - End:
+              FunctionCall:
+                prefix:
+                  Name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 40
+                        line: 9
+                        character: 8
+                      end_position:
+                        bytes: 44
+                        line: 9
+                        character: 12
+                      token_type:
+                        type: Identifier
+                        identifier: call
+                    trailing_trivia: []
+                suffixes:
+                  - Call:
+                      AnonymousCall:
+                        Parentheses:
+                          parentheses:
+                            tokens:
+                              - leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 44
+                                    line: 9
+                                    character: 12
+                                  end_position:
+                                    bytes: 45
+                                    line: 9
+                                    character: 13
+                                  token_type:
+                                    type: Symbol
+                                    symbol: (
+                                trailing_trivia: []
+                              - leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 45
+                                    line: 9
+                                    character: 13
+                                  end_position:
+                                    bytes: 46
+                                    line: 9
+                                    character: 14
+                                  token_type:
+                                    type: Symbol
+                                    symbol: )
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 46
+                                      line: 9
+                                      character: 14
+                                    end_position:
+                                      bytes: 47
+                                      line: 9
+                                      character: 14
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "\n"
+                          arguments:
+                            pairs: []
+  - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/return-break/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/return-break/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..e0cf1504e36f78802b65885704de6750925f0cee
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/return-break/source.lua
@@ -0,0 +1,9 @@
+do
+	return 1
+end
+
+do
+	break
+end
+
+return call()
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/return-break/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/return-break/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1038c32af324abd8c84be33f3b9991c153de0b11
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/return-break/tokens.snap
@@ -0,0 +1,281 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/return-break
+
+---
+- 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: 4
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 4
+    line: 2
+    character: 2
+  end_position:
+    bytes: 10
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 10
+    line: 2
+    character: 8
+  end_position:
+    bytes: 11
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 11
+    line: 2
+    character: 9
+  end_position:
+    bytes: 12
+    line: 2
+    character: 10
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 12
+    line: 2
+    character: 10
+  end_position:
+    bytes: 13
+    line: 2
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 13
+    line: 3
+    character: 1
+  end_position:
+    bytes: 16
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 16
+    line: 3
+    character: 4
+  end_position:
+    bytes: 17
+    line: 3
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 17
+    line: 4
+    character: 1
+  end_position:
+    bytes: 18
+    line: 4
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 18
+    line: 5
+    character: 1
+  end_position:
+    bytes: 20
+    line: 5
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 20
+    line: 5
+    character: 3
+  end_position:
+    bytes: 21
+    line: 5
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 21
+    line: 6
+    character: 1
+  end_position:
+    bytes: 22
+    line: 6
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 22
+    line: 6
+    character: 2
+  end_position:
+    bytes: 27
+    line: 6
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: break
+- start_position:
+    bytes: 27
+    line: 6
+    character: 7
+  end_position:
+    bytes: 28
+    line: 6
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 28
+    line: 7
+    character: 1
+  end_position:
+    bytes: 31
+    line: 7
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 31
+    line: 7
+    character: 4
+  end_position:
+    bytes: 32
+    line: 7
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 32
+    line: 8
+    character: 1
+  end_position:
+    bytes: 33
+    line: 8
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 33
+    line: 9
+    character: 1
+  end_position:
+    bytes: 39
+    line: 9
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 39
+    line: 9
+    character: 7
+  end_position:
+    bytes: 40
+    line: 9
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 40
+    line: 9
+    character: 8
+  end_position:
+    bytes: 44
+    line: 9
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 44
+    line: 9
+    character: 12
+  end_position:
+    bytes: 45
+    line: 9
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 45
+    line: 9
+    character: 13
+  end_position:
+    bytes: 46
+    line: 9
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 46
+    line: 9
+    character: 14
+  end_position:
+    bytes: 47
+    line: 9
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 47
+    line: 10
+    character: 1
+  end_position:
+    bytes: 47
+    line: 10
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..04d72ebf735909fc449d0cfaca5a7409157120db
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-1/ast.snap
@@ -0,0 +1,264 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/semicolons-1
+---
+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: []
+    - 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: " "
+  - - Assignment:
+        var_list:
+          pairs:
+            - End:
+                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:
+                    - 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:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 17
+                            line: 1
+                            character: 18
+                          end_position:
+                            bytes: 18
+                            line: 1
+                            character: 19
+                          token_type:
+                            type: Identifier
+                            identifier: x
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 18
+                              line: 1
+                              character: 19
+                            end_position:
+                              bytes: 19
+                              line: 1
+                              character: 20
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  binop:
+                    Plus:
+                      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:
+                        - start_position:
+                            bytes: 20
+                            line: 1
+                            character: 21
+                          end_position:
+                            bytes: 21
+                            line: 1
+                            character: 22
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    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: "1"
+                      trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..60b7ec8f135bd3aa3491098a1d464165c82926dd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-1/source.lua
@@ -0,0 +1 @@
+local x = 1; x = x + 1
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..36c8231181107567f3338c6971648b78e42df2d9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-1/tokens.snap
@@ -0,0 +1,215 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/semicolons-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: 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: Number
+    text: "1"
+- 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: 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: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 18
+    line: 1
+    character: 19
+  end_position:
+    bytes: 19
+    line: 1
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 21
+    line: 1
+    character: 22
+  end_position:
+    bytes: 22
+    line: 1
+    character: 23
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 22
+    line: 1
+    character: 23
+  end_position:
+    bytes: 22
+    line: 1
+    character: 23
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8424289c70984e2a9836c70d0361447db0d7ea9c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-2/ast.snap
@@ -0,0 +1,180 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/semicolons-2
+---
+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:
+                    - start_position:
+                        bytes: 11
+                        line: 1
+                        character: 12
+                      end_position:
+                        bytes: 12
+                        line: 1
+                        character: 12
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+last_stmt:
+  - Return:
+      token:
+        leading_trivia: []
+        token:
+          start_position:
+            bytes: 12
+            line: 2
+            character: 1
+          end_position:
+            bytes: 18
+            line: 2
+            character: 7
+          token_type:
+            type: Symbol
+            symbol: return
+        trailing_trivia:
+          - start_position:
+              bytes: 18
+              line: 2
+              character: 7
+            end_position:
+              bytes: 19
+              line: 2
+              character: 8
+            token_type:
+              type: Whitespace
+              characters: " "
+      returns:
+        pairs:
+          - End:
+              Var:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 19
+                      line: 2
+                      character: 8
+                    end_position:
+                      bytes: 20
+                      line: 2
+                      character: 9
+                    token_type:
+                      type: Identifier
+                      identifier: x
+                  trailing_trivia: []
+  - leading_trivia: []
+    token:
+      start_position:
+        bytes: 20
+        line: 2
+        character: 9
+      end_position:
+        bytes: 21
+        line: 2
+        character: 10
+      token_type:
+        type: Symbol
+        symbol: ;
+    trailing_trivia: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..ad92d12511cd5d66b4e2914a23561a3be7f13423
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-2/source.lua
@@ -0,0 +1,2 @@
+local x = 1
+return x;
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ba27d4cb0b7103dc57922d8f1104039cd96872ff
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/semicolons-2/tokens.snap
@@ -0,0 +1,149 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/semicolons-2
+
+---
+- 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: Number
+    text: "1"
+- 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: 18
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 18
+    line: 2
+    character: 7
+  end_position:
+    bytes: 19
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 19
+    line: 2
+    character: 8
+  end_position:
+    bytes: 20
+    line: 2
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: x
+- 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: 21
+    line: 2
+    character: 10
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/shebang/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/shebang/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6b4590333049feafefbfb897ea61556ced598168
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/shebang/ast.snap
@@ -0,0 +1,136 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 47
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/shebang
+---
+stmts:
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia:
+              - start_position:
+                  bytes: 0
+                  line: 1
+                  character: 1
+                end_position:
+                  bytes: 18
+                  line: 1
+                  character: 19
+                token_type:
+                  type: Shebang
+                  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
+                  character: 1
+                end_position:
+                  bytes: 20
+                  line: 2
+                  character: 1
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+            token:
+              start_position:
+                bytes: 20
+                line: 3
+                character: 1
+              end_position:
+                bytes: 25
+                line: 3
+                character: 6
+              token_type:
+                type: Identifier
+                identifier: print
+            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: 39
+                            line: 3
+                            character: 20
+                          end_position:
+                            bytes: 40
+                            line: 3
+                            character: 21
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia: []
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 26
+                                line: 3
+                                character: 7
+                              end_position:
+                                bytes: 39
+                                line: 3
+                                character: 20
+                              token_type:
+                                type: StringLiteral
+                                literal: Hello world
+                                quote_type: Double
+                            trailing_trivia: []
+    - leading_trivia: []
+      token:
+        start_position:
+          bytes: 40
+          line: 3
+          character: 21
+        end_position:
+          bytes: 41
+          line: 3
+          character: 22
+        token_type:
+          type: Symbol
+          symbol: ;
+      trailing_trivia:
+        - start_position:
+            bytes: 41
+            line: 3
+            character: 22
+          end_position:
+            bytes: 42
+            line: 3
+            character: 22
+          token_type:
+            type: Whitespace
+            characters: "\n"
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/shebang/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/shebang/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..202a2c86e15e42f6f9c9e03fed3d29e8d8dae8c8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/shebang/source.lua
@@ -0,0 +1,3 @@
+#!/usr/bin/env lua
+
+print("Hello world");
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/shebang/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/shebang/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2cea764348cbc7e655b2504790775de59ffda207
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/shebang/tokens.snap
@@ -0,0 +1,117 @@
+---
+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: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Shebang
+    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
+    character: 1
+  end_position:
+    bytes: 20
+    line: 2
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 20
+    line: 3
+    character: 1
+  end_position:
+    bytes: 25
+    line: 3
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: print
+- start_position:
+    bytes: 25
+    line: 3
+    character: 6
+  end_position:
+    bytes: 26
+    line: 3
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 26
+    line: 3
+    character: 7
+  end_position:
+    bytes: 39
+    line: 3
+    character: 20
+  token_type:
+    type: StringLiteral
+    literal: Hello world
+    quote_type: Double
+- start_position:
+    bytes: 39
+    line: 3
+    character: 20
+  end_position:
+    bytes: 40
+    line: 3
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 40
+    line: 3
+    character: 21
+  end_position:
+    bytes: 41
+    line: 3
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: ;
+- start_position:
+    bytes: 41
+    line: 3
+    character: 22
+  end_position:
+    bytes: 42
+    line: 3
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 42
+    line: 4
+    character: 1
+  end_position:
+    bytes: 42
+    line: 4
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1dda28e0b207b4c17cdb61f34a01e04b54a9a083
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-1/ast.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/single-line-comment-1
+
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..4a7ee141c49a52b2f2739210707f43a7310355a9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-1/source.lua
@@ -0,0 +1,2 @@
+-- hello world
+-- and doge you too
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..92ea695756ef17487b11d691a6a0e93ed1089be9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-1/tokens.snap
@@ -0,0 +1,50 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/single-line-comment-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 14
+    line: 1
+    character: 15
+  token_type:
+    type: SingleLineComment
+    comment: " hello world"
+- start_position:
+    bytes: 14
+    line: 1
+    character: 15
+  end_position:
+    bytes: 15
+    line: 1
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 2
+    character: 1
+  end_position:
+    bytes: 34
+    line: 2
+    character: 20
+  token_type:
+    type: SingleLineComment
+    comment: " and doge you too"
+- start_position:
+    bytes: 34
+    line: 2
+    character: 20
+  end_position:
+    bytes: 34
+    line: 2
+    character: 20
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..540e9bccbf9df50b8ad3d093fa04a3a858b74488
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-2/ast.snap
@@ -0,0 +1,84 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/single-line-comment-2
+
+---
+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: 5
+                            line: 1
+                            character: 6
+                          end_position:
+                            bytes: 6
+                            line: 1
+                            character: 7
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 6
+                              line: 1
+                              character: 7
+                            end_position:
+                              bytes: 7
+                              line: 1
+                              character: 8
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                          - start_position:
+                              bytes: 7
+                              line: 1
+                              character: 8
+                            end_position:
+                              bytes: 20
+                              line: 1
+                              character: 21
+                            token_type:
+                              type: SingleLineComment
+                              comment: " This calls"
+                  arguments:
+                    pairs: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2e1eecc9fcb42da193486c34b177f3c29c729135
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-2/source.lua
@@ -0,0 +1 @@
+call() -- This calls
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..37c9362a1a0fc37cd4c6a5cffebf7c64b0fe8f3d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-2/tokens.snap
@@ -0,0 +1,72 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/single-line-comment-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: SingleLineComment
+    comment: " This calls"
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cb7ae8e84550a536b014fa2ef774a04ef1b61d80
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-3/ast.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/single-line-comment-3
+
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..d83f9542073df80182e05ec677b7601d1b45c815
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-3/source.lua
@@ -0,0 +1 @@
+-- tab	in comment
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3405d41f1ec1b7bc89caf7a5abcd269e113d3ebb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-3/tokens.snap
@@ -0,0 +1,28 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/single-line-comment-3
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 17
+    line: 1
+    character: 18
+  token_type:
+    type: SingleLineComment
+    comment: " tab\tin comment"
+- start_position:
+    bytes: 17
+    line: 1
+    character: 18
+  end_position:
+    bytes: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1ffe9aa9560f459349f69f5025b53b98a93c0bc5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-4/ast.snap
@@ -0,0 +1,8 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/single-line-comment-4
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..597200730a199752fcd4801d4922431e190cfe19
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-4/source.lua
@@ -0,0 +1,4 @@
+--[comment
+--(comment)
+--[=comment
+--
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e016797aa3785d1cf1ce9198cad3ae4cc7659db9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-4/tokens.snap
@@ -0,0 +1,105 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 38
+expression: tokens
+input_file: full-moon/tests/cases/pass/single-line-comment-4
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 10
+    line: 1
+    character: 11
+  token_type:
+    type: SingleLineComment
+    comment: "[comment"
+- start_position:
+    bytes: 10
+    line: 1
+    character: 11
+  end_position:
+    bytes: 11
+    line: 1
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 11
+    line: 2
+    character: 1
+  end_position:
+    bytes: 22
+    line: 2
+    character: 12
+  token_type:
+    type: SingleLineComment
+    comment: (comment)
+- start_position:
+    bytes: 22
+    line: 2
+    character: 12
+  end_position:
+    bytes: 23
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 23
+    line: 3
+    character: 1
+  end_position:
+    bytes: 34
+    line: 3
+    character: 12
+  token_type:
+    type: SingleLineComment
+    comment: "[=comment"
+- start_position:
+    bytes: 34
+    line: 3
+    character: 12
+  end_position:
+    bytes: 35
+    line: 3
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 35
+    line: 4
+    character: 1
+  end_position:
+    bytes: 37
+    line: 4
+    character: 3
+  token_type:
+    type: SingleLineComment
+    comment: ""
+- start_position:
+    bytes: 37
+    line: 4
+    character: 3
+  end_position:
+    bytes: 38
+    line: 4
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 38
+    line: 5
+    character: 1
+  end_position:
+    bytes: 38
+    line: 5
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..25ffa7323eae88bca773ee1d24c72dc04738b805
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-5/ast.snap
@@ -0,0 +1,7 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2e983ada42af991e5711cfdbcd09a480cb2db9b4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-5/source.lua
@@ -0,0 +1,2 @@
+--`signatures` the value defaults to zero or is ignored if `signatures.length
+--=== 0`. Whenever possible implementors should make an active decision about
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f17080eb48eb15bbbe589da3861fa2f53b524838
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-5/tokens.snap
@@ -0,0 +1,49 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 38
+expression: tokens
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 77
+    line: 1
+    character: 78
+  token_type:
+    type: SingleLineComment
+    comment: "`signatures` the value defaults to zero or is ignored if `signatures.length"
+- start_position:
+    bytes: 77
+    line: 1
+    character: 78
+  end_position:
+    bytes: 78
+    line: 1
+    character: 78
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 78
+    line: 2
+    character: 1
+  end_position:
+    bytes: 155
+    line: 2
+    character: 78
+  token_type:
+    type: SingleLineComment
+    comment: "=== 0`. Whenever possible implementors should make an active decision about"
+- start_position:
+    bytes: 155
+    line: 2
+    character: 78
+  end_position:
+    bytes: 155
+    line: 2
+    character: 78
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-6/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-6/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..25ffa7323eae88bca773ee1d24c72dc04738b805
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-6/ast.snap
@@ -0,0 +1,7 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+---
+stmts: []
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-6/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-6/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f822b93c6e2a069efe9627a794f7a850d30e0506
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-6/source.lua
@@ -0,0 +1 @@
+--随便写点中文
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-6/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-6/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..223fb990f5cfa9bd319638ce8c5a4f32b2d52998
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-6/tokens.snap
@@ -0,0 +1,39 @@
+---
+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
+    line: 1
+    character: 1
+  end_position:
+    bytes: 20
+    line: 1
+    character: 9
+  token_type:
+    type: SingleLineComment
+    comment: 随便写点中文
+- start_position:
+    bytes: 20
+    line: 1
+    character: 9
+  end_position:
+    bytes: 21
+    line: 1
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 21
+    line: 2
+    character: 1
+  end_position:
+    bytes: 21
+    line: 2
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-7/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-7/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..640d51b6f2e7b0491604561806e6fd4746b29d28
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-7/ast.snap
@@ -0,0 +1,119 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/single-line-comment-7
+---
+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: a
+                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:
+                    - start_position:
+                        bytes: 11
+                        line: 1
+                        character: 12
+                      end_position:
+                        bytes: 12
+                        line: 1
+                        character: 12
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-7/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-7/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2f5cb16638a4ecb10caf6ed3a52ca82e0f02773a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-7/source.lua
@@ -0,0 +1,3 @@
+local a = 1
+
+--}}封装方便访问的接口==========================================
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-7/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-7/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..87f28442323e4895dc087881fbdd3b07b21b71ff
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/single-line-comment-7/tokens.snap
@@ -0,0 +1,127 @@
+---
+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
+    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: a
+- 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: Number
+    text: "1"
+- 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: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 13
+    line: 3
+    character: 1
+  end_position:
+    bytes: 86
+    line: 3
+    character: 56
+  token_type:
+    type: SingleLineComment
+    comment: "}}封装方便访问的接口=========================================="
+- start_position:
+    bytes: 86
+    line: 3
+    character: 56
+  end_position:
+    bytes: 86
+    line: 3
+    character: 56
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape-newline/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape-newline/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d36adc4ba7f808ec1ce7a2d54f564eb9fa58f2bf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape-newline/ast.snap
@@ -0,0 +1,90 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/strings-escape-newline
+---
+stmts:
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 0
+                line: 1
+                character: 1
+              end_position:
+                bytes: 5
+                line: 1
+                character: 6
+              token_type:
+                type: Identifier
+                identifier: print
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 5
+                            line: 1
+                            character: 6
+                          end_position:
+                            bytes: 6
+                            line: 1
+                            character: 7
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 17
+                            line: 2
+                            character: 6
+                          end_position:
+                            bytes: 18
+                            line: 2
+                            character: 7
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 18
+                              line: 2
+                              character: 7
+                            end_position:
+                              bytes: 19
+                              line: 2
+                              character: 7
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 6
+                                line: 1
+                                character: 7
+                              end_position:
+                                bytes: 17
+                                line: 2
+                                character: 6
+                              token_type:
+                                type: StringLiteral
+                                literal: "foo\\\n\tbar"
+                                quote_type: Double
+                            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape-newline/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape-newline/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..4ed7bf4c4a398d78e427190db476beae86c4e083
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape-newline/source.lua
@@ -0,0 +1,2 @@
+print("foo\
+	bar")
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape-newline/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape-newline/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..173ab55cdc8312d902e796f6daa0000241d241fa
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape-newline/tokens.snap
@@ -0,0 +1,73 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/strings-escape-newline
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: print
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 17
+    line: 2
+    character: 6
+  token_type:
+    type: StringLiteral
+    literal: "foo\\\n\tbar"
+    quote_type: Double
+- 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: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 19
+    line: 3
+    character: 1
+  end_position:
+    bytes: 19
+    line: 3
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f1cdb6c7e25c7897f3493cd38cdf37066b02b0c3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape/ast.snap
@@ -0,0 +1,385 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/strings-escape
+---
+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: 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: 11
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 5
+                                line: 1
+                                character: 6
+                              end_position:
+                                bytes: 9
+                                line: 1
+                                character: 10
+                              token_type:
+                                type: StringLiteral
+                                literal: "\\\\"
+                                quote_type: Single
+                            trailing_trivia: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 11
+                line: 2
+                character: 1
+              end_position:
+                bytes: 15
+                line: 2
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 15
+                            line: 2
+                            character: 5
+                          end_position:
+                            bytes: 16
+                            line: 2
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 20
+                            line: 2
+                            character: 10
+                          end_position:
+                            bytes: 21
+                            line: 2
+                            character: 11
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 21
+                              line: 2
+                              character: 11
+                            end_position:
+                              bytes: 22
+                              line: 2
+                              character: 11
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 16
+                                line: 2
+                                character: 6
+                              end_position:
+                                bytes: 20
+                                line: 2
+                                character: 10
+                              token_type:
+                                type: StringLiteral
+                                literal: "\\\\"
+                                quote_type: Double
+                            trailing_trivia: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 22
+                line: 3
+                character: 1
+              end_position:
+                bytes: 26
+                line: 3
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 26
+                            line: 3
+                            character: 5
+                          end_position:
+                            bytes: 27
+                            line: 3
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 42
+                            line: 3
+                            character: 21
+                          end_position:
+                            bytes: 43
+                            line: 3
+                            character: 22
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia: []
+                  arguments:
+                    pairs:
+                      - End:
+                          TableConstructor:
+                            braces:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 27
+                                      line: 3
+                                      character: 6
+                                    end_position:
+                                      bytes: 28
+                                      line: 3
+                                      character: 7
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "{"
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 28
+                                        line: 3
+                                        character: 7
+                                      end_position:
+                                        bytes: 29
+                                        line: 3
+                                        character: 8
+                                      token_type:
+                                        type: Whitespace
+                                        characters: " "
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 41
+                                      line: 3
+                                      character: 20
+                                    end_position:
+                                      bytes: 42
+                                      line: 3
+                                      character: 21
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "}"
+                                  trailing_trivia: []
+                            fields:
+                              pairs:
+                                - End:
+                                    ExpressionKey:
+                                      brackets:
+                                        tokens:
+                                          - leading_trivia: []
+                                            token:
+                                              start_position:
+                                                bytes: 29
+                                                line: 3
+                                                character: 8
+                                              end_position:
+                                                bytes: 30
+                                                line: 3
+                                                character: 9
+                                              token_type:
+                                                type: Symbol
+                                                symbol: "["
+                                            trailing_trivia: []
+                                          - leading_trivia: []
+                                            token:
+                                              start_position:
+                                                bytes: 34
+                                                line: 3
+                                                character: 13
+                                              end_position:
+                                                bytes: 35
+                                                line: 3
+                                                character: 14
+                                              token_type:
+                                                type: Symbol
+                                                symbol: "]"
+                                            trailing_trivia:
+                                              - start_position:
+                                                  bytes: 35
+                                                  line: 3
+                                                  character: 14
+                                                end_position:
+                                                  bytes: 36
+                                                  line: 3
+                                                  character: 15
+                                                token_type:
+                                                  type: Whitespace
+                                                  characters: " "
+                                      key:
+                                        String:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 30
+                                              line: 3
+                                              character: 9
+                                            end_position:
+                                              bytes: 34
+                                              line: 3
+                                              character: 13
+                                            token_type:
+                                              type: StringLiteral
+                                              literal: "\\\\"
+                                              quote_type: Double
+                                          trailing_trivia: []
+                                      equal:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 36
+                                            line: 3
+                                            character: 15
+                                          end_position:
+                                            bytes: 37
+                                            line: 3
+                                            character: 16
+                                          token_type:
+                                            type: Symbol
+                                            symbol: "="
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 37
+                                              line: 3
+                                              character: 16
+                                            end_position:
+                                              bytes: 38
+                                              line: 3
+                                              character: 17
+                                            token_type:
+                                              type: Whitespace
+                                              characters: " "
+                                      value:
+                                        String:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 38
+                                              line: 3
+                                              character: 17
+                                            end_position:
+                                              bytes: 40
+                                              line: 3
+                                              character: 19
+                                            token_type:
+                                              type: StringLiteral
+                                              literal: ""
+                                              quote_type: Double
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 40
+                                                line: 3
+                                                character: 19
+                                              end_position:
+                                                bytes: 41
+                                                line: 3
+                                                character: 20
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..5c2e4f13d231361933cbae8755a71218b113c259
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape/source.lua
@@ -0,0 +1,3 @@
+call('\\')
+call("\\")
+call({ ["\\"] = "" })
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b5501309d80ac54e702558312504a3d54f33ba5f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/strings-escape/tokens.snap
@@ -0,0 +1,284 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 38
+expression: tokens
+input_file: full-moon/tests/cases/pass/strings-escape
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 9
+    line: 1
+    character: 10
+  token_type:
+    type: StringLiteral
+    literal: "\\\\"
+    quote_type: Single
+- 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: 11
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 11
+    line: 2
+    character: 1
+  end_position:
+    bytes: 15
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 15
+    line: 2
+    character: 5
+  end_position:
+    bytes: 16
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 16
+    line: 2
+    character: 6
+  end_position:
+    bytes: 20
+    line: 2
+    character: 10
+  token_type:
+    type: StringLiteral
+    literal: "\\\\"
+    quote_type: Double
+- start_position:
+    bytes: 20
+    line: 2
+    character: 10
+  end_position:
+    bytes: 21
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 21
+    line: 2
+    character: 11
+  end_position:
+    bytes: 22
+    line: 2
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 22
+    line: 3
+    character: 1
+  end_position:
+    bytes: 26
+    line: 3
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 26
+    line: 3
+    character: 5
+  end_position:
+    bytes: 27
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 27
+    line: 3
+    character: 6
+  end_position:
+    bytes: 28
+    line: 3
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 28
+    line: 3
+    character: 7
+  end_position:
+    bytes: 29
+    line: 3
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 29
+    line: 3
+    character: 8
+  end_position:
+    bytes: 30
+    line: 3
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 30
+    line: 3
+    character: 9
+  end_position:
+    bytes: 34
+    line: 3
+    character: 13
+  token_type:
+    type: StringLiteral
+    literal: "\\\\"
+    quote_type: Double
+- start_position:
+    bytes: 34
+    line: 3
+    character: 13
+  end_position:
+    bytes: 35
+    line: 3
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 35
+    line: 3
+    character: 14
+  end_position:
+    bytes: 36
+    line: 3
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 36
+    line: 3
+    character: 15
+  end_position:
+    bytes: 37
+    line: 3
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 37
+    line: 3
+    character: 16
+  end_position:
+    bytes: 38
+    line: 3
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 38
+    line: 3
+    character: 17
+  end_position:
+    bytes: 40
+    line: 3
+    character: 19
+  token_type:
+    type: StringLiteral
+    literal: ""
+    quote_type: Double
+- start_position:
+    bytes: 40
+    line: 3
+    character: 19
+  end_position:
+    bytes: 41
+    line: 3
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 41
+    line: 3
+    character: 20
+  end_position:
+    bytes: 42
+    line: 3
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 42
+    line: 3
+    character: 21
+  end_position:
+    bytes: 43
+    line: 3
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 43
+    line: 3
+    character: 22
+  end_position:
+    bytes: 43
+    line: 3
+    character: 22
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/strings/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/strings/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4a9bf05e5a8754368737630fb89cf4f04172ba43
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/strings/ast.snap
@@ -0,0 +1,325 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/strings
+---
+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: 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: 15
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 5
+                                line: 1
+                                character: 6
+                              end_position:
+                                bytes: 13
+                                line: 1
+                                character: 14
+                              token_type:
+                                type: StringLiteral
+                                literal: double
+                                quote_type: Double
+                            trailing_trivia: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 15
+                line: 2
+                character: 1
+              end_position:
+                bytes: 19
+                line: 2
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 19
+                            line: 2
+                            character: 5
+                          end_position:
+                            bytes: 20
+                            line: 2
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 28
+                            line: 2
+                            character: 14
+                          end_position:
+                            bytes: 29
+                            line: 2
+                            character: 15
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 29
+                              line: 2
+                              character: 15
+                            end_position:
+                              bytes: 30
+                              line: 2
+                              character: 15
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 20
+                                line: 2
+                                character: 6
+                              end_position:
+                                bytes: 28
+                                line: 2
+                                character: 14
+                              token_type:
+                                type: StringLiteral
+                                literal: single
+                                quote_type: Single
+                            trailing_trivia: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 30
+                line: 3
+                character: 1
+              end_position:
+                bytes: 34
+                line: 3
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 34
+                            line: 3
+                            character: 5
+                          end_position:
+                            bytes: 35
+                            line: 3
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 45
+                            line: 3
+                            character: 16
+                          end_position:
+                            bytes: 46
+                            line: 3
+                            character: 17
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 46
+                              line: 3
+                              character: 17
+                            end_position:
+                              bytes: 47
+                              line: 3
+                              character: 17
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 35
+                                line: 3
+                                character: 6
+                              end_position:
+                                bytes: 45
+                                line: 3
+                                character: 16
+                              token_type:
+                                type: StringLiteral
+                                literal: "foo\\nbar"
+                                quote_type: Double
+                            trailing_trivia: []
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 47
+                line: 4
+                character: 1
+              end_position:
+                bytes: 51
+                line: 4
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: call
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 51
+                            line: 4
+                            character: 5
+                          end_position:
+                            bytes: 52
+                            line: 4
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 54
+                            line: 4
+                            character: 8
+                          end_position:
+                            bytes: 55
+                            line: 4
+                            character: 9
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia: []
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 52
+                                line: 4
+                                character: 6
+                              end_position:
+                                bytes: 54
+                                line: 4
+                                character: 8
+                              token_type:
+                                type: StringLiteral
+                                literal: ""
+                                quote_type: Double
+                            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/strings/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/strings/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..9f41684004d9b9140f464e02ce594e1799b0944d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/strings/source.lua
@@ -0,0 +1,4 @@
+call("double")
+call('single')
+call("foo\nbar")
+call("")
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/strings/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/strings/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a8ec42c7d790b56cc0987a609484e68f259e6253
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/strings/tokens.snap
@@ -0,0 +1,230 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/strings
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 13
+    line: 1
+    character: 14
+  token_type:
+    type: StringLiteral
+    literal: double
+    quote_type: Double
+- 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: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 2
+    character: 1
+  end_position:
+    bytes: 19
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 19
+    line: 2
+    character: 5
+  end_position:
+    bytes: 20
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 20
+    line: 2
+    character: 6
+  end_position:
+    bytes: 28
+    line: 2
+    character: 14
+  token_type:
+    type: StringLiteral
+    literal: single
+    quote_type: Single
+- start_position:
+    bytes: 28
+    line: 2
+    character: 14
+  end_position:
+    bytes: 29
+    line: 2
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 29
+    line: 2
+    character: 15
+  end_position:
+    bytes: 30
+    line: 2
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 30
+    line: 3
+    character: 1
+  end_position:
+    bytes: 34
+    line: 3
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 34
+    line: 3
+    character: 5
+  end_position:
+    bytes: 35
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 35
+    line: 3
+    character: 6
+  end_position:
+    bytes: 45
+    line: 3
+    character: 16
+  token_type:
+    type: StringLiteral
+    literal: "foo\\nbar"
+    quote_type: Double
+- start_position:
+    bytes: 45
+    line: 3
+    character: 16
+  end_position:
+    bytes: 46
+    line: 3
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 46
+    line: 3
+    character: 17
+  end_position:
+    bytes: 47
+    line: 3
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 47
+    line: 4
+    character: 1
+  end_position:
+    bytes: 51
+    line: 4
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 51
+    line: 4
+    character: 5
+  end_position:
+    bytes: 52
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 52
+    line: 4
+    character: 6
+  end_position:
+    bytes: 54
+    line: 4
+    character: 8
+  token_type:
+    type: StringLiteral
+    literal: ""
+    quote_type: Double
+- start_position:
+    bytes: 54
+    line: 4
+    character: 8
+  end_position:
+    bytes: 55
+    line: 4
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 55
+    line: 4
+    character: 9
+  end_position:
+    bytes: 55
+    line: 4
+    character: 9
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-1/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9c19b7a601b6872a5a9d6169f9c10f1b342b4463
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-1/ast.snap
@@ -0,0 +1,137 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/table-constructor-1
+---
+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: 12
+                            line: 2
+                            character: 1
+                          end_position:
+                            bytes: 13
+                            line: 2
+                            character: 2
+                          token_type:
+                            type: Symbol
+                            symbol: "}"
+                        trailing_trivia: []
+                  fields:
+                    pairs: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-1/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0e6aaa89b07dffc68f90d9027e66d1d44fb32e4c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-1/source.lua
@@ -0,0 +1,2 @@
+local x = {
+}
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-1/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5e2fdf499cd592531c0cf426043245421cf447de
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-1/tokens.snap
@@ -0,0 +1,116 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/table-constructor-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: 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: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 13
+    line: 2
+    character: 2
+  end_position:
+    bytes: 13
+    line: 2
+    character: 2
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-2/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6c551af251f099d52aec59481bab54ee9ad501ee
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-2/ast.snap
@@ -0,0 +1,227 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/table-constructor-2
+---
+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: []
+                      - 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: []
+                  fields:
+                    pairs:
+                      - Punctuated:
+                          - NoKey:
+                              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: "1"
+                                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: " "
+                      - Punctuated:
+                          - NoKey:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 14
+                                    line: 1
+                                    character: 15
+                                  end_position:
+                                    bytes: 15
+                                    line: 1
+                                    character: 16
+                                  token_type:
+                                    type: Number
+                                    text: "2"
+                                trailing_trivia: []
+                          - 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: " "
+                      - End:
+                          NoKey:
+                            Number:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 17
+                                  line: 1
+                                  character: 18
+                                end_position:
+                                  bytes: 18
+                                  line: 1
+                                  character: 19
+                                token_type:
+                                  type: Number
+                                  text: "3"
+                              trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-2/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..7192737b68b1fff85b23782eb0c07e5c88f21287
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-2/source.lua
@@ -0,0 +1 @@
+local x = {1, 2, 3}
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-2/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7a2f30eb7c55f27cfce2a2b77dc0789c614764e6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-2/tokens.snap
@@ -0,0 +1,182 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/table-constructor-2
+
+---
+- 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: 13
+  token_type:
+    type: Number
+    text: "1"
+- 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: Number
+    text: "2"
+- 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: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Number
+    text: "3"
+- 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: 19
+    line: 1
+    character: 20
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-3/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-3/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d8685812fac81f3df22f02cc8bcaf517d17f338c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-3/ast.snap
@@ -0,0 +1,910 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/table-constructor-3
+---
+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: 35
+                            line: 5
+                            character: 1
+                          end_position:
+                            bytes: 36
+                            line: 5
+                            character: 2
+                          token_type:
+                            type: Symbol
+                            symbol: "}"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 36
+                              line: 5
+                              character: 2
+                            end_position:
+                              bytes: 37
+                              line: 5
+                              character: 2
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  fields:
+                    pairs:
+                      - Punctuated:
+                          - NameKey:
+                              key:
+                                leading_trivia:
+                                  - start_position:
+                                      bytes: 12
+                                      line: 2
+                                      character: 1
+                                    end_position:
+                                      bytes: 13
+                                      line: 2
+                                      character: 2
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "\t"
+                                token:
+                                  start_position:
+                                    bytes: 13
+                                    line: 2
+                                    character: 2
+                                  end_position:
+                                    bytes: 14
+                                    line: 2
+                                    character: 3
+                                  token_type:
+                                    type: Identifier
+                                    identifier: a
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 14
+                                      line: 2
+                                      character: 3
+                                    end_position:
+                                      bytes: 15
+                                      line: 2
+                                      character: 4
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              equal:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 15
+                                    line: 2
+                                    character: 4
+                                  end_position:
+                                    bytes: 16
+                                    line: 2
+                                    character: 5
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 16
+                                      line: 2
+                                      character: 5
+                                    end_position:
+                                      bytes: 17
+                                      line: 2
+                                      character: 6
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              value:
+                                Number:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 17
+                                      line: 2
+                                      character: 6
+                                    end_position:
+                                      bytes: 18
+                                      line: 2
+                                      character: 7
+                                    token_type:
+                                      type: Number
+                                      text: "1"
+                                  trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 18
+                                line: 2
+                                character: 7
+                              end_position:
+                                bytes: 19
+                                line: 2
+                                character: 8
+                              token_type:
+                                type: Symbol
+                                symbol: ","
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 19
+                                  line: 2
+                                  character: 8
+                                end_position:
+                                  bytes: 20
+                                  line: 2
+                                  character: 8
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+                      - Punctuated:
+                          - NameKey:
+                              key:
+                                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: 22
+                                    line: 3
+                                    character: 3
+                                  token_type:
+                                    type: Identifier
+                                    identifier: b
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 22
+                                      line: 3
+                                      character: 3
+                                    end_position:
+                                      bytes: 23
+                                      line: 3
+                                      character: 4
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              equal:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 23
+                                    line: 3
+                                    character: 4
+                                  end_position:
+                                    bytes: 24
+                                    line: 3
+                                    character: 5
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 24
+                                      line: 3
+                                      character: 5
+                                    end_position:
+                                      bytes: 25
+                                      line: 3
+                                      character: 6
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              value:
+                                Number:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 25
+                                      line: 3
+                                      character: 6
+                                    end_position:
+                                      bytes: 26
+                                      line: 3
+                                      character: 7
+                                    token_type:
+                                      type: Number
+                                      text: "2"
+                                  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"
+                      - End:
+                          NameKey:
+                            key:
+                              leading_trivia:
+                                - start_position:
+                                    bytes: 28
+                                    line: 4
+                                    character: 1
+                                  end_position:
+                                    bytes: 29
+                                    line: 4
+                                    character: 2
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\t"
+                              token:
+                                start_position:
+                                  bytes: 29
+                                  line: 4
+                                  character: 2
+                                end_position:
+                                  bytes: 30
+                                  line: 4
+                                  character: 3
+                                token_type:
+                                  type: Identifier
+                                  identifier: c
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 30
+                                    line: 4
+                                    character: 3
+                                  end_position:
+                                    bytes: 31
+                                    line: 4
+                                    character: 4
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            equal:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 31
+                                  line: 4
+                                  character: 4
+                                end_position:
+                                  bytes: 32
+                                  line: 4
+                                  character: 5
+                                token_type:
+                                  type: Symbol
+                                  symbol: "="
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 32
+                                    line: 4
+                                    character: 5
+                                  end_position:
+                                    bytes: 33
+                                    line: 4
+                                    character: 6
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            value:
+                              Number:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 33
+                                    line: 4
+                                    character: 6
+                                  end_position:
+                                    bytes: 34
+                                    line: 4
+                                    character: 7
+                                  token_type:
+                                    type: Number
+                                    text: "3"
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 34
+                                      line: 4
+                                      character: 7
+                                    end_position:
+                                      bytes: 35
+                                      line: 4
+                                      character: 7
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 37
+                line: 6
+                character: 1
+              end_position:
+                bytes: 38
+                line: 6
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 38
+              line: 7
+              character: 1
+            end_position:
+              bytes: 43
+              line: 7
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 43
+                line: 7
+                character: 6
+              end_position:
+                bytes: 44
+                line: 7
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 44
+                    line: 7
+                    character: 7
+                  end_position:
+                    bytes: 45
+                    line: 7
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: y
+                trailing_trivia:
+                  - start_position:
+                      bytes: 45
+                      line: 7
+                      character: 8
+                    end_position:
+                      bytes: 46
+                      line: 7
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 46
+              line: 7
+              character: 9
+            end_position:
+              bytes: 47
+              line: 7
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 47
+                line: 7
+                character: 10
+              end_position:
+                bytes: 48
+                line: 7
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                TableConstructor:
+                  braces:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 48
+                            line: 7
+                            character: 11
+                          end_position:
+                            bytes: 49
+                            line: 7
+                            character: 12
+                          token_type:
+                            type: Symbol
+                            symbol: "{"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 49
+                              line: 7
+                              character: 12
+                            end_position:
+                              bytes: 50
+                              line: 7
+                              character: 12
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 74
+                            line: 11
+                            character: 1
+                          end_position:
+                            bytes: 75
+                            line: 11
+                            character: 2
+                          token_type:
+                            type: Symbol
+                            symbol: "}"
+                        trailing_trivia: []
+                  fields:
+                    pairs:
+                      - Punctuated:
+                          - NameKey:
+                              key:
+                                leading_trivia:
+                                  - start_position:
+                                      bytes: 50
+                                      line: 8
+                                      character: 1
+                                    end_position:
+                                      bytes: 51
+                                      line: 8
+                                      character: 2
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "\t"
+                                token:
+                                  start_position:
+                                    bytes: 51
+                                    line: 8
+                                    character: 2
+                                  end_position:
+                                    bytes: 52
+                                    line: 8
+                                    character: 3
+                                  token_type:
+                                    type: Identifier
+                                    identifier: a
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 52
+                                      line: 8
+                                      character: 3
+                                    end_position:
+                                      bytes: 53
+                                      line: 8
+                                      character: 4
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              equal:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 53
+                                    line: 8
+                                    character: 4
+                                  end_position:
+                                    bytes: 54
+                                    line: 8
+                                    character: 5
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 54
+                                      line: 8
+                                      character: 5
+                                    end_position:
+                                      bytes: 55
+                                      line: 8
+                                      character: 6
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              value:
+                                Number:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 55
+                                      line: 8
+                                      character: 6
+                                    end_position:
+                                      bytes: 56
+                                      line: 8
+                                      character: 7
+                                    token_type:
+                                      type: Number
+                                      text: "1"
+                                  trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 56
+                                line: 8
+                                character: 7
+                              end_position:
+                                bytes: 57
+                                line: 8
+                                character: 8
+                              token_type:
+                                type: Symbol
+                                symbol: ","
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 57
+                                  line: 8
+                                  character: 8
+                                end_position:
+                                  bytes: 58
+                                  line: 8
+                                  character: 8
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+                      - Punctuated:
+                          - NameKey:
+                              key:
+                                leading_trivia:
+                                  - start_position:
+                                      bytes: 58
+                                      line: 9
+                                      character: 1
+                                    end_position:
+                                      bytes: 59
+                                      line: 9
+                                      character: 2
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "\t"
+                                token:
+                                  start_position:
+                                    bytes: 59
+                                    line: 9
+                                    character: 2
+                                  end_position:
+                                    bytes: 60
+                                    line: 9
+                                    character: 3
+                                  token_type:
+                                    type: Identifier
+                                    identifier: b
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 60
+                                      line: 9
+                                      character: 3
+                                    end_position:
+                                      bytes: 61
+                                      line: 9
+                                      character: 4
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              equal:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 61
+                                    line: 9
+                                    character: 4
+                                  end_position:
+                                    bytes: 62
+                                    line: 9
+                                    character: 5
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 62
+                                      line: 9
+                                      character: 5
+                                    end_position:
+                                      bytes: 63
+                                      line: 9
+                                      character: 6
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              value:
+                                Number:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 63
+                                      line: 9
+                                      character: 6
+                                    end_position:
+                                      bytes: 64
+                                      line: 9
+                                      character: 7
+                                    token_type:
+                                      type: Number
+                                      text: "2"
+                                  trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 64
+                                line: 9
+                                character: 7
+                              end_position:
+                                bytes: 65
+                                line: 9
+                                character: 8
+                              token_type:
+                                type: Symbol
+                                symbol: ","
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 65
+                                  line: 9
+                                  character: 8
+                                end_position:
+                                  bytes: 66
+                                  line: 9
+                                  character: 8
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+                      - Punctuated:
+                          - NameKey:
+                              key:
+                                leading_trivia:
+                                  - start_position:
+                                      bytes: 66
+                                      line: 10
+                                      character: 1
+                                    end_position:
+                                      bytes: 67
+                                      line: 10
+                                      character: 2
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "\t"
+                                token:
+                                  start_position:
+                                    bytes: 67
+                                    line: 10
+                                    character: 2
+                                  end_position:
+                                    bytes: 68
+                                    line: 10
+                                    character: 3
+                                  token_type:
+                                    type: Identifier
+                                    identifier: c
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 68
+                                      line: 10
+                                      character: 3
+                                    end_position:
+                                      bytes: 69
+                                      line: 10
+                                      character: 4
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              equal:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 69
+                                    line: 10
+                                    character: 4
+                                  end_position:
+                                    bytes: 70
+                                    line: 10
+                                    character: 5
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 70
+                                      line: 10
+                                      character: 5
+                                    end_position:
+                                      bytes: 71
+                                      line: 10
+                                      character: 6
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              value:
+                                Number:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 71
+                                      line: 10
+                                      character: 6
+                                    end_position:
+                                      bytes: 72
+                                      line: 10
+                                      character: 7
+                                    token_type:
+                                      type: Number
+                                      text: "3"
+                                  trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 72
+                                line: 10
+                                character: 7
+                              end_position:
+                                bytes: 73
+                                line: 10
+                                character: 8
+                              token_type:
+                                type: Symbol
+                                symbol: ","
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 73
+                                  line: 10
+                                  character: 8
+                                end_position:
+                                  bytes: 74
+                                  line: 10
+                                  character: 8
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-3/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-3/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..17788fde433a50da8218a7d3714e5109ce93eaaa
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-3/source.lua
@@ -0,0 +1,11 @@
+local x = {
+	a = 1,
+	b = 2,
+	c = 3
+}
+
+local y = {
+	a = 1,
+	b = 2,
+	c = 3,
+}
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-3/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-3/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..761cd2d22a57646d11125c459b8db9be57a052b9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-3/tokens.snap
@@ -0,0 +1,754 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/table-constructor-3
+
+---
+- 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: Identifier
+    identifier: a
+- start_position:
+    bytes: 14
+    line: 2
+    character: 3
+  end_position:
+    bytes: 15
+    line: 2
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- 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: Whitespace
+    characters: " "
+- start_position:
+    bytes: 17
+    line: 2
+    character: 6
+  end_position:
+    bytes: 18
+    line: 2
+    character: 7
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 18
+    line: 2
+    character: 7
+  end_position:
+    bytes: 19
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 19
+    line: 2
+    character: 8
+  end_position:
+    bytes: 20
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 20
+    line: 3
+    character: 1
+  end_position:
+    bytes: 21
+    line: 3
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 21
+    line: 3
+    character: 2
+  end_position:
+    bytes: 22
+    line: 3
+    character: 3
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 22
+    line: 3
+    character: 3
+  end_position:
+    bytes: 23
+    line: 3
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 23
+    line: 3
+    character: 4
+  end_position:
+    bytes: 24
+    line: 3
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 24
+    line: 3
+    character: 5
+  end_position:
+    bytes: 25
+    line: 3
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 25
+    line: 3
+    character: 6
+  end_position:
+    bytes: 26
+    line: 3
+    character: 7
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 26
+    line: 3
+    character: 7
+  end_position:
+    bytes: 27
+    line: 3
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 27
+    line: 3
+    character: 8
+  end_position:
+    bytes: 28
+    line: 3
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 28
+    line: 4
+    character: 1
+  end_position:
+    bytes: 29
+    line: 4
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 29
+    line: 4
+    character: 2
+  end_position:
+    bytes: 30
+    line: 4
+    character: 3
+  token_type:
+    type: Identifier
+    identifier: c
+- start_position:
+    bytes: 30
+    line: 4
+    character: 3
+  end_position:
+    bytes: 31
+    line: 4
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 31
+    line: 4
+    character: 4
+  end_position:
+    bytes: 32
+    line: 4
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 32
+    line: 4
+    character: 5
+  end_position:
+    bytes: 33
+    line: 4
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 33
+    line: 4
+    character: 6
+  end_position:
+    bytes: 34
+    line: 4
+    character: 7
+  token_type:
+    type: Number
+    text: "3"
+- start_position:
+    bytes: 34
+    line: 4
+    character: 7
+  end_position:
+    bytes: 35
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 35
+    line: 5
+    character: 1
+  end_position:
+    bytes: 36
+    line: 5
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 36
+    line: 5
+    character: 2
+  end_position:
+    bytes: 37
+    line: 5
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 37
+    line: 6
+    character: 1
+  end_position:
+    bytes: 38
+    line: 6
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 38
+    line: 7
+    character: 1
+  end_position:
+    bytes: 43
+    line: 7
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 43
+    line: 7
+    character: 6
+  end_position:
+    bytes: 44
+    line: 7
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 44
+    line: 7
+    character: 7
+  end_position:
+    bytes: 45
+    line: 7
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 45
+    line: 7
+    character: 8
+  end_position:
+    bytes: 46
+    line: 7
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 46
+    line: 7
+    character: 9
+  end_position:
+    bytes: 47
+    line: 7
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 47
+    line: 7
+    character: 10
+  end_position:
+    bytes: 48
+    line: 7
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 48
+    line: 7
+    character: 11
+  end_position:
+    bytes: 49
+    line: 7
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 49
+    line: 7
+    character: 12
+  end_position:
+    bytes: 50
+    line: 7
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 50
+    line: 8
+    character: 1
+  end_position:
+    bytes: 51
+    line: 8
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 51
+    line: 8
+    character: 2
+  end_position:
+    bytes: 52
+    line: 8
+    character: 3
+  token_type:
+    type: Identifier
+    identifier: a
+- start_position:
+    bytes: 52
+    line: 8
+    character: 3
+  end_position:
+    bytes: 53
+    line: 8
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 53
+    line: 8
+    character: 4
+  end_position:
+    bytes: 54
+    line: 8
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 54
+    line: 8
+    character: 5
+  end_position:
+    bytes: 55
+    line: 8
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 55
+    line: 8
+    character: 6
+  end_position:
+    bytes: 56
+    line: 8
+    character: 7
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 56
+    line: 8
+    character: 7
+  end_position:
+    bytes: 57
+    line: 8
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 57
+    line: 8
+    character: 8
+  end_position:
+    bytes: 58
+    line: 8
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 58
+    line: 9
+    character: 1
+  end_position:
+    bytes: 59
+    line: 9
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 59
+    line: 9
+    character: 2
+  end_position:
+    bytes: 60
+    line: 9
+    character: 3
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 60
+    line: 9
+    character: 3
+  end_position:
+    bytes: 61
+    line: 9
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 61
+    line: 9
+    character: 4
+  end_position:
+    bytes: 62
+    line: 9
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 62
+    line: 9
+    character: 5
+  end_position:
+    bytes: 63
+    line: 9
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 63
+    line: 9
+    character: 6
+  end_position:
+    bytes: 64
+    line: 9
+    character: 7
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 64
+    line: 9
+    character: 7
+  end_position:
+    bytes: 65
+    line: 9
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 65
+    line: 9
+    character: 8
+  end_position:
+    bytes: 66
+    line: 9
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 66
+    line: 10
+    character: 1
+  end_position:
+    bytes: 67
+    line: 10
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 67
+    line: 10
+    character: 2
+  end_position:
+    bytes: 68
+    line: 10
+    character: 3
+  token_type:
+    type: Identifier
+    identifier: c
+- start_position:
+    bytes: 68
+    line: 10
+    character: 3
+  end_position:
+    bytes: 69
+    line: 10
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 69
+    line: 10
+    character: 4
+  end_position:
+    bytes: 70
+    line: 10
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 70
+    line: 10
+    character: 5
+  end_position:
+    bytes: 71
+    line: 10
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 71
+    line: 10
+    character: 6
+  end_position:
+    bytes: 72
+    line: 10
+    character: 7
+  token_type:
+    type: Number
+    text: "3"
+- start_position:
+    bytes: 72
+    line: 10
+    character: 7
+  end_position:
+    bytes: 73
+    line: 10
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 73
+    line: 10
+    character: 8
+  end_position:
+    bytes: 74
+    line: 10
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 74
+    line: 11
+    character: 1
+  end_position:
+    bytes: 75
+    line: 11
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 75
+    line: 11
+    character: 2
+  end_position:
+    bytes: 75
+    line: 11
+    character: 2
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-4/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-4/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2a0f13bf60d006d359678e369ec1293bed464fa6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-4/ast.snap
@@ -0,0 +1,312 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/table-constructor-4
+---
+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: 27
+                            line: 3
+                            character: 1
+                          end_position:
+                            bytes: 28
+                            line: 3
+                            character: 2
+                          token_type:
+                            type: Symbol
+                            symbol: "}"
+                        trailing_trivia: []
+                  fields:
+                    pairs:
+                      - Punctuated:
+                          - ExpressionKey:
+                              brackets:
+                                tokens:
+                                  - leading_trivia:
+                                      - start_position:
+                                          bytes: 12
+                                          line: 2
+                                          character: 1
+                                        end_position:
+                                          bytes: 13
+                                          line: 2
+                                          character: 2
+                                        token_type:
+                                          type: Whitespace
+                                          characters: "\t"
+                                    token:
+                                      start_position:
+                                        bytes: 13
+                                        line: 2
+                                        character: 2
+                                      end_position:
+                                        bytes: 14
+                                        line: 2
+                                        character: 3
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "["
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 20
+                                        line: 2
+                                        character: 9
+                                      end_position:
+                                        bytes: 21
+                                        line: 2
+                                        character: 10
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "]"
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 21
+                                          line: 2
+                                          character: 10
+                                        end_position:
+                                          bytes: 22
+                                          line: 2
+                                          character: 11
+                                        token_type:
+                                          type: Whitespace
+                                          characters: " "
+                              key:
+                                FunctionCall:
+                                  prefix:
+                                    Name:
+                                      leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 14
+                                          line: 2
+                                          character: 3
+                                        end_position:
+                                          bytes: 18
+                                          line: 2
+                                          character: 7
+                                        token_type:
+                                          type: Identifier
+                                          identifier: call
+                                      trailing_trivia: []
+                                  suffixes:
+                                    - Call:
+                                        AnonymousCall:
+                                          Parentheses:
+                                            parentheses:
+                                              tokens:
+                                                - leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 18
+                                                      line: 2
+                                                      character: 7
+                                                    end_position:
+                                                      bytes: 19
+                                                      line: 2
+                                                      character: 8
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: (
+                                                  trailing_trivia: []
+                                                - leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 19
+                                                      line: 2
+                                                      character: 8
+                                                    end_position:
+                                                      bytes: 20
+                                                      line: 2
+                                                      character: 9
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: )
+                                                  trailing_trivia: []
+                                            arguments:
+                                              pairs: []
+                              equal:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 22
+                                    line: 2
+                                    character: 11
+                                  end_position:
+                                    bytes: 23
+                                    line: 2
+                                    character: 12
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 23
+                                      line: 2
+                                      character: 12
+                                    end_position:
+                                      bytes: 24
+                                      line: 2
+                                      character: 13
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              value:
+                                Number:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 24
+                                      line: 2
+                                      character: 13
+                                    end_position:
+                                      bytes: 25
+                                      line: 2
+                                      character: 14
+                                    token_type:
+                                      type: Number
+                                      text: "1"
+                                  trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 25
+                                line: 2
+                                character: 14
+                              end_position:
+                                bytes: 26
+                                line: 2
+                                character: 15
+                              token_type:
+                                type: Symbol
+                                symbol: ","
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 26
+                                  line: 2
+                                  character: 15
+                                end_position:
+                                  bytes: 27
+                                  line: 2
+                                  character: 15
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-4/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-4/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..5870b430addf13cce10eb2fe2e1d9b55d771ff02
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-4/source.lua
@@ -0,0 +1,3 @@
+local x = {
+	[call()] = 1,
+}
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-4/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-4/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4e46a8ac4270b8cefbef53eee5dc61360246d326
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-4/tokens.snap
@@ -0,0 +1,248 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/table-constructor-4
+
+---
+- 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: 18
+    line: 2
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 18
+    line: 2
+    character: 7
+  end_position:
+    bytes: 19
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 19
+    line: 2
+    character: 8
+  end_position:
+    bytes: 20
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: )
+- 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: 23
+    line: 2
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 23
+    line: 2
+    character: 12
+  end_position:
+    bytes: 24
+    line: 2
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 24
+    line: 2
+    character: 13
+  end_position:
+    bytes: 25
+    line: 2
+    character: 14
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 25
+    line: 2
+    character: 14
+  end_position:
+    bytes: 26
+    line: 2
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 26
+    line: 2
+    character: 15
+  end_position:
+    bytes: 27
+    line: 2
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 27
+    line: 3
+    character: 1
+  end_position:
+    bytes: 28
+    line: 3
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 28
+    line: 3
+    character: 2
+  end_position:
+    bytes: 28
+    line: 3
+    character: 2
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-5/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-5/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7f0856dfebaf5c2782e2f8be222a75071705e2ac
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-5/ast.snap
@@ -0,0 +1,365 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/table-constructor-5
+---
+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: 31
+                            line: 4
+                            character: 1
+                          end_position:
+                            bytes: 32
+                            line: 4
+                            character: 2
+                          token_type:
+                            type: Symbol
+                            symbol: "}"
+                        trailing_trivia: []
+                  fields:
+                    pairs:
+                      - Punctuated:
+                          - ExpressionKey:
+                              brackets:
+                                tokens:
+                                  - leading_trivia:
+                                      - start_position:
+                                          bytes: 12
+                                          line: 2
+                                          character: 1
+                                        end_position:
+                                          bytes: 13
+                                          line: 2
+                                          character: 2
+                                        token_type:
+                                          type: Whitespace
+                                          characters: "\t"
+                                    token:
+                                      start_position:
+                                        bytes: 13
+                                        line: 2
+                                        character: 2
+                                      end_position:
+                                        bytes: 14
+                                        line: 2
+                                        character: 3
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "["
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 20
+                                        line: 2
+                                        character: 9
+                                      end_position:
+                                        bytes: 21
+                                        line: 2
+                                        character: 10
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "]"
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 21
+                                          line: 2
+                                          character: 10
+                                        end_position:
+                                          bytes: 22
+                                          line: 2
+                                          character: 11
+                                        token_type:
+                                          type: Whitespace
+                                          characters: " "
+                              key:
+                                FunctionCall:
+                                  prefix:
+                                    Name:
+                                      leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 14
+                                          line: 2
+                                          character: 3
+                                        end_position:
+                                          bytes: 18
+                                          line: 2
+                                          character: 7
+                                        token_type:
+                                          type: Identifier
+                                          identifier: call
+                                      trailing_trivia: []
+                                  suffixes:
+                                    - Call:
+                                        AnonymousCall:
+                                          Parentheses:
+                                            parentheses:
+                                              tokens:
+                                                - leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 18
+                                                      line: 2
+                                                      character: 7
+                                                    end_position:
+                                                      bytes: 19
+                                                      line: 2
+                                                      character: 8
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: (
+                                                  trailing_trivia: []
+                                                - leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 19
+                                                      line: 2
+                                                      character: 8
+                                                    end_position:
+                                                      bytes: 20
+                                                      line: 2
+                                                      character: 9
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: )
+                                                  trailing_trivia: []
+                                            arguments:
+                                              pairs: []
+                              equal:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 22
+                                    line: 2
+                                    character: 11
+                                  end_position:
+                                    bytes: 23
+                                    line: 2
+                                    character: 12
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 23
+                                      line: 2
+                                      character: 12
+                                    end_position:
+                                      bytes: 24
+                                      line: 2
+                                      character: 13
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              value:
+                                Number:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 24
+                                      line: 2
+                                      character: 13
+                                    end_position:
+                                      bytes: 25
+                                      line: 2
+                                      character: 14
+                                    token_type:
+                                      type: Number
+                                      text: "1"
+                                  trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 25
+                                line: 2
+                                character: 14
+                              end_position:
+                                bytes: 26
+                                line: 2
+                                character: 15
+                              token_type:
+                                type: Symbol
+                                symbol: ","
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 26
+                                  line: 2
+                                  character: 15
+                                end_position:
+                                  bytes: 27
+                                  line: 2
+                                  character: 15
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+                      - Punctuated:
+                          - NoKey:
+                              Number:
+                                leading_trivia:
+                                  - start_position:
+                                      bytes: 27
+                                      line: 3
+                                      character: 1
+                                    end_position:
+                                      bytes: 28
+                                      line: 3
+                                      character: 2
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "\t"
+                                token:
+                                  start_position:
+                                    bytes: 28
+                                    line: 3
+                                    character: 2
+                                  end_position:
+                                    bytes: 29
+                                    line: 3
+                                    character: 3
+                                  token_type:
+                                    type: Number
+                                    text: "2"
+                                trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 29
+                                line: 3
+                                character: 3
+                              end_position:
+                                bytes: 30
+                                line: 3
+                                character: 4
+                              token_type:
+                                type: Symbol
+                                symbol: ","
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 30
+                                  line: 3
+                                  character: 4
+                                end_position:
+                                  bytes: 31
+                                  line: 3
+                                  character: 4
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-5/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-5/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..afeca1f3193ea8ea9de2b0c2cc1f5305b377ec6d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-5/source.lua
@@ -0,0 +1,4 @@
+local x = {
+	[call()] = 1,
+	2,
+}
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-5/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-5/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9afbf2ab61614418a5ba6a3ef77c5e9fded223f5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-5/tokens.snap
@@ -0,0 +1,292 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/table-constructor-5
+
+---
+- 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: 18
+    line: 2
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 18
+    line: 2
+    character: 7
+  end_position:
+    bytes: 19
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 19
+    line: 2
+    character: 8
+  end_position:
+    bytes: 20
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: )
+- 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: 23
+    line: 2
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 23
+    line: 2
+    character: 12
+  end_position:
+    bytes: 24
+    line: 2
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 24
+    line: 2
+    character: 13
+  end_position:
+    bytes: 25
+    line: 2
+    character: 14
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 25
+    line: 2
+    character: 14
+  end_position:
+    bytes: 26
+    line: 2
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 26
+    line: 2
+    character: 15
+  end_position:
+    bytes: 27
+    line: 2
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 27
+    line: 3
+    character: 1
+  end_position:
+    bytes: 28
+    line: 3
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 28
+    line: 3
+    character: 2
+  end_position:
+    bytes: 29
+    line: 3
+    character: 3
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 29
+    line: 3
+    character: 3
+  end_position:
+    bytes: 30
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 30
+    line: 3
+    character: 4
+  end_position:
+    bytes: 31
+    line: 3
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 31
+    line: 4
+    character: 1
+  end_position:
+    bytes: 32
+    line: 4
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 32
+    line: 4
+    character: 2
+  end_position:
+    bytes: 32
+    line: 4
+    character: 2
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-6/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-6/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..886715070621d4e0b3906eebe40e86312b5bccb1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-6/ast.snap
@@ -0,0 +1,166 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/table-constructor-6
+---
+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: 9
+                    line: 1
+                    character: 10
+                  token_type:
+                    type: Identifier
+                    identifier: foo
+                trailing_trivia:
+                  - start_position:
+                      bytes: 9
+                      line: 1
+                      character: 10
+                    end_position:
+                      bytes: 10
+                      line: 1
+                      character: 11
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                TableConstructor:
+                  braces:
+                    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:
+                          - start_position:
+                              bytes: 13
+                              line: 1
+                              character: 14
+                            end_position:
+                              bytes: 14
+                              line: 1
+                              character: 15
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      - 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: []
+                  fields:
+                    pairs:
+                      - End:
+                          NoKey:
+                            Var:
+                              Name:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 14
+                                    line: 1
+                                    character: 15
+                                  end_position:
+                                    bytes: 17
+                                    line: 1
+                                    character: 18
+                                  token_type:
+                                    type: Identifier
+                                    identifier: bar
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 17
+                                      line: 1
+                                      character: 18
+                                    end_position:
+                                      bytes: 18
+                                      line: 1
+                                      character: 19
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-6/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-6/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..c5bde7d58f1679761c28e454f7fdf6cfa6fdd060
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-6/source.lua
@@ -0,0 +1 @@
+local foo = { bar }
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-6/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-6/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e3466688ef71c1d51e53b686863457ea1fed0990
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructor-6/tokens.snap
@@ -0,0 +1,138 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/table-constructor-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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: foo
+- 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: 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: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: bar
+- 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: 19
+    line: 1
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 19
+    line: 1
+    character: 20
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-7/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-7/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..37b8b5085e7c42452f1befba56aca5ebb20f74d5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-7/ast.snap
@@ -0,0 +1,551 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/table-constructors-7
+---
+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: 15
+                    line: 1
+                    character: 16
+                  token_type:
+                    type: Identifier
+                    identifier: blacklist
+                trailing_trivia:
+                  - start_position:
+                      bytes: 15
+                      line: 1
+                      character: 16
+                    end_position:
+                      bytes: 16
+                      line: 1
+                      character: 17
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                TableConstructor:
+                  braces:
+                    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:
+                          - start_position:
+                              bytes: 19
+                              line: 1
+                              character: 20
+                            end_position:
+                              bytes: 20
+                              line: 1
+                              character: 20
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 215
+                            line: 5
+                            character: 1
+                          end_position:
+                            bytes: 216
+                            line: 5
+                            character: 2
+                          token_type:
+                            type: Symbol
+                            symbol: "}"
+                        trailing_trivia: []
+                  fields:
+                    pairs:
+                      - Punctuated:
+                          - ExpressionKey:
+                              brackets:
+                                tokens:
+                                  - 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: 22
+                                        line: 2
+                                        character: 3
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "["
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 55
+                                        line: 2
+                                        character: 36
+                                      end_position:
+                                        bytes: 56
+                                        line: 2
+                                        character: 37
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "]"
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 56
+                                          line: 2
+                                          character: 37
+                                        end_position:
+                                          bytes: 57
+                                          line: 2
+                                          character: 38
+                                        token_type:
+                                          type: Whitespace
+                                          characters: " "
+                              key:
+                                String:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 22
+                                      line: 2
+                                      character: 3
+                                    end_position:
+                                      bytes: 55
+                                      line: 2
+                                      character: 36
+                                    token_type:
+                                      type: StringLiteral
+                                      literal: Audio file failed to load (18).
+                                      quote_type: Double
+                                  trailing_trivia: []
+                              equal:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 57
+                                    line: 2
+                                    character: 38
+                                  end_position:
+                                    bytes: 58
+                                    line: 2
+                                    character: 39
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 58
+                                      line: 2
+                                      character: 39
+                                    end_position:
+                                      bytes: 59
+                                      line: 2
+                                      character: 40
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              value:
+                                Symbol:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 59
+                                      line: 2
+                                      character: 40
+                                    end_position:
+                                      bytes: 63
+                                      line: 2
+                                      character: 44
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "true"
+                                  trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 63
+                                line: 2
+                                character: 44
+                              end_position:
+                                bytes: 64
+                                line: 2
+                                character: 45
+                              token_type:
+                                type: Symbol
+                                symbol: ;
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 64
+                                  line: 2
+                                  character: 45
+                                end_position:
+                                  bytes: 65
+                                  line: 2
+                                  character: 45
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+                      - Punctuated:
+                          - ExpressionKey:
+                              brackets:
+                                tokens:
+                                  - leading_trivia:
+                                      - start_position:
+                                          bytes: 65
+                                          line: 3
+                                          character: 1
+                                        end_position:
+                                          bytes: 66
+                                          line: 3
+                                          character: 2
+                                        token_type:
+                                          type: Whitespace
+                                          characters: "\t"
+                                    token:
+                                      start_position:
+                                        bytes: 66
+                                        line: 3
+                                        character: 2
+                                      end_position:
+                                        bytes: 67
+                                        line: 3
+                                        character: 3
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "["
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 131
+                                        line: 3
+                                        character: 67
+                                      end_position:
+                                        bytes: 132
+                                        line: 3
+                                        character: 68
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "]"
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 132
+                                          line: 3
+                                          character: 68
+                                        end_position:
+                                          bytes: 133
+                                          line: 3
+                                          character: 69
+                                        token_type:
+                                          type: Whitespace
+                                          characters: " "
+                              key:
+                                String:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 67
+                                      line: 3
+                                      character: 3
+                                    end_position:
+                                      bytes: 131
+                                      line: 3
+                                      character: 67
+                                    token_type:
+                                      type: StringLiteral
+                                      literal: HTTP 0 (HTTP 429 (HTTP/1.1 429 ProvisionedThroughputExceeded))
+                                      quote_type: Double
+                                  trailing_trivia: []
+                              equal:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 133
+                                    line: 3
+                                    character: 69
+                                  end_position:
+                                    bytes: 134
+                                    line: 3
+                                    character: 70
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 134
+                                      line: 3
+                                      character: 70
+                                    end_position:
+                                      bytes: 135
+                                      line: 3
+                                      character: 71
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              value:
+                                Symbol:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 135
+                                      line: 3
+                                      character: 71
+                                    end_position:
+                                      bytes: 139
+                                      line: 3
+                                      character: 75
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "true"
+                                  trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 139
+                                line: 3
+                                character: 75
+                              end_position:
+                                bytes: 140
+                                line: 3
+                                character: 76
+                              token_type:
+                                type: Symbol
+                                symbol: ;
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 140
+                                  line: 3
+                                  character: 76
+                                end_position:
+                                  bytes: 141
+                                  line: 3
+                                  character: 76
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+                      - Punctuated:
+                          - ExpressionKey:
+                              brackets:
+                                tokens:
+                                  - leading_trivia:
+                                      - start_position:
+                                          bytes: 141
+                                          line: 4
+                                          character: 1
+                                        end_position:
+                                          bytes: 142
+                                          line: 4
+                                          character: 2
+                                        token_type:
+                                          type: Whitespace
+                                          characters: "\t"
+                                    token:
+                                      start_position:
+                                        bytes: 142
+                                        line: 4
+                                        character: 2
+                                      end_position:
+                                        bytes: 143
+                                        line: 4
+                                        character: 3
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "["
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 205
+                                        line: 4
+                                        character: 65
+                                      end_position:
+                                        bytes: 206
+                                        line: 4
+                                        character: 66
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "]"
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 206
+                                          line: 4
+                                          character: 66
+                                        end_position:
+                                          bytes: 207
+                                          line: 4
+                                          character: 67
+                                        token_type:
+                                          type: Whitespace
+                                          characters: " "
+                              key:
+                                String:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 143
+                                      line: 4
+                                      character: 3
+                                    end_position:
+                                      bytes: 205
+                                      line: 4
+                                      character: 65
+                                    token_type:
+                                      type: StringLiteral
+                                      literal: LoadCharacter can only be called when Player is in the world
+                                      quote_type: Double
+                                  trailing_trivia: []
+                              equal:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 207
+                                    line: 4
+                                    character: 67
+                                  end_position:
+                                    bytes: 208
+                                    line: 4
+                                    character: 68
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "="
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 208
+                                      line: 4
+                                      character: 68
+                                    end_position:
+                                      bytes: 209
+                                      line: 4
+                                      character: 69
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              value:
+                                Symbol:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 209
+                                      line: 4
+                                      character: 69
+                                    end_position:
+                                      bytes: 213
+                                      line: 4
+                                      character: 73
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "true"
+                                  trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 213
+                                line: 4
+                                character: 73
+                              end_position:
+                                bytes: 214
+                                line: 4
+                                character: 74
+                              token_type:
+                                type: Symbol
+                                symbol: ;
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 214
+                                  line: 4
+                                  character: 74
+                                end_position:
+                                  bytes: 215
+                                  line: 4
+                                  character: 74
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-7/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-7/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..5688c7fcc49b1834a94f17de9391c2a3e6085823
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-7/source.lua
@@ -0,0 +1,5 @@
+local blacklist = {
+	["Audio file failed to load (18)."] = true;
+	["HTTP 0 (HTTP 429 (HTTP/1.1 429 ProvisionedThroughputExceeded))"] = true;
+	["LoadCharacter can only be called when Player is in the world"] = true;
+}
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-7/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-7/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..fb2a7b02baf12a4d557652af1ca1e443770f86c5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-7/tokens.snap
@@ -0,0 +1,449 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/table-constructors-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: 15
+    line: 1
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: blacklist
+- 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: 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: 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: 20
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 20
+    line: 2
+    character: 1
+  end_position:
+    bytes: 21
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 21
+    line: 2
+    character: 2
+  end_position:
+    bytes: 22
+    line: 2
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 22
+    line: 2
+    character: 3
+  end_position:
+    bytes: 55
+    line: 2
+    character: 36
+  token_type:
+    type: StringLiteral
+    literal: Audio file failed to load (18).
+    quote_type: Double
+- start_position:
+    bytes: 55
+    line: 2
+    character: 36
+  end_position:
+    bytes: 56
+    line: 2
+    character: 37
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 56
+    line: 2
+    character: 37
+  end_position:
+    bytes: 57
+    line: 2
+    character: 38
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 57
+    line: 2
+    character: 38
+  end_position:
+    bytes: 58
+    line: 2
+    character: 39
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 58
+    line: 2
+    character: 39
+  end_position:
+    bytes: 59
+    line: 2
+    character: 40
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 59
+    line: 2
+    character: 40
+  end_position:
+    bytes: 63
+    line: 2
+    character: 44
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 63
+    line: 2
+    character: 44
+  end_position:
+    bytes: 64
+    line: 2
+    character: 45
+  token_type:
+    type: Symbol
+    symbol: ;
+- start_position:
+    bytes: 64
+    line: 2
+    character: 45
+  end_position:
+    bytes: 65
+    line: 2
+    character: 45
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 65
+    line: 3
+    character: 1
+  end_position:
+    bytes: 66
+    line: 3
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 66
+    line: 3
+    character: 2
+  end_position:
+    bytes: 67
+    line: 3
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 67
+    line: 3
+    character: 3
+  end_position:
+    bytes: 131
+    line: 3
+    character: 67
+  token_type:
+    type: StringLiteral
+    literal: HTTP 0 (HTTP 429 (HTTP/1.1 429 ProvisionedThroughputExceeded))
+    quote_type: Double
+- start_position:
+    bytes: 131
+    line: 3
+    character: 67
+  end_position:
+    bytes: 132
+    line: 3
+    character: 68
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 132
+    line: 3
+    character: 68
+  end_position:
+    bytes: 133
+    line: 3
+    character: 69
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 133
+    line: 3
+    character: 69
+  end_position:
+    bytes: 134
+    line: 3
+    character: 70
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 134
+    line: 3
+    character: 70
+  end_position:
+    bytes: 135
+    line: 3
+    character: 71
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 135
+    line: 3
+    character: 71
+  end_position:
+    bytes: 139
+    line: 3
+    character: 75
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 139
+    line: 3
+    character: 75
+  end_position:
+    bytes: 140
+    line: 3
+    character: 76
+  token_type:
+    type: Symbol
+    symbol: ;
+- start_position:
+    bytes: 140
+    line: 3
+    character: 76
+  end_position:
+    bytes: 141
+    line: 3
+    character: 76
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 141
+    line: 4
+    character: 1
+  end_position:
+    bytes: 142
+    line: 4
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 142
+    line: 4
+    character: 2
+  end_position:
+    bytes: 143
+    line: 4
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 143
+    line: 4
+    character: 3
+  end_position:
+    bytes: 205
+    line: 4
+    character: 65
+  token_type:
+    type: StringLiteral
+    literal: LoadCharacter can only be called when Player is in the world
+    quote_type: Double
+- start_position:
+    bytes: 205
+    line: 4
+    character: 65
+  end_position:
+    bytes: 206
+    line: 4
+    character: 66
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 206
+    line: 4
+    character: 66
+  end_position:
+    bytes: 207
+    line: 4
+    character: 67
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 207
+    line: 4
+    character: 67
+  end_position:
+    bytes: 208
+    line: 4
+    character: 68
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 208
+    line: 4
+    character: 68
+  end_position:
+    bytes: 209
+    line: 4
+    character: 69
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 209
+    line: 4
+    character: 69
+  end_position:
+    bytes: 213
+    line: 4
+    character: 73
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 213
+    line: 4
+    character: 73
+  end_position:
+    bytes: 214
+    line: 4
+    character: 74
+  token_type:
+    type: Symbol
+    symbol: ;
+- start_position:
+    bytes: 214
+    line: 4
+    character: 74
+  end_position:
+    bytes: 215
+    line: 4
+    character: 74
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 215
+    line: 5
+    character: 1
+  end_position:
+    bytes: 216
+    line: 5
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 216
+    line: 5
+    character: 2
+  end_position:
+    bytes: 216
+    line: 5
+    character: 2
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-8/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-8/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3cdcdf5ca90685f4ddf5cb2b271b9200b0bc7bca
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-8/ast.snap
@@ -0,0 +1,373 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/table-constructors-8
+---
+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: 129
+                          line: 4
+                          character: 1
+                        end_position:
+                          bytes: 130
+                          line: 4
+                          character: 2
+                        token_type:
+                          type: Symbol
+                          symbol: "}"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 130
+                            line: 4
+                            character: 2
+                          end_position:
+                            bytes: 131
+                            line: 4
+                            character: 2
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+                fields:
+                  pairs:
+                    - Punctuated:
+                        - ExpressionKey:
+                            brackets:
+                              tokens:
+                                - 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: Symbol
+                                      symbol: "["
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 36
+                                      line: 2
+                                      character: 28
+                                    end_position:
+                                      bytes: 37
+                                      line: 2
+                                      character: 29
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "]"
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 37
+                                        line: 2
+                                        character: 29
+                                      end_position:
+                                        bytes: 38
+                                        line: 2
+                                        character: 30
+                                      token_type:
+                                        type: Whitespace
+                                        characters: " "
+                            key:
+                              String:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 11
+                                    line: 2
+                                    character: 3
+                                  end_position:
+                                    bytes: 36
+                                    line: 2
+                                    character: 28
+                                  token_type:
+                                    type: StringLiteral
+                                    literal: "Noob Attack: Periastron"
+                                    quote_type: Double
+                                trailing_trivia: []
+                            equal:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 38
+                                  line: 2
+                                  character: 30
+                                end_position:
+                                  bytes: 39
+                                  line: 2
+                                  character: 31
+                                token_type:
+                                  type: Symbol
+                                  symbol: "="
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 39
+                                    line: 2
+                                    character: 31
+                                  end_position:
+                                    bytes: 40
+                                    line: 2
+                                    character: 32
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            value:
+                              String:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 40
+                                    line: 2
+                                    character: 32
+                                  end_position:
+                                    bytes: 66
+                                    line: 2
+                                    character: 58
+                                  token_type:
+                                    type: StringLiteral
+                                    literal: Noob Attack - Periastron
+                                    quote_type: Double
+                                trailing_trivia: []
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 66
+                              line: 2
+                              character: 58
+                            end_position:
+                              bytes: 67
+                              line: 2
+                              character: 59
+                            token_type:
+                              type: Symbol
+                              symbol: ;
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 67
+                                line: 2
+                                character: 59
+                              end_position:
+                                bytes: 68
+                                line: 2
+                                character: 59
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+                    - Punctuated:
+                        - ExpressionKey:
+                            brackets:
+                              tokens:
+                                - leading_trivia:
+                                    - start_position:
+                                        bytes: 68
+                                        line: 3
+                                        character: 1
+                                      end_position:
+                                        bytes: 69
+                                        line: 3
+                                        character: 2
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\t"
+                                  token:
+                                    start_position:
+                                      bytes: 69
+                                      line: 3
+                                      character: 2
+                                    end_position:
+                                      bytes: 70
+                                      line: 3
+                                      character: 3
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "["
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 97
+                                      line: 3
+                                      character: 28
+                                    end_position:
+                                      bytes: 98
+                                      line: 3
+                                      character: 29
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "]"
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 98
+                                        line: 3
+                                        character: 29
+                                      end_position:
+                                        bytes: 99
+                                        line: 3
+                                        character: 30
+                                      token_type:
+                                        type: Whitespace
+                                        characters: " "
+                            key:
+                              String:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 70
+                                    line: 3
+                                    character: 3
+                                  end_position:
+                                    bytes: 97
+                                    line: 3
+                                    character: 28
+                                  token_type:
+                                    type: StringLiteral
+                                    literal: Noob Attack꞉ Periastron
+                                    quote_type: Double
+                                trailing_trivia: []
+                            equal:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 99
+                                  line: 3
+                                  character: 30
+                                end_position:
+                                  bytes: 100
+                                  line: 3
+                                  character: 31
+                                token_type:
+                                  type: Symbol
+                                  symbol: "="
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 100
+                                    line: 3
+                                    character: 31
+                                  end_position:
+                                    bytes: 101
+                                    line: 3
+                                    character: 32
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            value:
+                              String:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 101
+                                    line: 3
+                                    character: 32
+                                  end_position:
+                                    bytes: 127
+                                    line: 3
+                                    character: 58
+                                  token_type:
+                                    type: StringLiteral
+                                    literal: Noob Attack - Periastron
+                                    quote_type: Double
+                                trailing_trivia: []
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 127
+                              line: 3
+                              character: 58
+                            end_position:
+                              bytes: 128
+                              line: 3
+                              character: 59
+                            token_type:
+                              type: Symbol
+                              symbol: ;
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 128
+                                line: 3
+                                character: 59
+                              end_position:
+                                bytes: 129
+                                line: 3
+                                character: 59
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+  - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-8/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-8/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..ed28eaa45238ffa7912a24d7391e5a6170b83a27
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-8/source.lua
@@ -0,0 +1,4 @@
+return {
+	["Noob Attack: Periastron"] = "Noob Attack - Periastron";
+	["Noob Attack꞉ Periastron"] = "Noob Attack - Periastron";
+}
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-8/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-8/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d6eda3400bd38928373f235e82b3cf751bf567e7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/table-constructors-8/tokens.snap
@@ -0,0 +1,307 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/table-constructors-8
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "{"
+- 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: 10
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 10
+    line: 2
+    character: 2
+  end_position:
+    bytes: 11
+    line: 2
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 11
+    line: 2
+    character: 3
+  end_position:
+    bytes: 36
+    line: 2
+    character: 28
+  token_type:
+    type: StringLiteral
+    literal: "Noob Attack: Periastron"
+    quote_type: Double
+- start_position:
+    bytes: 36
+    line: 2
+    character: 28
+  end_position:
+    bytes: 37
+    line: 2
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 37
+    line: 2
+    character: 29
+  end_position:
+    bytes: 38
+    line: 2
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 38
+    line: 2
+    character: 30
+  end_position:
+    bytes: 39
+    line: 2
+    character: 31
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 39
+    line: 2
+    character: 31
+  end_position:
+    bytes: 40
+    line: 2
+    character: 32
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 40
+    line: 2
+    character: 32
+  end_position:
+    bytes: 66
+    line: 2
+    character: 58
+  token_type:
+    type: StringLiteral
+    literal: Noob Attack - Periastron
+    quote_type: Double
+- start_position:
+    bytes: 66
+    line: 2
+    character: 58
+  end_position:
+    bytes: 67
+    line: 2
+    character: 59
+  token_type:
+    type: Symbol
+    symbol: ;
+- start_position:
+    bytes: 67
+    line: 2
+    character: 59
+  end_position:
+    bytes: 68
+    line: 2
+    character: 59
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 68
+    line: 3
+    character: 1
+  end_position:
+    bytes: 69
+    line: 3
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 69
+    line: 3
+    character: 2
+  end_position:
+    bytes: 70
+    line: 3
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 70
+    line: 3
+    character: 3
+  end_position:
+    bytes: 97
+    line: 3
+    character: 28
+  token_type:
+    type: StringLiteral
+    literal: Noob Attack꞉ Periastron
+    quote_type: Double
+- start_position:
+    bytes: 97
+    line: 3
+    character: 28
+  end_position:
+    bytes: 98
+    line: 3
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 98
+    line: 3
+    character: 29
+  end_position:
+    bytes: 99
+    line: 3
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 99
+    line: 3
+    character: 30
+  end_position:
+    bytes: 100
+    line: 3
+    character: 31
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 100
+    line: 3
+    character: 31
+  end_position:
+    bytes: 101
+    line: 3
+    character: 32
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 101
+    line: 3
+    character: 32
+  end_position:
+    bytes: 127
+    line: 3
+    character: 58
+  token_type:
+    type: StringLiteral
+    literal: Noob Attack - Periastron
+    quote_type: Double
+- start_position:
+    bytes: 127
+    line: 3
+    character: 58
+  end_position:
+    bytes: 128
+    line: 3
+    character: 59
+  token_type:
+    type: Symbol
+    symbol: ;
+- start_position:
+    bytes: 128
+    line: 3
+    character: 59
+  end_position:
+    bytes: 129
+    line: 3
+    character: 59
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 129
+    line: 4
+    character: 1
+  end_position:
+    bytes: 130
+    line: 4
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 130
+    line: 4
+    character: 2
+  end_position:
+    bytes: 131
+    line: 4
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 131
+    line: 5
+    character: 1
+  end_position:
+    bytes: 131
+    line: 5
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/trivia-parsing/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/trivia-parsing/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7164014c8468bde2f130a2e4edd1deb0805164c4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/trivia-parsing/ast.snap
@@ -0,0 +1,734 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/trivia-parsing
+---
+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: 9
+                    line: 1
+                    character: 10
+                  token_type:
+                    type: Identifier
+                    identifier: foo
+                trailing_trivia:
+                  - start_position:
+                      bytes: 9
+                      line: 1
+                      character: 10
+                    end_position:
+                      bytes: 10
+                      line: 1
+                      character: 11
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                Var:
+                  Name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 12
+                        line: 1
+                        character: 13
+                      end_position:
+                        bytes: 15
+                        line: 1
+                        character: 16
+                      token_type:
+                        type: Identifier
+                        identifier: bar
+                    trailing_trivia:
+                      - 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: 35
+                          line: 1
+                          character: 36
+                        token_type:
+                          type: SingleLineComment
+                          comment: " trailing comment"
+                      - start_position:
+                          bytes: 35
+                          line: 1
+                          character: 36
+                        end_position:
+                          bytes: 36
+                          line: 1
+                          character: 36
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 36
+                line: 2
+                character: 1
+              end_position:
+                bytes: 37
+                line: 2
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+            - start_position:
+                bytes: 37
+                line: 3
+                character: 1
+              end_position:
+                bytes: 55
+                line: 3
+                character: 19
+              token_type:
+                type: SingleLineComment
+                comment: " leading comment"
+            - start_position:
+                bytes: 55
+                line: 3
+                character: 19
+              end_position:
+                bytes: 56
+                line: 3
+                character: 19
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 56
+              line: 4
+              character: 1
+            end_position:
+              bytes: 61
+              line: 4
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 61
+                line: 4
+                character: 6
+              end_position:
+                bytes: 62
+                line: 4
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 62
+                    line: 4
+                    character: 7
+                  end_position:
+                    bytes: 65
+                    line: 4
+                    character: 10
+                  token_type:
+                    type: Identifier
+                    identifier: bar
+                trailing_trivia:
+                  - start_position:
+                      bytes: 65
+                      line: 4
+                      character: 10
+                    end_position:
+                      bytes: 66
+                      line: 4
+                      character: 11
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 66
+              line: 4
+              character: 11
+            end_position:
+              bytes: 67
+              line: 4
+              character: 12
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 67
+                line: 4
+                character: 12
+              end_position:
+                bytes: 68
+                line: 4
+                character: 13
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Var:
+                  Name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 68
+                        line: 4
+                        character: 13
+                      end_position:
+                        bytes: 71
+                        line: 4
+                        character: 16
+                      token_type:
+                        type: Identifier
+                        identifier: baz
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 71
+                          line: 4
+                          character: 16
+                        end_position:
+                          bytes: 72
+                          line: 4
+                          character: 16
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 72
+              line: 5
+              character: 1
+            end_position:
+              bytes: 77
+              line: 5
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 77
+                line: 5
+                character: 6
+              end_position:
+                bytes: 78
+                line: 5
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 78
+                    line: 5
+                    character: 7
+                  end_position:
+                    bytes: 81
+                    line: 5
+                    character: 10
+                  token_type:
+                    type: Identifier
+                    identifier: baz
+                trailing_trivia:
+                  - start_position:
+                      bytes: 81
+                      line: 5
+                      character: 10
+                    end_position:
+                      bytes: 82
+                      line: 5
+                      character: 11
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 82
+              line: 5
+              character: 11
+            end_position:
+              bytes: 83
+              line: 5
+              character: 12
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 83
+                line: 5
+                character: 12
+              end_position:
+                bytes: 84
+                line: 5
+                character: 13
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Var:
+                  Name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 84
+                        line: 5
+                        character: 13
+                      end_position:
+                        bytes: 87
+                        line: 5
+                        character: 16
+                      token_type:
+                        type: Identifier
+                        identifier: foo
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 87
+                          line: 5
+                          character: 16
+                        end_position:
+                          bytes: 88
+                          line: 5
+                          character: 16
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+    - ~
+  - - Do:
+        do_token:
+          leading_trivia:
+            - start_position:
+                bytes: 88
+                line: 6
+                character: 1
+              end_position:
+                bytes: 89
+                line: 6
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 89
+              line: 7
+              character: 1
+            end_position:
+              bytes: 91
+              line: 7
+              character: 3
+            token_type:
+              type: Symbol
+              symbol: do
+          trailing_trivia:
+            - start_position:
+                bytes: 91
+                line: 7
+                character: 3
+              end_position:
+                bytes: 92
+                line: 7
+                character: 3
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        block:
+          stmts:
+            - - LocalAssignment:
+                  local_token:
+                    leading_trivia:
+                      - start_position:
+                          bytes: 92
+                          line: 8
+                          character: 1
+                        end_position:
+                          bytes: 93
+                          line: 8
+                          character: 2
+                        token_type:
+                          type: Whitespace
+                          characters: "\t"
+                    token:
+                      start_position:
+                        bytes: 93
+                        line: 8
+                        character: 2
+                      end_position:
+                        bytes: 98
+                        line: 8
+                        character: 7
+                      token_type:
+                        type: Symbol
+                        symbol: local
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 98
+                          line: 8
+                          character: 7
+                        end_position:
+                          bytes: 99
+                          line: 8
+                          character: 8
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  name_list:
+                    pairs:
+                      - End:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 99
+                              line: 8
+                              character: 8
+                            end_position:
+                              bytes: 102
+                              line: 8
+                              character: 11
+                            token_type:
+                              type: Identifier
+                              identifier: foo
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 102
+                                line: 8
+                                character: 11
+                              end_position:
+                                bytes: 103
+                                line: 8
+                                character: 12
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                  equal_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 103
+                        line: 8
+                        character: 12
+                      end_position:
+                        bytes: 104
+                        line: 8
+                        character: 13
+                      token_type:
+                        type: Symbol
+                        symbol: "="
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 104
+                          line: 8
+                          character: 13
+                        end_position:
+                          bytes: 105
+                          line: 8
+                          character: 14
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  expr_list:
+                    pairs:
+                      - End:
+                          Var:
+                            Name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 105
+                                  line: 8
+                                  character: 14
+                                end_position:
+                                  bytes: 108
+                                  line: 8
+                                  character: 17
+                                token_type:
+                                  type: Identifier
+                                  identifier: bar
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 108
+                                    line: 8
+                                    character: 17
+                                  end_position:
+                                    bytes: 109
+                                    line: 8
+                                    character: 17
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\n"
+              - ~
+            - - LocalAssignment:
+                  local_token:
+                    leading_trivia:
+                      - start_position:
+                          bytes: 109
+                          line: 9
+                          character: 1
+                        end_position:
+                          bytes: 110
+                          line: 9
+                          character: 2
+                        token_type:
+                          type: Whitespace
+                          characters: "\t"
+                      - start_position:
+                          bytes: 110
+                          line: 9
+                          character: 2
+                        end_position:
+                          bytes: 120
+                          line: 9
+                          character: 12
+                        token_type:
+                          type: SingleLineComment
+                          comment: " comment"
+                      - start_position:
+                          bytes: 120
+                          line: 9
+                          character: 12
+                        end_position:
+                          bytes: 121
+                          line: 9
+                          character: 12
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+                      - start_position:
+                          bytes: 121
+                          line: 10
+                          character: 1
+                        end_position:
+                          bytes: 122
+                          line: 10
+                          character: 2
+                        token_type:
+                          type: Whitespace
+                          characters: "\t"
+                    token:
+                      start_position:
+                        bytes: 122
+                        line: 10
+                        character: 2
+                      end_position:
+                        bytes: 127
+                        line: 10
+                        character: 7
+                      token_type:
+                        type: Symbol
+                        symbol: local
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 127
+                          line: 10
+                          character: 7
+                        end_position:
+                          bytes: 128
+                          line: 10
+                          character: 8
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  name_list:
+                    pairs:
+                      - End:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 128
+                              line: 10
+                              character: 8
+                            end_position:
+                              bytes: 131
+                              line: 10
+                              character: 11
+                            token_type:
+                              type: Identifier
+                              identifier: bar
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 131
+                                line: 10
+                                character: 11
+                              end_position:
+                                bytes: 132
+                                line: 10
+                                character: 12
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                  equal_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 132
+                        line: 10
+                        character: 12
+                      end_position:
+                        bytes: 133
+                        line: 10
+                        character: 13
+                      token_type:
+                        type: Symbol
+                        symbol: "="
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 133
+                          line: 10
+                          character: 13
+                        end_position:
+                          bytes: 134
+                          line: 10
+                          character: 14
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  expr_list:
+                    pairs:
+                      - End:
+                          Var:
+                            Name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 134
+                                  line: 10
+                                  character: 14
+                                end_position:
+                                  bytes: 137
+                                  line: 10
+                                  character: 17
+                                token_type:
+                                  type: Identifier
+                                  identifier: baz
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 137
+                                    line: 10
+                                    character: 17
+                                  end_position:
+                                    bytes: 138
+                                    line: 10
+                                    character: 17
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\n"
+              - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 138
+              line: 11
+              character: 1
+            end_position:
+              bytes: 141
+              line: 11
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/trivia-parsing/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/trivia-parsing/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..702108ccbe2e016760b8c8277480a0f5d59ae754
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/trivia-parsing/source.lua
@@ -0,0 +1,11 @@
+local foo = bar -- trailing comment
+
+-- leading comment
+local bar = baz
+local baz = foo
+
+do
+	local foo = bar
+	-- comment
+	local bar = baz
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/trivia-parsing/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/trivia-parsing/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9d60f0338aa9a361a0181397f104cdcb2050779a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/trivia-parsing/tokens.snap
@@ -0,0 +1,611 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/trivia-parsing
+
+---
+- 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: 9
+    line: 1
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: foo
+- 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: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 15
+    line: 1
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: bar
+- 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: 35
+    line: 1
+    character: 36
+  token_type:
+    type: SingleLineComment
+    comment: " trailing comment"
+- start_position:
+    bytes: 35
+    line: 1
+    character: 36
+  end_position:
+    bytes: 36
+    line: 1
+    character: 36
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 36
+    line: 2
+    character: 1
+  end_position:
+    bytes: 37
+    line: 2
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 37
+    line: 3
+    character: 1
+  end_position:
+    bytes: 55
+    line: 3
+    character: 19
+  token_type:
+    type: SingleLineComment
+    comment: " leading comment"
+- start_position:
+    bytes: 55
+    line: 3
+    character: 19
+  end_position:
+    bytes: 56
+    line: 3
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 56
+    line: 4
+    character: 1
+  end_position:
+    bytes: 61
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 61
+    line: 4
+    character: 6
+  end_position:
+    bytes: 62
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 62
+    line: 4
+    character: 7
+  end_position:
+    bytes: 65
+    line: 4
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 65
+    line: 4
+    character: 10
+  end_position:
+    bytes: 66
+    line: 4
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 66
+    line: 4
+    character: 11
+  end_position:
+    bytes: 67
+    line: 4
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 67
+    line: 4
+    character: 12
+  end_position:
+    bytes: 68
+    line: 4
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 68
+    line: 4
+    character: 13
+  end_position:
+    bytes: 71
+    line: 4
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 71
+    line: 4
+    character: 16
+  end_position:
+    bytes: 72
+    line: 4
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 72
+    line: 5
+    character: 1
+  end_position:
+    bytes: 77
+    line: 5
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 77
+    line: 5
+    character: 6
+  end_position:
+    bytes: 78
+    line: 5
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 78
+    line: 5
+    character: 7
+  end_position:
+    bytes: 81
+    line: 5
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 81
+    line: 5
+    character: 10
+  end_position:
+    bytes: 82
+    line: 5
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 82
+    line: 5
+    character: 11
+  end_position:
+    bytes: 83
+    line: 5
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 83
+    line: 5
+    character: 12
+  end_position:
+    bytes: 84
+    line: 5
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 84
+    line: 5
+    character: 13
+  end_position:
+    bytes: 87
+    line: 5
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 87
+    line: 5
+    character: 16
+  end_position:
+    bytes: 88
+    line: 5
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 88
+    line: 6
+    character: 1
+  end_position:
+    bytes: 89
+    line: 6
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 89
+    line: 7
+    character: 1
+  end_position:
+    bytes: 91
+    line: 7
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 91
+    line: 7
+    character: 3
+  end_position:
+    bytes: 92
+    line: 7
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 92
+    line: 8
+    character: 1
+  end_position:
+    bytes: 93
+    line: 8
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 93
+    line: 8
+    character: 2
+  end_position:
+    bytes: 98
+    line: 8
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 98
+    line: 8
+    character: 7
+  end_position:
+    bytes: 99
+    line: 8
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 99
+    line: 8
+    character: 8
+  end_position:
+    bytes: 102
+    line: 8
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 102
+    line: 8
+    character: 11
+  end_position:
+    bytes: 103
+    line: 8
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 103
+    line: 8
+    character: 12
+  end_position:
+    bytes: 104
+    line: 8
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 104
+    line: 8
+    character: 13
+  end_position:
+    bytes: 105
+    line: 8
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 105
+    line: 8
+    character: 14
+  end_position:
+    bytes: 108
+    line: 8
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 108
+    line: 8
+    character: 17
+  end_position:
+    bytes: 109
+    line: 8
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 109
+    line: 9
+    character: 1
+  end_position:
+    bytes: 110
+    line: 9
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 110
+    line: 9
+    character: 2
+  end_position:
+    bytes: 120
+    line: 9
+    character: 12
+  token_type:
+    type: SingleLineComment
+    comment: " comment"
+- start_position:
+    bytes: 120
+    line: 9
+    character: 12
+  end_position:
+    bytes: 121
+    line: 9
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 121
+    line: 10
+    character: 1
+  end_position:
+    bytes: 122
+    line: 10
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 122
+    line: 10
+    character: 2
+  end_position:
+    bytes: 127
+    line: 10
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 127
+    line: 10
+    character: 7
+  end_position:
+    bytes: 128
+    line: 10
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 128
+    line: 10
+    character: 8
+  end_position:
+    bytes: 131
+    line: 10
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 131
+    line: 10
+    character: 11
+  end_position:
+    bytes: 132
+    line: 10
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 132
+    line: 10
+    character: 12
+  end_position:
+    bytes: 133
+    line: 10
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 133
+    line: 10
+    character: 13
+  end_position:
+    bytes: 134
+    line: 10
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 134
+    line: 10
+    character: 14
+  end_position:
+    bytes: 137
+    line: 10
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 137
+    line: 10
+    character: 17
+  end_position:
+    bytes: 138
+    line: 10
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 138
+    line: 11
+    character: 1
+  end_position:
+    bytes: 141
+    line: 11
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 141
+    line: 11
+    character: 4
+  end_position:
+    bytes: 141
+    line: 11
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/unops/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/unops/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..da0e77602e4f5484039fb96ee97de19f6e1826f7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/unops/ast.snap
@@ -0,0 +1,667 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/unops
+---
+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: 21
+                    line: 1
+                    character: 22
+                  token_type:
+                    type: Identifier
+                    identifier: negativeLiteral
+                trailing_trivia:
+                  - start_position:
+                      bytes: 21
+                      line: 1
+                      character: 22
+                    end_position:
+                      bytes: 22
+                      line: 1
+                      character: 23
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                UnaryOperator:
+                  unop:
+                    Minus:
+                      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: []
+                  expression:
+                    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: "3"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 26
+                            line: 1
+                            character: 27
+                          end_position:
+                            bytes: 27
+                            line: 1
+                            character: 27
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 27
+              line: 2
+              character: 1
+            end_position:
+              bytes: 32
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 32
+                line: 2
+                character: 6
+              end_position:
+                bytes: 33
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 33
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 49
+                    line: 2
+                    character: 23
+                  token_type:
+                    type: Identifier
+                    identifier: negativeVariable
+                trailing_trivia:
+                  - start_position:
+                      bytes: 49
+                      line: 2
+                      character: 23
+                    end_position:
+                      bytes: 50
+                      line: 2
+                      character: 24
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 50
+              line: 2
+              character: 24
+            end_position:
+              bytes: 51
+              line: 2
+              character: 25
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 51
+                line: 2
+                character: 25
+              end_position:
+                bytes: 52
+                line: 2
+                character: 26
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                UnaryOperator:
+                  unop:
+                    Minus:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 52
+                          line: 2
+                          character: 26
+                        end_position:
+                          bytes: 53
+                          line: 2
+                          character: 27
+                        token_type:
+                          type: Symbol
+                          symbol: "-"
+                      trailing_trivia: []
+                  expression:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 53
+                            line: 2
+                            character: 27
+                          end_position:
+                            bytes: 54
+                            line: 2
+                            character: 28
+                          token_type:
+                            type: Identifier
+                            identifier: x
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 54
+                              line: 2
+                              character: 28
+                            end_position:
+                              bytes: 55
+                              line: 2
+                              character: 28
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 55
+              line: 3
+              character: 1
+            end_position:
+              bytes: 60
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 60
+                line: 3
+                character: 6
+              end_position:
+                bytes: 61
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 61
+                    line: 3
+                    character: 7
+                  end_position:
+                    bytes: 71
+                    line: 3
+                    character: 17
+                  token_type:
+                    type: Identifier
+                    identifier: notLiteral
+                trailing_trivia:
+                  - start_position:
+                      bytes: 71
+                      line: 3
+                      character: 17
+                    end_position:
+                      bytes: 72
+                      line: 3
+                      character: 18
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 72
+              line: 3
+              character: 18
+            end_position:
+              bytes: 73
+              line: 3
+              character: 19
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 73
+                line: 3
+                character: 19
+              end_position:
+                bytes: 74
+                line: 3
+                character: 20
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                UnaryOperator:
+                  unop:
+                    Not:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 74
+                          line: 3
+                          character: 20
+                        end_position:
+                          bytes: 77
+                          line: 3
+                          character: 23
+                        token_type:
+                          type: Symbol
+                          symbol: not
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 77
+                            line: 3
+                            character: 23
+                          end_position:
+                            bytes: 78
+                            line: 3
+                            character: 24
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  expression:
+                    Symbol:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 78
+                          line: 3
+                          character: 24
+                        end_position:
+                          bytes: 82
+                          line: 3
+                          character: 28
+                        token_type:
+                          type: Symbol
+                          symbol: "true"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 82
+                            line: 3
+                            character: 28
+                          end_position:
+                            bytes: 83
+                            line: 3
+                            character: 28
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 83
+              line: 4
+              character: 1
+            end_position:
+              bytes: 88
+              line: 4
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 88
+                line: 4
+                character: 6
+              end_position:
+                bytes: 89
+                line: 4
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 89
+                    line: 4
+                    character: 7
+                  end_position:
+                    bytes: 100
+                    line: 4
+                    character: 18
+                  token_type:
+                    type: Identifier
+                    identifier: notVariable
+                trailing_trivia:
+                  - start_position:
+                      bytes: 100
+                      line: 4
+                      character: 18
+                    end_position:
+                      bytes: 101
+                      line: 4
+                      character: 19
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 101
+              line: 4
+              character: 19
+            end_position:
+              bytes: 102
+              line: 4
+              character: 20
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 102
+                line: 4
+                character: 20
+              end_position:
+                bytes: 103
+                line: 4
+                character: 21
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                UnaryOperator:
+                  unop:
+                    Not:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 103
+                          line: 4
+                          character: 21
+                        end_position:
+                          bytes: 106
+                          line: 4
+                          character: 24
+                        token_type:
+                          type: Symbol
+                          symbol: not
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 106
+                            line: 4
+                            character: 24
+                          end_position:
+                            bytes: 107
+                            line: 4
+                            character: 25
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  expression:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 107
+                            line: 4
+                            character: 25
+                          end_position:
+                            bytes: 108
+                            line: 4
+                            character: 26
+                          token_type:
+                            type: Identifier
+                            identifier: x
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 108
+                              line: 4
+                              character: 26
+                            end_position:
+                              bytes: 109
+                              line: 4
+                              character: 26
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 109
+              line: 5
+              character: 1
+            end_position:
+              bytes: 114
+              line: 5
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 114
+                line: 5
+                character: 6
+              end_position:
+                bytes: 115
+                line: 5
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 115
+                    line: 5
+                    character: 7
+                  end_position:
+                    bytes: 121
+                    line: 5
+                    character: 13
+                  token_type:
+                    type: Identifier
+                    identifier: length
+                trailing_trivia:
+                  - start_position:
+                      bytes: 121
+                      line: 5
+                      character: 13
+                    end_position:
+                      bytes: 122
+                      line: 5
+                      character: 14
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 122
+              line: 5
+              character: 14
+            end_position:
+              bytes: 123
+              line: 5
+              character: 15
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 123
+                line: 5
+                character: 15
+              end_position:
+                bytes: 124
+                line: 5
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                UnaryOperator:
+                  unop:
+                    Hash:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 124
+                          line: 5
+                          character: 16
+                        end_position:
+                          bytes: 125
+                          line: 5
+                          character: 17
+                        token_type:
+                          type: Symbol
+                          symbol: "#"
+                      trailing_trivia: []
+                  expression:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 125
+                            line: 5
+                            character: 17
+                          end_position:
+                            bytes: 126
+                            line: 5
+                            character: 18
+                          token_type:
+                            type: Identifier
+                            identifier: x
+                        trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/unops/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/unops/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..47d8330ddf02bc7ff3464f6d33275e735a35015d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/unops/source.lua
@@ -0,0 +1,5 @@
+local negativeLiteral = -3
+local negativeVariable = -x
+local notLiteral = not true
+local notVariable = not x
+local length = #x
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/unops/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/unops/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5101a9d9832bf224b6e1577241e7d17235f997e0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/unops/tokens.snap
@@ -0,0 +1,523 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/unops
+
+---
+- 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: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Identifier
+    identifier: negativeLiteral
+- 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: 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: Number
+    text: "3"
+- start_position:
+    bytes: 26
+    line: 1
+    character: 27
+  end_position:
+    bytes: 27
+    line: 1
+    character: 27
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 27
+    line: 2
+    character: 1
+  end_position:
+    bytes: 32
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 32
+    line: 2
+    character: 6
+  end_position:
+    bytes: 33
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 33
+    line: 2
+    character: 7
+  end_position:
+    bytes: 49
+    line: 2
+    character: 23
+  token_type:
+    type: Identifier
+    identifier: negativeVariable
+- start_position:
+    bytes: 49
+    line: 2
+    character: 23
+  end_position:
+    bytes: 50
+    line: 2
+    character: 24
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 50
+    line: 2
+    character: 24
+  end_position:
+    bytes: 51
+    line: 2
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 51
+    line: 2
+    character: 25
+  end_position:
+    bytes: 52
+    line: 2
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 52
+    line: 2
+    character: 26
+  end_position:
+    bytes: 53
+    line: 2
+    character: 27
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 53
+    line: 2
+    character: 27
+  end_position:
+    bytes: 54
+    line: 2
+    character: 28
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 54
+    line: 2
+    character: 28
+  end_position:
+    bytes: 55
+    line: 2
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 55
+    line: 3
+    character: 1
+  end_position:
+    bytes: 60
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 60
+    line: 3
+    character: 6
+  end_position:
+    bytes: 61
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 61
+    line: 3
+    character: 7
+  end_position:
+    bytes: 71
+    line: 3
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: notLiteral
+- start_position:
+    bytes: 71
+    line: 3
+    character: 17
+  end_position:
+    bytes: 72
+    line: 3
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 72
+    line: 3
+    character: 18
+  end_position:
+    bytes: 73
+    line: 3
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 73
+    line: 3
+    character: 19
+  end_position:
+    bytes: 74
+    line: 3
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 74
+    line: 3
+    character: 20
+  end_position:
+    bytes: 77
+    line: 3
+    character: 23
+  token_type:
+    type: Symbol
+    symbol: not
+- start_position:
+    bytes: 77
+    line: 3
+    character: 23
+  end_position:
+    bytes: 78
+    line: 3
+    character: 24
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 78
+    line: 3
+    character: 24
+  end_position:
+    bytes: 82
+    line: 3
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 82
+    line: 3
+    character: 28
+  end_position:
+    bytes: 83
+    line: 3
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 83
+    line: 4
+    character: 1
+  end_position:
+    bytes: 88
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 88
+    line: 4
+    character: 6
+  end_position:
+    bytes: 89
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 89
+    line: 4
+    character: 7
+  end_position:
+    bytes: 100
+    line: 4
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: notVariable
+- start_position:
+    bytes: 100
+    line: 4
+    character: 18
+  end_position:
+    bytes: 101
+    line: 4
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 101
+    line: 4
+    character: 19
+  end_position:
+    bytes: 102
+    line: 4
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 102
+    line: 4
+    character: 20
+  end_position:
+    bytes: 103
+    line: 4
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 103
+    line: 4
+    character: 21
+  end_position:
+    bytes: 106
+    line: 4
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: not
+- start_position:
+    bytes: 106
+    line: 4
+    character: 24
+  end_position:
+    bytes: 107
+    line: 4
+    character: 25
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 107
+    line: 4
+    character: 25
+  end_position:
+    bytes: 108
+    line: 4
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 108
+    line: 4
+    character: 26
+  end_position:
+    bytes: 109
+    line: 4
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 109
+    line: 5
+    character: 1
+  end_position:
+    bytes: 114
+    line: 5
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 114
+    line: 5
+    character: 6
+  end_position:
+    bytes: 115
+    line: 5
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 115
+    line: 5
+    character: 7
+  end_position:
+    bytes: 121
+    line: 5
+    character: 13
+  token_type:
+    type: Identifier
+    identifier: length
+- start_position:
+    bytes: 121
+    line: 5
+    character: 13
+  end_position:
+    bytes: 122
+    line: 5
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 122
+    line: 5
+    character: 14
+  end_position:
+    bytes: 123
+    line: 5
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 123
+    line: 5
+    character: 15
+  end_position:
+    bytes: 124
+    line: 5
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 124
+    line: 5
+    character: 16
+  end_position:
+    bytes: 125
+    line: 5
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "#"
+- start_position:
+    bytes: 125
+    line: 5
+    character: 17
+  end_position:
+    bytes: 126
+    line: 5
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 126
+    line: 5
+    character: 18
+  end_position:
+    bytes: 126
+    line: 5
+    character: 18
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/utf-8/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/utf-8/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cc9212d6db8ff5871e55488e97b82cf1d165e428
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/utf-8/ast.snap
@@ -0,0 +1,136 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/utf-8
+---
+stmts:
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 0
+                line: 1
+                character: 1
+              end_position:
+                bytes: 5
+                line: 1
+                character: 6
+              token_type:
+                type: Identifier
+                identifier: print
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 5
+                            line: 1
+                            character: 6
+                          end_position:
+                            bytes: 6
+                            line: 1
+                            character: 7
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 24
+                            line: 1
+                            character: 22
+                          end_position:
+                            bytes: 25
+                            line: 1
+                            character: 23
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia: []
+                  arguments:
+                    pairs:
+                      - End:
+                          BinaryOperator:
+                            lhs:
+                              String:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 6
+                                    line: 1
+                                    character: 7
+                                  end_position:
+                                    bytes: 13
+                                    line: 1
+                                    character: 11
+                                  token_type:
+                                    type: StringLiteral
+                                    literal: "👚 "
+                                    quote_type: Double
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 13
+                                      line: 1
+                                      character: 11
+                                    end_position:
+                                      bytes: 14
+                                      line: 1
+                                      character: 12
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                            binop:
+                              TwoDots:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 14
+                                    line: 1
+                                    character: 12
+                                  end_position:
+                                    bytes: 16
+                                    line: 1
+                                    character: 14
+                                  token_type:
+                                    type: Symbol
+                                    symbol: ".."
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 16
+                                      line: 1
+                                      character: 14
+                                    end_position:
+                                      bytes: 17
+                                      line: 1
+                                      character: 15
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                            rhs:
+                              Var:
+                                Name:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 17
+                                      line: 1
+                                      character: 15
+                                    end_position:
+                                      bytes: 24
+                                      line: 1
+                                      character: 22
+                                    token_type:
+                                      type: Identifier
+                                      identifier: message
+                                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/utf-8/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/utf-8/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2f69a435e2c49caeff7418f261d185b5adde63fd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/utf-8/source.lua
@@ -0,0 +1 @@
+print("👚 " .. message)
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/utf-8/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/utf-8/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9f6d50f11f009a353270107eda145aef19af055c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/utf-8/tokens.snap
@@ -0,0 +1,106 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/utf-8
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: print
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 13
+    line: 1
+    character: 11
+  token_type:
+    type: StringLiteral
+    literal: "👚 "
+    quote_type: Double
+- start_position:
+    bytes: 13
+    line: 1
+    character: 11
+  end_position:
+    bytes: 14
+    line: 1
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 14
+    line: 1
+    character: 12
+  end_position:
+    bytes: 16
+    line: 1
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: ".."
+- start_position:
+    bytes: 16
+    line: 1
+    character: 14
+  end_position:
+    bytes: 17
+    line: 1
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 17
+    line: 1
+    character: 15
+  end_position:
+    bytes: 24
+    line: 1
+    character: 22
+  token_type:
+    type: Identifier
+    identifier: message
+- start_position:
+    bytes: 24
+    line: 1
+    character: 22
+  end_position:
+    bytes: 25
+    line: 1
+    character: 23
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 25
+    line: 1
+    character: 23
+  end_position:
+    bytes: 25
+    line: 1
+    character: 23
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/while/ast.snap b/src/Rust/vvs_parser/src/tests/cases/pass/while/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..081c5300112b29f5e32742796884d05502add1f7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/while/ast.snap
@@ -0,0 +1,222 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/cases/pass/while
+---
+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:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 6
+                  line: 1
+                  character: 7
+                end_position:
+                  bytes: 15
+                  line: 1
+                  character: 16
+                token_type:
+                  type: Identifier
+                  identifier: condition
+              trailing_trivia:
+                - start_position:
+                    bytes: 15
+                    line: 1
+                    character: 16
+                  end_position:
+                    bytes: 16
+                    line: 1
+                    character: 17
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+        do_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 16
+              line: 1
+              character: 17
+            end_position:
+              bytes: 18
+              line: 1
+              character: 19
+            token_type:
+              type: Symbol
+              symbol: do
+          trailing_trivia:
+            - start_position:
+                bytes: 18
+                line: 1
+                character: 19
+              end_position:
+                bytes: 19
+                line: 1
+                character: 19
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        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:
+                                    - start_position:
+                                        bytes: 26
+                                        line: 2
+                                        character: 8
+                                      end_position:
+                                        bytes: 27
+                                        line: 2
+                                        character: 8
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\n"
+                            arguments:
+                              pairs: []
+              - ~
+          last_stmt:
+            - Break:
+                leading_trivia:
+                  - start_position:
+                      bytes: 27
+                      line: 3
+                      character: 1
+                    end_position:
+                      bytes: 28
+                      line: 3
+                      character: 2
+                    token_type:
+                      type: Whitespace
+                      characters: "\t"
+                token:
+                  start_position:
+                    bytes: 28
+                    line: 3
+                    character: 2
+                  end_position:
+                    bytes: 33
+                    line: 3
+                    character: 7
+                  token_type:
+                    type: Symbol
+                    symbol: break
+                trailing_trivia:
+                  - start_position:
+                      bytes: 33
+                      line: 3
+                      character: 7
+                    end_position:
+                      bytes: 34
+                      line: 3
+                      character: 7
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+            - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 34
+              line: 4
+              character: 1
+            end_position:
+              bytes: 37
+              line: 4
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/while/source.lua b/src/Rust/vvs_parser/src/tests/cases/pass/while/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0fe6ecf3e9cc473d70d29f8709c2efe297f5726b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/while/source.lua
@@ -0,0 +1,4 @@
+while condition do
+	call()
+	break
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/cases/pass/while/tokens.snap b/src/Rust/vvs_parser/src/tests/cases/pass/while/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7d618d483aa98523b326ca8131b6626829b41579
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/cases/pass/while/tokens.snap
@@ -0,0 +1,182 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/cases/pass/while
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: while
+- 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: 15
+    line: 1
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: condition
+- 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: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: do
+- 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: 24
+    line: 2
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: call
+- start_position:
+    bytes: 24
+    line: 2
+    character: 6
+  end_position:
+    bytes: 25
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 25
+    line: 2
+    character: 7
+  end_position:
+    bytes: 26
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 26
+    line: 2
+    character: 8
+  end_position:
+    bytes: 27
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 27
+    line: 3
+    character: 1
+  end_position:
+    bytes: 28
+    line: 3
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 28
+    line: 3
+    character: 2
+  end_position:
+    bytes: 33
+    line: 3
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: break
+- start_position:
+    bytes: 33
+    line: 3
+    character: 7
+  end_position:
+    bytes: 34
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 34
+    line: 4
+    character: 1
+  end_position:
+    bytes: 37
+    line: 4
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 37
+    line: 4
+    character: 4
+  end_position:
+    bytes: 37
+    line: 4
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/comments_around_functions.rs b/src/Rust/vvs_parser/src/tests/comments_around_functions.rs
new file mode 100644
index 0000000000000000000000000000000000000000..dfa197804fd6295216ab214e92503afc9aad7d20
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/comments_around_functions.rs
@@ -0,0 +1,52 @@
+// This is code from a real life usage of full-moon
+
+use crate::{ast::*, node::Node, tokenizer::TokenKind, visitors::Visitor};
+
+const CODE: &str = r#"
+
+local Module = {}
+Module.__index = Module
+
+--[[
+    Creates a new instance of Module.
+
+    ```lua
+        Module.new()
+    ```
+
+    @static
+    @param name string - This is the name for this Module.
+    @returns Module - Returns the new Module!
+]]
+function Module.new(name)
+
+end
+
+"#;
+
+struct MemberVisitor {
+    comments: Vec<String>,
+}
+
+impl Visitor for MemberVisitor {
+    fn visit_function_declaration(&mut self, function: &FunctionDeclaration) {
+        let (tokens, _) = function.surrounding_trivia();
+        let mut tokens = tokens;
+        tokens.retain(|t| t.token_kind() == TokenKind::MultiLineComment);
+        self.comments
+            .extend(tokens.into_iter().map(|t| t.to_string()).collect::<Vec<String>>())
+    }
+}
+
+fn generate() -> Result<(), Vec<crate::Error>> {
+    let ast = crate::prelude::parser::parse_lua_tree(CODE)?;
+    let mut visitor = MemberVisitor { comments: Vec::new() };
+    visitor.visit_ast(&ast);
+    println!("{:?}", visitor.comments);
+    Ok(())
+}
+
+#[test]
+fn test() {
+    generate().expect("Oh");
+}
diff --git a/src/Rust/vvs_parser/src/tests/common.rs b/src/Rust/vvs_parser/src/tests/common.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c484fa2f5fdb56d1637d4d45d64ad4b24f404cb6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/common.rs
@@ -0,0 +1,19 @@
+use std::fs;
+use std::path::Path;
+
+fn with_insta_settings(path: &Path, f: impl FnOnce()) {
+    let mut settings = insta::Settings::clone_current();
+    settings.set_prepend_module_to_snapshot(false);
+    settings.set_snapshot_path(path);
+    settings.set_input_file(path);
+    settings.bind(f)
+}
+
+pub fn run_test_folder<P: AsRef<Path>>(folder: P, test_fn: impl Fn(&Path)) {
+    for entry in fs::read_dir(folder).expect("couldn't read directory") {
+        let entry = entry.unwrap();
+        let path = entry.path().canonicalize().unwrap();
+        dbg!(entry.path().to_string_lossy());
+        with_insta_settings(&path, || test_fn(&path))
+    }
+}
diff --git a/src/Rust/vvs_parser/src/tests/derive_node.rs b/src/Rust/vvs_parser/src/tests/derive_node.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ef4e837fb461acd6360163c933806381c6c469f0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/derive_node.rs
@@ -0,0 +1,32 @@
+use crate::{ast, node::Node, prelude::parser::parse_lua_tree as parse, visitors::Visitor};
+
+const MIN_MAX_CODE: &str = "local x = { 1, 2, 3 }";
+
+#[test]
+fn test_position_min_max() {
+    struct TestVisitor(bool);
+
+    impl Visitor for TestVisitor {
+        fn visit_table_constructor(&mut self, constructor: &ast::TableConstructor) {
+            self.0 = true;
+            assert_eq!(
+                MIN_MAX_CODE
+                    .as_bytes()
+                    .get(constructor.start_position().unwrap().bytes()),
+                Some(&b'{')
+            );
+            assert_eq!(
+                MIN_MAX_CODE
+                    .as_bytes()
+                    .get(constructor.end_position().unwrap().bytes() - 1),
+                Some(&b'}')
+            );
+        }
+    }
+
+    let ast = parse(MIN_MAX_CODE).unwrap();
+
+    let mut visitor = TestVisitor(false);
+    visitor.visit_ast(&ast);
+    assert!(visitor.0, "TableConstructor was never found");
+}
diff --git a/src/Rust/vvs_parser/src/tests/fail_cases.rs b/src/Rust/vvs_parser/src/tests/fail_cases.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a8461cd7736f16e525b3bb19876967dc5faddf62
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/fail_cases.rs
@@ -0,0 +1,94 @@
+use crate::{ast::AstResult, tests::common::run_test_folder, tokenizer};
+use codespan_reporting::{
+    diagnostic::{Diagnostic, Label},
+    files::SimpleFiles,
+};
+use insta::{assert_snapshot, assert_yaml_snapshot};
+use std::fs;
+
+fn process_codespan_display(source_name: &str, source: &str, errors: &[crate::Error]) {
+    let mut files = SimpleFiles::new();
+    let file_id = files.add(source_name, source);
+    let config = codespan_reporting::term::Config::default();
+    let mut output = termcolor::NoColor::new(Vec::new());
+
+    for error in errors {
+        let range = error.range();
+        let diagnostic = Diagnostic::error()
+            .with_message(error.error_message())
+            .with_code(match error {
+                crate::Error::AstError(_) => "ast",
+                crate::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_snapshot!("error_display", String::from_utf8(output.into_inner()).unwrap());
+}
+
+fn run_parser_fail_cases(folder: &str) {
+    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).collect().unwrap();
+        assert_yaml_snapshot!("tokens", tokens);
+
+        let result = AstResult::parse_fallible(&source);
+
+        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.lua", &source, result.errors());
+
+        let ast = result.into_ast().update_positions();
+        assert_yaml_snapshot!("ast_to_string", format!("{ast}"));
+    });
+}
+
+#[test]
+fn test_roblox_parser_fail_cases() {
+    run_parser_fail_cases("./src/tests/roblox_cases/fail/parser");
+}
+
+#[test]
+fn test_lua52_parser_fail_cases() {
+    run_parser_fail_cases("./src/tests/lua52_cases/fail/parser");
+}
+
+#[test]
+fn test_lua53_parser_fail_cases() {
+    run_parser_fail_cases("./src/tests/lua53_cases/fail/parser");
+}
+
+#[test]
+fn test_lua54_parser_fail_cases() {
+    run_parser_fail_cases("./src/tests/lua54_cases/fail/parser");
+}
+
+#[test]
+fn test_vivy_parser_fail_cases() {
+    run_parser_fail_cases("./src/tests/vivy_cases/fail/parser");
+}
+
+#[test]
+fn test_option_parser_fail_cases() {
+    run_test_folder("./src/tests/option_cases/fail/parser", |path| {
+        let source = fs::read_to_string(path.join("source.ini")).expect("couldn't read source.ini");
+        let tokens = tokenizer::Lexer::new(&source).collect().unwrap();
+        assert_yaml_snapshot!("tokens", tokens);
+
+        let result = crate::ast::OptionTableResult::parse_fallible(&source);
+        if result.errors().is_empty() {
+            panic!("fail case passed for {path:?}");
+        }
+
+        assert_yaml_snapshot!("errors", result.errors());
+        assert_yaml_snapshot!("option_table", result.option_table());
+
+        process_codespan_display("source.ini", &source, result.errors());
+    });
+}
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/ast.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b43eda27a59dc1ef94fbcc0d907bb05879296e48
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/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-1
+---
+nodes:
+  stmts: []
+eof:
+  leading_trivia: []
+  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/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3ae24382142dd91330df32526e46642a358dddcc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/lua52_cases/fail/parser/goto-1
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/error_display.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..59b9a7010d9970da57a525da3366e8f678eeb151
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/error_display.snap
@@ -0,0 +1,11 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+assertion_line: 53
+expression: "String::from_utf8(output.into_inner()).unwrap()"
+input_file: vvs_parser/tests/lua52_cases/fail/parser/goto-1
+---
+error[ast]: unexpected expression when looking for a statement
+  ┌─ source.lua:1:5
+  │
+1 │ goto
+  │     ^
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/errors.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..892b3f6c83c0e12ae7beee9260cba56ccbe54528
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/errors.snap
@@ -0,0 +1,19 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+assertion_line: 22
+expression: result.errors()
+input_file: vvs_parser/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: unexpected expression when looking for a statement
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/source.lua b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..cce75b692468bd159c75a41b4876187b99a956e7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/source.lua
@@ -0,0 +1 @@
+goto
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/tokens.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7ae0d19319ef95651af93e4925a32011afcf7364
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/goto-1/tokens.snap
@@ -0,0 +1,27 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+assertion_line: 60
+expression: tokens
+input_file: vvs_parser/tests/lua52_cases/fail/parser/goto-1
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: goto
+- start_position:
+    bytes: 4
+    line: 1
+    character: 5
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/ast.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ddf9510e690768d8843f0484a5c3c9ba8e92a811
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/ast.snap
@@ -0,0 +1,22 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+assertion_line: 23
+expression: result.ast()
+input_file: vvs_parser/tests/lua52_cases/fail/parser/label-1
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b3b47b03e9ada211ebb14940a6de6b9620e860cc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/ast_to_string.snap
@@ -0,0 +1,7 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+assertion_line: 28
+expression: "vvs_parser::print(&ast)"
+input_file: vvs_parser/tests/lua52_cases/fail/parser/label-1
+---
+""
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/error_display.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d102ab01c8adb995490c0761a8e7a4e0c1c98f08
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/error_display.snap
@@ -0,0 +1,17 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+assertion_line: 53
+expression: "String::from_utf8(output.into_inner()).unwrap()"
+input_file: vvs_parser/tests/lua52_cases/fail/parser/label-1
+---
+error[ast]: unexpected token, this needs to be a statement
+  ┌─ source.lua:1:1
+  │
+1 │ ::label
+  │ ^^
+
+error[ast]: unexpected expression when looking for a statement
+  ┌─ source.lua:1:8
+  │
+1 │ ::label
+  │        ^
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/errors.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..105e410b1588d0ec0700771ca4b0103bbf810077
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/errors.snap
@@ -0,0 +1,33 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+assertion_line: 22
+expression: result.errors()
+input_file: vvs_parser/tests/lua52_cases/fail/parser/label-1
+---
+- AstError:
+    token:
+      start_position:
+        bytes: 0
+        line: 1
+        character: 1
+      end_position:
+        bytes: 2
+        line: 1
+        character: 3
+      token_type:
+        type: Symbol
+        symbol: "::"
+    additional: "unexpected token, this needs to be 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: unexpected expression when looking for a statement
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/source.lua b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..4ef49c49f456acc613ac8f7c8cc34aba1ae436df
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/source.lua
@@ -0,0 +1 @@
+::label
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/tokens.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..897e38791c519490c708c4c0992e197ee4a0a02e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-1/tokens.snap
@@ -0,0 +1,39 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/lua52_cases/fail/parser/label-1
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 2
+    line: 1
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: "::"
+- start_position:
+    bytes: 2
+    line: 1
+    character: 3
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: label
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/ast.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..978cd6d9a5a2b6e4e4c2d93fde8fe553a6f696ce
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/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/label-2
+---
+nodes:
+  stmts: []
+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/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ff6f72223eb08c47e627964e36fe7572e5508cc0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/lua52_cases/fail/parser/label-2
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/error_display.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c93bc34ffcc3e65386a9e8cd72dd9271df4f58c3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/error_display.snap
@@ -0,0 +1,17 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+assertion_line: 53
+expression: "String::from_utf8(output.into_inner()).unwrap()"
+input_file: vvs_parser/tests/lua52_cases/fail/parser/label-2
+---
+error[ast]: unexpected expression when looking for a statement
+  ┌─ source.lua:1:6
+  │
+1 │ label::
+  │      ^^
+
+error[ast]: unexpected token, this needs to be a statement
+  ┌─ source.lua:1:6
+  │
+1 │ label::
+  │      ^^
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/errors.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..14bd5089782f1455f3a5d0520e33503488825043
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/errors.snap
@@ -0,0 +1,34 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+assertion_line: 22
+expression: result.errors()
+input_file: vvs_parser/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: 5
+        line: 1
+        character: 6
+      end_position:
+        bytes: 7
+        line: 1
+        character: 8
+      token_type:
+        type: Symbol
+        symbol: "::"
+    additional: "unexpected token, this needs to be a statement"
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/source.lua b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..6a8a2de76629ac8dfcfe02c248742fae405c019f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/source.lua
@@ -0,0 +1 @@
+label::
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/tokens.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6a18496e22277edd7e5f8d83a3d67299457c8b37
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/fail/parser/label-2/tokens.snap
@@ -0,0 +1,39 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+input_file: full-moon/tests/lua52_cases/fail/parser/label-2
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: label
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: "::"
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/pass/not-z-escape-string/ast.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/not-z-escape-string/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f087bb32dd3d8cb2c2e62432c097d23a39350594
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/not-z-escape-string/ast.snap
@@ -0,0 +1,79 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/lua52_cases/pass/not-z-escape-string
+---
+stmts:
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 0
+                line: 1
+                character: 1
+              end_position:
+                bytes: 5
+                line: 1
+                character: 6
+              token_type:
+                type: Identifier
+                identifier: print
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 5
+                            line: 1
+                            character: 6
+                          end_position:
+                            bytes: 6
+                            line: 1
+                            character: 7
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 28
+                            line: 2
+                            character: 12
+                          end_position:
+                            bytes: 29
+                            line: 2
+                            character: 13
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia: []
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 6
+                                line: 1
+                                character: 7
+                              end_position:
+                                bytes: 28
+                                line: 2
+                                character: 12
+                              token_type:
+                                type: StringLiteral
+                                literal: "testing \\\n\t   twelve"
+                                quote_type: Double
+                            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/pass/not-z-escape-string/source.lua b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/not-z-escape-string/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..05b5128a640c1e659d836665fd3650ecad49d77d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/not-z-escape-string/source.lua
@@ -0,0 +1,2 @@
+print("testing \
+	   twelve")
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/pass/not-z-escape-string/tokens.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/not-z-escape-string/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b07bc0577121e8f50ef1bb459e17bcd5fe7cb32c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/not-z-escape-string/tokens.snap
@@ -0,0 +1,60 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: print
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 28
+    line: 2
+    character: 12
+  token_type:
+    type: StringLiteral
+    literal: "testing \\\n\t   twelve"
+    quote_type: Double
+- start_position:
+    bytes: 28
+    line: 2
+    character: 12
+  end_position:
+    bytes: 29
+    line: 2
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 29
+    line: 2
+    character: 13
+  end_position:
+    bytes: 29
+    line: 2
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/pass/numbers/ast.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/numbers/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..59fb072d176f2df0b9ce433cdf59be81704a3a63
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/numbers/ast.snap
@@ -0,0 +1,429 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 47
+expression: ast.nodes()
+input_file: full-moon/tests/lua52_cases/pass/numbers
+---
+stmts:
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 0
+                line: 1
+                character: 1
+              end_position:
+                bytes: 25
+                line: 1
+                character: 26
+              token_type:
+                type: SingleLineComment
+                comment: " fractional hexadecimal"
+            - start_position:
+                bytes: 25
+                line: 1
+                character: 26
+              end_position:
+                bytes: 26
+                line: 1
+                character: 26
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 26
+              line: 2
+              character: 1
+            end_position:
+              bytes: 31
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 31
+                line: 2
+                character: 6
+              end_position:
+                bytes: 32
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 32
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 33
+                    line: 2
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: a
+                trailing_trivia:
+                  - start_position:
+                      bytes: 33
+                      line: 2
+                      character: 8
+                    end_position:
+                      bytes: 34
+                      line: 2
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 36
+                      line: 2
+                      character: 11
+                    end_position:
+                      bytes: 42
+                      line: 2
+                      character: 17
+                    token_type:
+                      type: Number
+                      text: "0x0.1E"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 42
+                        line: 2
+                        character: 17
+                      end_position:
+                        bytes: 43
+                        line: 2
+                        character: 17
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 43
+                line: 3
+                character: 1
+              end_position:
+                bytes: 44
+                line: 3
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+            - start_position:
+                bytes: 44
+                line: 4
+                character: 1
+              end_position:
+                bytes: 77
+                line: 4
+                character: 34
+              token_type:
+                type: SingleLineComment
+                comment: " binary exponent in hexadecimal"
+            - start_position:
+                bytes: 77
+                line: 4
+                character: 34
+              end_position:
+                bytes: 78
+                line: 4
+                character: 34
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 78
+              line: 5
+              character: 1
+            end_position:
+              bytes: 83
+              line: 5
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 83
+                line: 5
+                character: 6
+              end_position:
+                bytes: 84
+                line: 5
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 84
+                    line: 5
+                    character: 7
+                  end_position:
+                    bytes: 85
+                    line: 5
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: b
+                trailing_trivia:
+                  - start_position:
+                      bytes: 85
+                      line: 5
+                      character: 8
+                    end_position:
+                      bytes: 86
+                      line: 5
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 86
+              line: 5
+              character: 9
+            end_position:
+              bytes: 87
+              line: 5
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 87
+                line: 5
+                character: 10
+              end_position:
+                bytes: 88
+                line: 5
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 88
+                      line: 5
+                      character: 11
+                    end_position:
+                      bytes: 96
+                      line: 5
+                      character: 19
+                    token_type:
+                      type: Number
+                      text: "0xA23p-4"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 96
+                        line: 5
+                        character: 19
+                      end_position:
+                        bytes: 97
+                        line: 5
+                        character: 19
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 97
+                line: 6
+                character: 1
+              end_position:
+                bytes: 98
+                line: 6
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+            - start_position:
+                bytes: 98
+                line: 7
+                character: 1
+              end_position:
+                bytes: 118
+                line: 7
+                character: 21
+              token_type:
+                type: SingleLineComment
+                comment: " a mixture of both"
+            - start_position:
+                bytes: 118
+                line: 7
+                character: 21
+              end_position:
+                bytes: 119
+                line: 7
+                character: 21
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 119
+              line: 8
+              character: 1
+            end_position:
+              bytes: 124
+              line: 8
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 124
+                line: 8
+                character: 6
+              end_position:
+                bytes: 125
+                line: 8
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 125
+                    line: 8
+                    character: 7
+                  end_position:
+                    bytes: 126
+                    line: 8
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: c
+                trailing_trivia:
+                  - start_position:
+                      bytes: 126
+                      line: 8
+                      character: 8
+                    end_position:
+                      bytes: 127
+                      line: 8
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 127
+              line: 8
+              character: 9
+            end_position:
+              bytes: 128
+              line: 8
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 128
+                line: 8
+                character: 10
+              end_position:
+                bytes: 129
+                line: 8
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 129
+                      line: 8
+                      character: 11
+                    end_position:
+                      bytes: 149
+                      line: 8
+                      character: 31
+                    token_type:
+                      type: Number
+                      text: 0X1.921FB54442D18P+1
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 149
+                        line: 8
+                        character: 31
+                      end_position:
+                        bytes: 150
+                        line: 8
+                        character: 31
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/pass/numbers/source.lua b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/numbers/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..ef1430c41bf96d0a016ef493e696d82750a3f313
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/numbers/source.lua
@@ -0,0 +1,15 @@
+-- fractional hexadecimal
+local a = 0x0.1E
+
+-- binary exponent in hexadecimal
+local b = 0xA23p-4
+
+-- a mixture of both
+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
+-- 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/src/Rust/vvs_parser/src/tests/lua52_cases/pass/numbers/tokens.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/numbers/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f8b26543403cf4fb8b72128a0fe71bc9289b655f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/numbers/tokens.snap
@@ -0,0 +1,512 @@
+---
+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
+    line: 1
+    character: 1
+  end_position:
+    bytes: 25
+    line: 1
+    character: 26
+  token_type:
+    type: SingleLineComment
+    comment: " fractional hexadecimal"
+- 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: 31
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 31
+    line: 2
+    character: 6
+  end_position:
+    bytes: 32
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 32
+    line: 2
+    character: 7
+  end_position:
+    bytes: 33
+    line: 2
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: a
+- start_position:
+    bytes: 33
+    line: 2
+    character: 8
+  end_position:
+    bytes: 34
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- 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: 42
+    line: 2
+    character: 17
+  token_type:
+    type: Number
+    text: "0x0.1E"
+- start_position:
+    bytes: 42
+    line: 2
+    character: 17
+  end_position:
+    bytes: 43
+    line: 2
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 43
+    line: 3
+    character: 1
+  end_position:
+    bytes: 44
+    line: 3
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 44
+    line: 4
+    character: 1
+  end_position:
+    bytes: 77
+    line: 4
+    character: 34
+  token_type:
+    type: SingleLineComment
+    comment: " binary exponent in hexadecimal"
+- start_position:
+    bytes: 77
+    line: 4
+    character: 34
+  end_position:
+    bytes: 78
+    line: 4
+    character: 34
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 78
+    line: 5
+    character: 1
+  end_position:
+    bytes: 83
+    line: 5
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 83
+    line: 5
+    character: 6
+  end_position:
+    bytes: 84
+    line: 5
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 84
+    line: 5
+    character: 7
+  end_position:
+    bytes: 85
+    line: 5
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 85
+    line: 5
+    character: 8
+  end_position:
+    bytes: 86
+    line: 5
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 86
+    line: 5
+    character: 9
+  end_position:
+    bytes: 87
+    line: 5
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 87
+    line: 5
+    character: 10
+  end_position:
+    bytes: 88
+    line: 5
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 88
+    line: 5
+    character: 11
+  end_position:
+    bytes: 96
+    line: 5
+    character: 19
+  token_type:
+    type: Number
+    text: "0xA23p-4"
+- start_position:
+    bytes: 96
+    line: 5
+    character: 19
+  end_position:
+    bytes: 97
+    line: 5
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 97
+    line: 6
+    character: 1
+  end_position:
+    bytes: 98
+    line: 6
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 98
+    line: 7
+    character: 1
+  end_position:
+    bytes: 118
+    line: 7
+    character: 21
+  token_type:
+    type: SingleLineComment
+    comment: " a mixture of both"
+- start_position:
+    bytes: 118
+    line: 7
+    character: 21
+  end_position:
+    bytes: 119
+    line: 7
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 119
+    line: 8
+    character: 1
+  end_position:
+    bytes: 124
+    line: 8
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 124
+    line: 8
+    character: 6
+  end_position:
+    bytes: 125
+    line: 8
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 125
+    line: 8
+    character: 7
+  end_position:
+    bytes: 126
+    line: 8
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: c
+- start_position:
+    bytes: 126
+    line: 8
+    character: 8
+  end_position:
+    bytes: 127
+    line: 8
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 127
+    line: 8
+    character: 9
+  end_position:
+    bytes: 128
+    line: 8
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 128
+    line: 8
+    character: 10
+  end_position:
+    bytes: 129
+    line: 8
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 129
+    line: 8
+    character: 11
+  end_position:
+    bytes: 149
+    line: 8
+    character: 31
+  token_type:
+    type: Number
+    text: 0X1.921FB54442D18P+1
+- start_position:
+    bytes: 149
+    line: 8
+    character: 31
+  end_position:
+    bytes: 150
+    line: 8
+    character: 31
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- 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"
+- start_position:
+    bytes: 275
+    line: 12
+    character: 1
+  end_position:
+    bytes: 343
+    line: 12
+    character: 69
+  token_type:
+    type: SingleLineComment
+    comment: " rewrite todo: add this back, but in a separate luajit pass folder"
+- start_position:
+    bytes: 343
+    line: 12
+    character: 69
+  end_position:
+    bytes: 344
+    line: 12
+    character: 69
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 344
+    line: 13
+    character: 1
+  end_position:
+    bytes: 361
+    line: 13
+    character: 18
+  token_type:
+    type: SingleLineComment
+    comment: " local d = 42LL"
+- start_position:
+    bytes: 361
+    line: 13
+    character: 18
+  end_position:
+    bytes: 362
+    line: 13
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 362
+    line: 14
+    character: 1
+  end_position:
+    bytes: 381
+    line: 14
+    character: 20
+  token_type:
+    type: SingleLineComment
+    comment: " local e = 0x2aLL"
+- start_position:
+    bytes: 381
+    line: 14
+    character: 20
+  end_position:
+    bytes: 382
+    line: 14
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 382
+    line: 15
+    character: 1
+  end_position:
+    bytes: 400
+    line: 15
+    character: 19
+  token_type:
+    type: SingleLineComment
+    comment: " local f = 12.5i"
+- start_position:
+    bytes: 400
+    line: 15
+    character: 19
+  end_position:
+    bytes: 401
+    line: 15
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 401
+    line: 16
+    character: 1
+  end_position:
+    bytes: 401
+    line: 16
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/pass/z-escape-string/ast.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/z-escape-string/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8a1171775c79e3c76ec9cdab22811c89b3c28912
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/z-escape-string/ast.snap
@@ -0,0 +1,79 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/lua52_cases/pass/z-escape-string
+---
+stmts:
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 0
+                line: 1
+                character: 1
+              end_position:
+                bytes: 5
+                line: 1
+                character: 6
+              token_type:
+                type: Identifier
+                identifier: print
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 5
+                            line: 1
+                            character: 6
+                          end_position:
+                            bytes: 6
+                            line: 1
+                            character: 7
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 29
+                            line: 2
+                            character: 12
+                          end_position:
+                            bytes: 30
+                            line: 2
+                            character: 13
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia: []
+                  arguments:
+                    pairs:
+                      - End:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 6
+                                line: 1
+                                character: 7
+                              end_position:
+                                bytes: 29
+                                line: 2
+                                character: 12
+                              token_type:
+                                type: StringLiteral
+                                literal: "testing \\z\n\t   twelve"
+                                quote_type: Double
+                            trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/pass/z-escape-string/source.lua b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/z-escape-string/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..230a2b44a21ab07ea30b88b2f4ddeb9daedb8b3b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/z-escape-string/source.lua
@@ -0,0 +1,2 @@
+print("testing \z
+	   twelve")
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/lua52_cases/pass/z-escape-string/tokens.snap b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/z-escape-string/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3193aac1745e30a672b9ac81e2972afa80295f0a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua52_cases/pass/z-escape-string/tokens.snap
@@ -0,0 +1,60 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: print
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 29
+    line: 2
+    character: 12
+  token_type:
+    type: StringLiteral
+    literal: "testing \\z\n\t   twelve"
+    quote_type: Double
+- start_position:
+    bytes: 29
+    line: 2
+    character: 12
+  end_position:
+    bytes: 30
+    line: 2
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 30
+    line: 2
+    character: 13
+  end_position:
+    bytes: 30
+    line: 2
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/ast.snap b/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c7c48185224c551088f98a1bca61215732c09722
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4d317ff119446177608c9f436daee516d2fdfed8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::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/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/error.snap b/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/error.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6a22b3726ec171ce80657f79fd84976549027906
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/error.snap
@@ -0,0 +1,19 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: error
+---
+UnexpectedToken:
+  token:
+    start_position:
+      bytes: 75
+      line: 2
+      character: 11
+    end_position:
+      bytes: 76
+      line: 2
+      character: 12
+    token_type:
+      type: Number
+      text: "1"
+  additional: expected expression
+
diff --git a/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/error_display.snap b/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..afad87187c2dbfd14b1b839cefcc17ed9f3e3b86
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/errors.snap b/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..dc4ec410730816d145e0f3d21613ff9ee55208bf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/source.lua b/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..350ffca6ed51ecb7924501a857873150749e5b5c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/source.lua
@@ -0,0 +1,2 @@
+-- We shouldn't parse this as >> since it has a space in between
+local x = 1 > > 2
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/tokens.snap b/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..81737b53ac0163576b45acbf6a60769f362b65fd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua53_cases/fail/parser/double-greater-than-binop/tokens.snap
@@ -0,0 +1,180 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: tokens
+---
+- 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"
+- start_position:
+    bytes: 65
+    line: 2
+    character: 1
+  end_position:
+    bytes: 70
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 70
+    line: 2
+    character: 6
+  end_position:
+    bytes: 71
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 71
+    line: 2
+    character: 7
+  end_position:
+    bytes: 72
+    line: 2
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 72
+    line: 2
+    character: 8
+  end_position:
+    bytes: 73
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 73
+    line: 2
+    character: 9
+  end_position:
+    bytes: 74
+    line: 2
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 74
+    line: 2
+    character: 10
+  end_position:
+    bytes: 75
+    line: 2
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 75
+    line: 2
+    character: 11
+  end_position:
+    bytes: 76
+    line: 2
+    character: 12
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 76
+    line: 2
+    character: 12
+  end_position:
+    bytes: 77
+    line: 2
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 77
+    line: 2
+    character: 13
+  end_position:
+    bytes: 78
+    line: 2
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: ">"
+- start_position:
+    bytes: 78
+    line: 2
+    character: 14
+  end_position:
+    bytes: 79
+    line: 2
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 79
+    line: 2
+    character: 15
+  end_position:
+    bytes: 80
+    line: 2
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: ">"
+- start_position:
+    bytes: 80
+    line: 2
+    character: 16
+  end_position:
+    bytes: 81
+    line: 2
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 81
+    line: 2
+    character: 17
+  end_position:
+    bytes: 82
+    line: 2
+    character: 18
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 82
+    line: 2
+    character: 18
+  end_position:
+    bytes: 82
+    line: 2
+    character: 18
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/lua53_cases/pass/binary-operators/ast.snap b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/binary-operators/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..51a84e9b09f4a7cd73ec2314026a23741bc45b3b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/binary-operators/ast.snap
@@ -0,0 +1,1009 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 44
+expression: ast.nodes()
+input_file: full-moon/tests/lua53_cases/pass/binary-operators
+---
+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: a
+                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:
+                BinaryOperator:
+                  lhs:
+                    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:
+                        - start_position:
+                            bytes: 11
+                            line: 1
+                            character: 12
+                          end_position:
+                            bytes: 12
+                            line: 1
+                            character: 13
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  binop:
+                    Ampersand:
+                      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: " "
+                  rhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 14
+                          line: 1
+                          character: 15
+                        end_position:
+                          bytes: 15
+                          line: 1
+                          character: 16
+                        token_type:
+                          type: Number
+                          text: "2"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 15
+                            line: 1
+                            character: 16
+                          end_position:
+                            bytes: 16
+                            line: 1
+                            character: 16
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 16
+              line: 2
+              character: 1
+            end_position:
+              bytes: 21
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 21
+                line: 2
+                character: 6
+              end_position:
+                bytes: 22
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 22
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 23
+                    line: 2
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: b
+                trailing_trivia:
+                  - start_position:
+                      bytes: 23
+                      line: 2
+                      character: 8
+                    end_position:
+                      bytes: 24
+                      line: 2
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 24
+              line: 2
+              character: 9
+            end_position:
+              bytes: 25
+              line: 2
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 25
+                line: 2
+                character: 10
+              end_position:
+                bytes: 26
+                line: 2
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 26
+                          line: 2
+                          character: 11
+                        end_position:
+                          bytes: 27
+                          line: 2
+                          character: 12
+                        token_type:
+                          type: Number
+                          text: "1"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 27
+                            line: 2
+                            character: 12
+                          end_position:
+                            bytes: 28
+                            line: 2
+                            character: 13
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  binop:
+                    Pipe:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 28
+                          line: 2
+                          character: 13
+                        end_position:
+                          bytes: 29
+                          line: 2
+                          character: 14
+                        token_type:
+                          type: Symbol
+                          symbol: "|"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 29
+                            line: 2
+                            character: 14
+                          end_position:
+                            bytes: 30
+                            line: 2
+                            character: 15
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 30
+                          line: 2
+                          character: 15
+                        end_position:
+                          bytes: 31
+                          line: 2
+                          character: 16
+                        token_type:
+                          type: Number
+                          text: "2"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 31
+                            line: 2
+                            character: 16
+                          end_position:
+                            bytes: 32
+                            line: 2
+                            character: 16
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 32
+              line: 3
+              character: 1
+            end_position:
+              bytes: 37
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 37
+                line: 3
+                character: 6
+              end_position:
+                bytes: 38
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 38
+                    line: 3
+                    character: 7
+                  end_position:
+                    bytes: 39
+                    line: 3
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: c
+                trailing_trivia:
+                  - start_position:
+                      bytes: 39
+                      line: 3
+                      character: 8
+                    end_position:
+                      bytes: 40
+                      line: 3
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 40
+              line: 3
+              character: 9
+            end_position:
+              bytes: 41
+              line: 3
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 41
+                line: 3
+                character: 10
+              end_position:
+                bytes: 42
+                line: 3
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 42
+                          line: 3
+                          character: 11
+                        end_position:
+                          bytes: 43
+                          line: 3
+                          character: 12
+                        token_type:
+                          type: Number
+                          text: "1"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 43
+                            line: 3
+                            character: 12
+                          end_position:
+                            bytes: 44
+                            line: 3
+                            character: 13
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  binop:
+                    DoubleLesserThan:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 44
+                          line: 3
+                          character: 13
+                        end_position:
+                          bytes: 46
+                          line: 3
+                          character: 15
+                        token_type:
+                          type: Symbol
+                          symbol: "<~"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 46
+                            line: 3
+                            character: 15
+                          end_position:
+                            bytes: 47
+                            line: 3
+                            character: 16
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 47
+                          line: 3
+                          character: 16
+                        end_position:
+                          bytes: 48
+                          line: 3
+                          character: 17
+                        token_type:
+                          type: Number
+                          text: "2"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 48
+                            line: 3
+                            character: 17
+                          end_position:
+                            bytes: 49
+                            line: 3
+                            character: 17
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 49
+              line: 4
+              character: 1
+            end_position:
+              bytes: 54
+              line: 4
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 54
+                line: 4
+                character: 6
+              end_position:
+                bytes: 55
+                line: 4
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 55
+                    line: 4
+                    character: 7
+                  end_position:
+                    bytes: 56
+                    line: 4
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: d
+                trailing_trivia:
+                  - start_position:
+                      bytes: 56
+                      line: 4
+                      character: 8
+                    end_position:
+                      bytes: 57
+                      line: 4
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 57
+              line: 4
+              character: 9
+            end_position:
+              bytes: 58
+              line: 4
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 58
+                line: 4
+                character: 10
+              end_position:
+                bytes: 59
+                line: 4
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 59
+                          line: 4
+                          character: 11
+                        end_position:
+                          bytes: 60
+                          line: 4
+                          character: 12
+                        token_type:
+                          type: Number
+                          text: "1"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 60
+                            line: 4
+                            character: 12
+                          end_position:
+                            bytes: 61
+                            line: 4
+                            character: 13
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  binop:
+                    DoubleGreaterThan:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 61
+                          line: 4
+                          character: 13
+                        end_position:
+                          bytes: 63
+                          line: 4
+                          character: 15
+                        token_type:
+                          type: Symbol
+                          symbol: ~>
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 63
+                            line: 4
+                            character: 15
+                          end_position:
+                            bytes: 64
+                            line: 4
+                            character: 16
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 64
+                          line: 4
+                          character: 16
+                        end_position:
+                          bytes: 65
+                          line: 4
+                          character: 17
+                        token_type:
+                          type: Number
+                          text: "2"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 65
+                            line: 4
+                            character: 17
+                          end_position:
+                            bytes: 66
+                            line: 4
+                            character: 17
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 66
+              line: 5
+              character: 1
+            end_position:
+              bytes: 71
+              line: 5
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 71
+                line: 5
+                character: 6
+              end_position:
+                bytes: 72
+                line: 5
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 72
+                    line: 5
+                    character: 7
+                  end_position:
+                    bytes: 73
+                    line: 5
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: e
+                trailing_trivia:
+                  - start_position:
+                      bytes: 73
+                      line: 5
+                      character: 8
+                    end_position:
+                      bytes: 74
+                      line: 5
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 74
+              line: 5
+              character: 9
+            end_position:
+              bytes: 75
+              line: 5
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 75
+                line: 5
+                character: 10
+              end_position:
+                bytes: 76
+                line: 5
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 76
+                          line: 5
+                          character: 11
+                        end_position:
+                          bytes: 77
+                          line: 5
+                          character: 12
+                        token_type:
+                          type: Number
+                          text: "1"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 77
+                            line: 5
+                            character: 12
+                          end_position:
+                            bytes: 78
+                            line: 5
+                            character: 13
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  binop:
+                    Tilde:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 78
+                          line: 5
+                          character: 13
+                        end_position:
+                          bytes: 79
+                          line: 5
+                          character: 14
+                        token_type:
+                          type: Symbol
+                          symbol: "~"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 79
+                            line: 5
+                            character: 14
+                          end_position:
+                            bytes: 80
+                            line: 5
+                            character: 15
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 80
+                          line: 5
+                          character: 15
+                        end_position:
+                          bytes: 81
+                          line: 5
+                          character: 16
+                        token_type:
+                          type: Number
+                          text: "2"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 81
+                            line: 5
+                            character: 16
+                          end_position:
+                            bytes: 82
+                            line: 5
+                            character: 16
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 82
+              line: 6
+              character: 1
+            end_position:
+              bytes: 87
+              line: 6
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 87
+                line: 6
+                character: 6
+              end_position:
+                bytes: 88
+                line: 6
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 88
+                    line: 6
+                    character: 7
+                  end_position:
+                    bytes: 89
+                    line: 6
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: f
+                trailing_trivia:
+                  - start_position:
+                      bytes: 89
+                      line: 6
+                      character: 8
+                    end_position:
+                      bytes: 90
+                      line: 6
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 90
+              line: 6
+              character: 9
+            end_position:
+              bytes: 91
+              line: 6
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 91
+                line: 6
+                character: 10
+              end_position:
+                bytes: 92
+                line: 6
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 92
+                          line: 6
+                          character: 11
+                        end_position:
+                          bytes: 93
+                          line: 6
+                          character: 12
+                        token_type:
+                          type: Number
+                          text: "1"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 93
+                            line: 6
+                            character: 12
+                          end_position:
+                            bytes: 94
+                            line: 6
+                            character: 13
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  binop:
+                    DoubleSlash:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 94
+                          line: 6
+                          character: 13
+                        end_position:
+                          bytes: 96
+                          line: 6
+                          character: 15
+                        token_type:
+                          type: Symbol
+                          symbol: //
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 96
+                            line: 6
+                            character: 15
+                          end_position:
+                            bytes: 97
+                            line: 6
+                            character: 16
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 97
+                          line: 6
+                          character: 16
+                        end_position:
+                          bytes: 98
+                          line: 6
+                          character: 17
+                        token_type:
+                          type: Number
+                          text: "2"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 98
+                            line: 6
+                            character: 17
+                          end_position:
+                            bytes: 99
+                            line: 6
+                            character: 17
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/lua53_cases/pass/binary-operators/source.lua b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/binary-operators/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..4d5c6fb9049e1b9179ed16635c538cd2c0724a35
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/binary-operators/source.lua
@@ -0,0 +1,6 @@
+local a = 1 & 2
+local b = 1 | 2
+local c = 1 <~ 2
+local d = 1 ~> 2
+local e = 1 ~ 2
+local f = 1 // 2
diff --git a/src/Rust/vvs_parser/src/tests/lua53_cases/pass/binary-operators/tokens.snap b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/binary-operators/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e998ca3186e51145c32439c2d29b2d6999ee12c7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/binary-operators/tokens.snap
@@ -0,0 +1,808 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 36
+expression: tokens
+input_file: full-moon/tests/lua53_cases/pass/binary-operators
+---
+- 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: a
+- 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: Number
+    text: "1"
+- 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: Number
+    text: "2"
+- 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: 21
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 21
+    line: 2
+    character: 6
+  end_position:
+    bytes: 22
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 22
+    line: 2
+    character: 7
+  end_position:
+    bytes: 23
+    line: 2
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 23
+    line: 2
+    character: 8
+  end_position:
+    bytes: 24
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 24
+    line: 2
+    character: 9
+  end_position:
+    bytes: 25
+    line: 2
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 25
+    line: 2
+    character: 10
+  end_position:
+    bytes: 26
+    line: 2
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 26
+    line: 2
+    character: 11
+  end_position:
+    bytes: 27
+    line: 2
+    character: 12
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 27
+    line: 2
+    character: 12
+  end_position:
+    bytes: 28
+    line: 2
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 28
+    line: 2
+    character: 13
+  end_position:
+    bytes: 29
+    line: 2
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: "|"
+- start_position:
+    bytes: 29
+    line: 2
+    character: 14
+  end_position:
+    bytes: 30
+    line: 2
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 30
+    line: 2
+    character: 15
+  end_position:
+    bytes: 31
+    line: 2
+    character: 16
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 31
+    line: 2
+    character: 16
+  end_position:
+    bytes: 32
+    line: 2
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 32
+    line: 3
+    character: 1
+  end_position:
+    bytes: 37
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 37
+    line: 3
+    character: 6
+  end_position:
+    bytes: 38
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 38
+    line: 3
+    character: 7
+  end_position:
+    bytes: 39
+    line: 3
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: c
+- start_position:
+    bytes: 39
+    line: 3
+    character: 8
+  end_position:
+    bytes: 40
+    line: 3
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 40
+    line: 3
+    character: 9
+  end_position:
+    bytes: 41
+    line: 3
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 41
+    line: 3
+    character: 10
+  end_position:
+    bytes: 42
+    line: 3
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 42
+    line: 3
+    character: 11
+  end_position:
+    bytes: 43
+    line: 3
+    character: 12
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 43
+    line: 3
+    character: 12
+  end_position:
+    bytes: 44
+    line: 3
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 44
+    line: 3
+    character: 13
+  end_position:
+    bytes: 46
+    line: 3
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: "<~"
+- start_position:
+    bytes: 46
+    line: 3
+    character: 15
+  end_position:
+    bytes: 47
+    line: 3
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 47
+    line: 3
+    character: 16
+  end_position:
+    bytes: 48
+    line: 3
+    character: 17
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 48
+    line: 3
+    character: 17
+  end_position:
+    bytes: 49
+    line: 3
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 49
+    line: 4
+    character: 1
+  end_position:
+    bytes: 54
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 54
+    line: 4
+    character: 6
+  end_position:
+    bytes: 55
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 55
+    line: 4
+    character: 7
+  end_position:
+    bytes: 56
+    line: 4
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: d
+- start_position:
+    bytes: 56
+    line: 4
+    character: 8
+  end_position:
+    bytes: 57
+    line: 4
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 57
+    line: 4
+    character: 9
+  end_position:
+    bytes: 58
+    line: 4
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 58
+    line: 4
+    character: 10
+  end_position:
+    bytes: 59
+    line: 4
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 59
+    line: 4
+    character: 11
+  end_position:
+    bytes: 60
+    line: 4
+    character: 12
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 60
+    line: 4
+    character: 12
+  end_position:
+    bytes: 61
+    line: 4
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 61
+    line: 4
+    character: 13
+  end_position:
+    bytes: 63
+    line: 4
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: ~>
+- start_position:
+    bytes: 63
+    line: 4
+    character: 15
+  end_position:
+    bytes: 64
+    line: 4
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 64
+    line: 4
+    character: 16
+  end_position:
+    bytes: 65
+    line: 4
+    character: 17
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 65
+    line: 4
+    character: 17
+  end_position:
+    bytes: 66
+    line: 4
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 66
+    line: 5
+    character: 1
+  end_position:
+    bytes: 71
+    line: 5
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 71
+    line: 5
+    character: 6
+  end_position:
+    bytes: 72
+    line: 5
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 72
+    line: 5
+    character: 7
+  end_position:
+    bytes: 73
+    line: 5
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: e
+- start_position:
+    bytes: 73
+    line: 5
+    character: 8
+  end_position:
+    bytes: 74
+    line: 5
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 74
+    line: 5
+    character: 9
+  end_position:
+    bytes: 75
+    line: 5
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 75
+    line: 5
+    character: 10
+  end_position:
+    bytes: 76
+    line: 5
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 76
+    line: 5
+    character: 11
+  end_position:
+    bytes: 77
+    line: 5
+    character: 12
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 77
+    line: 5
+    character: 12
+  end_position:
+    bytes: 78
+    line: 5
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 78
+    line: 5
+    character: 13
+  end_position:
+    bytes: 79
+    line: 5
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: "~"
+- start_position:
+    bytes: 79
+    line: 5
+    character: 14
+  end_position:
+    bytes: 80
+    line: 5
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 80
+    line: 5
+    character: 15
+  end_position:
+    bytes: 81
+    line: 5
+    character: 16
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 81
+    line: 5
+    character: 16
+  end_position:
+    bytes: 82
+    line: 5
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 82
+    line: 6
+    character: 1
+  end_position:
+    bytes: 87
+    line: 6
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 87
+    line: 6
+    character: 6
+  end_position:
+    bytes: 88
+    line: 6
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 88
+    line: 6
+    character: 7
+  end_position:
+    bytes: 89
+    line: 6
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: f
+- start_position:
+    bytes: 89
+    line: 6
+    character: 8
+  end_position:
+    bytes: 90
+    line: 6
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 90
+    line: 6
+    character: 9
+  end_position:
+    bytes: 91
+    line: 6
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 91
+    line: 6
+    character: 10
+  end_position:
+    bytes: 92
+    line: 6
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 92
+    line: 6
+    character: 11
+  end_position:
+    bytes: 93
+    line: 6
+    character: 12
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 93
+    line: 6
+    character: 12
+  end_position:
+    bytes: 94
+    line: 6
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 94
+    line: 6
+    character: 13
+  end_position:
+    bytes: 96
+    line: 6
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: //
+- start_position:
+    bytes: 96
+    line: 6
+    character: 15
+  end_position:
+    bytes: 97
+    line: 6
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 97
+    line: 6
+    character: 16
+  end_position:
+    bytes: 98
+    line: 6
+    character: 17
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 98
+    line: 6
+    character: 17
+  end_position:
+    bytes: 99
+    line: 6
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 99
+    line: 7
+    character: 1
+  end_position:
+    bytes: 99
+    line: 7
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/lua53_cases/pass/unary-operators/ast.snap b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/unary-operators/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bffea940a1639509fe59c498465cb9b41fa812b8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/unary-operators/ast.snap
@@ -0,0 +1,126 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/lua53_cases/pass/unary-operators
+---
+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:
+                UnaryOperator:
+                  unop:
+                    Tilde:
+                      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: []
+                  expression:
+                    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: "1"
+                      trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/lua53_cases/pass/unary-operators/source.lua b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/unary-operators/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..55c2a6c3c69374eb21a25d05e09e6b6bbf0076fc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/unary-operators/source.lua
@@ -0,0 +1 @@
+local x = ~1
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/lua53_cases/pass/unary-operators/tokens.snap b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/unary-operators/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cc697e6e0b37ff3f21d8ef5667f4a35f15db5376
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua53_cases/pass/unary-operators/tokens.snap
@@ -0,0 +1,103 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- 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: 13
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 12
+    line: 1
+    character: 13
+  end_position:
+    bytes: 12
+    line: 1
+    character: 13
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2b426b0b2bfb4a6d7192db6b42c022f386e0ee4b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6dada6e11d4f736625b87fc716649afca84d905a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/ast_to_string.snap
@@ -0,0 +1,7 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1
+---
+local name <const>
+
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/error.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/error.snap
new file mode 100644
index 0000000000000000000000000000000000000000..afe5c2f91ecc6d77ea6d72bfd0155898e58eb5f6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/error.snap
@@ -0,0 +1,19 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 100
+expression: error
+---
+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/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/error_display.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..59128ce548d5d5f6b0db6508afbc68b879c67592
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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 <const
+  │                  ^
+
+
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/errors.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..439a596ae60cd7c6fe102efb245ce47419b088bc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/errors.snap
@@ -0,0 +1,19 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: result.errors
+input_file: full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-1
+---
+- AstError:
+    token:
+      start_position:
+        bytes: 17
+        line: 1
+        character: 18
+      end_position:
+        bytes: 17
+        line: 1
+        character: 18
+      token_type:
+        type: Eof
+    additional: "expected `>` to close attribute"
+
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/source.lua b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..fe2df6e9620a5045ae934a0ab1f11c27732966fb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/source.lua
@@ -0,0 +1 @@
+local name <const
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/tokens.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..82429fb30ad5d61baef68795365085346625bf08
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-1/tokens.snap
@@ -0,0 +1,82 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 94
+expression: tokens
+---
+- 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: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: name
+- 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: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: const
+- start_position:
+    bytes: 17
+    line: 1
+    character: 18
+  end_position:
+    bytes: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bc5e7f75233770fb0559f4da59c48c6df1133853
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d944282292e2c242bdfa0b1b8bdc9a4ebb6d30e6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/ast_to_string.snap
@@ -0,0 +1,7 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: "vvs_parser::print(&ast)"
+input_file: full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2
+---
+local name <const >= 10
+
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/error.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/error.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ce13d5475433d1b31c8e2d2fc2772f1b71379f6c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/error.snap
@@ -0,0 +1,20 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 100
+expression: error
+---
+UnexpectedToken:
+  token:
+    start_position:
+      bytes: 18
+      line: 1
+      character: 19
+    end_position:
+      bytes: 19
+      line: 1
+      character: 20
+    token_type:
+      type: Symbol
+      symbol: "="
+  additional: "expected `>`"
+
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/error_display.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b93f53ce2b3ca68182c3aad80c44ecc8ec76a38c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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 <const = 10
+  │                   ^
+
+
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/errors.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..da498cb7fe2b322aabf7f7c0f2ca4d0d6bc56f9b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/errors.snap
@@ -0,0 +1,20 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: result.errors
+input_file: full-moon/tests/lua54_cases/fail/parser/unclosed-attribute-2
+---
+- 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 attribute"
+
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/source.lua b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..3213aacec1acbff116cfe6fb3f94a69c8b83f950
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/source.lua
@@ -0,0 +1 @@
+local name <const = 10
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/tokens.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e5477525edddc0f2edcd5a7166f586ce8f5007e9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/fail/parser/unclosed-attribute-2/tokens.snap
@@ -0,0 +1,126 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 94
+expression: tokens
+---
+- 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: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: name
+- 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: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: const
+- 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: 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: Whitespace
+    characters: " "
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 22
+    line: 1
+    character: 23
+  token_type:
+    type: Number
+    text: "10"
+- start_position:
+    bytes: 22
+    line: 1
+    character: 23
+  end_position:
+    bytes: 22
+    line: 1
+    character: 23
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/pass/attributes/ast.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/pass/attributes/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..76f534631a9be237e0fe834e47cd5711f34ee68c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/pass/attributes/ast.snap
@@ -0,0 +1,1051 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/lua54_cases/pass/attributes
+---
+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: a
+                trailing_trivia:
+                  - start_position:
+                      bytes: 7
+                      line: 1
+                      character: 8
+                    end_position:
+                      bytes: 8
+                      line: 1
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        attributes:
+          - brackets:
+              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: 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: " "
+            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: const
+              trailing_trivia: []
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 18
+                      line: 1
+                      character: 19
+                    end_position:
+                      bytes: 19
+                      line: 1
+                      character: 20
+                    token_type:
+                      type: Number
+                      text: "5"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 19
+                        line: 1
+                        character: 20
+                      end_position:
+                        bytes: 20
+                        line: 1
+                        character: 20
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 20
+              line: 2
+              character: 1
+            end_position:
+              bytes: 25
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 25
+                line: 2
+                character: 6
+              end_position:
+                bytes: 26
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 26
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 27
+                    line: 2
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: d
+                trailing_trivia:
+                  - start_position:
+                      bytes: 27
+                      line: 2
+                      character: 8
+                    end_position:
+                      bytes: 28
+                      line: 2
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        attributes:
+          - brackets:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 28
+                      line: 2
+                      character: 9
+                    end_position:
+                      bytes: 29
+                      line: 2
+                      character: 10
+                    token_type:
+                      type: Symbol
+                      symbol: "<"
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 34
+                      line: 2
+                      character: 15
+                    end_position:
+                      bytes: 35
+                      line: 2
+                      character: 16
+                    token_type:
+                      type: Symbol
+                      symbol: ">"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 35
+                        line: 2
+                        character: 16
+                      end_position:
+                        bytes: 36
+                        line: 2
+                        character: 16
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+            name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 29
+                  line: 2
+                  character: 10
+                end_position:
+                  bytes: 34
+                  line: 2
+                  character: 15
+                token_type:
+                  type: Identifier
+                  identifier: close
+              trailing_trivia: []
+        equal_token: ~
+        expr_list:
+          pairs: []
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 36
+              line: 3
+              character: 1
+            end_position:
+              bytes: 41
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 41
+                line: 3
+                character: 6
+              end_position:
+                bytes: 42
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - Punctuated:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 42
+                      line: 3
+                      character: 7
+                    end_position:
+                      bytes: 43
+                      line: 3
+                      character: 8
+                    token_type:
+                      type: Identifier
+                      identifier: e
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 43
+                        line: 3
+                        character: 8
+                      end_position:
+                        bytes: 44
+                        line: 3
+                        character: 9
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 51
+                      line: 3
+                      character: 16
+                    end_position:
+                      bytes: 52
+                      line: 3
+                      character: 17
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 52
+                        line: 3
+                        character: 17
+                      end_position:
+                        bytes: 53
+                        line: 3
+                        character: 18
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 53
+                    line: 3
+                    character: 18
+                  end_position:
+                    bytes: 54
+                    line: 3
+                    character: 19
+                  token_type:
+                    type: Identifier
+                    identifier: f
+                trailing_trivia:
+                  - start_position:
+                      bytes: 54
+                      line: 3
+                      character: 19
+                    end_position:
+                      bytes: 55
+                      line: 3
+                      character: 20
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        attributes:
+          - brackets:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 44
+                      line: 3
+                      character: 9
+                    end_position:
+                      bytes: 45
+                      line: 3
+                      character: 10
+                    token_type:
+                      type: Symbol
+                      symbol: "<"
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 50
+                      line: 3
+                      character: 15
+                    end_position:
+                      bytes: 51
+                      line: 3
+                      character: 16
+                    token_type:
+                      type: Symbol
+                      symbol: ">"
+                  trailing_trivia: []
+            name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 45
+                  line: 3
+                  character: 10
+                end_position:
+                  bytes: 50
+                  line: 3
+                  character: 15
+                token_type:
+                  type: Identifier
+                  identifier: const
+              trailing_trivia: []
+          - brackets:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 55
+                      line: 3
+                      character: 20
+                    end_position:
+                      bytes: 56
+                      line: 3
+                      character: 21
+                    token_type:
+                      type: Symbol
+                      symbol: "<"
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 61
+                      line: 3
+                      character: 26
+                    end_position:
+                      bytes: 62
+                      line: 3
+                      character: 27
+                    token_type:
+                      type: Symbol
+                      symbol: ">"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 62
+                        line: 3
+                        character: 27
+                      end_position:
+                        bytes: 63
+                        line: 3
+                        character: 28
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 56
+                  line: 3
+                  character: 21
+                end_position:
+                  bytes: 61
+                  line: 3
+                  character: 26
+                token_type:
+                  type: Identifier
+                  identifier: close
+              trailing_trivia: []
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 63
+              line: 3
+              character: 28
+            end_position:
+              bytes: 64
+              line: 3
+              character: 29
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 64
+                line: 3
+                character: 29
+              end_position:
+                bytes: 65
+                line: 3
+                character: 30
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - Punctuated:
+                - Number:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 65
+                        line: 3
+                        character: 30
+                      end_position:
+                        bytes: 66
+                        line: 3
+                        character: 31
+                      token_type:
+                        type: Number
+                        text: "1"
+                    trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 66
+                      line: 3
+                      character: 31
+                    end_position:
+                      bytes: 67
+                      line: 3
+                      character: 32
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 67
+                        line: 3
+                        character: 32
+                      end_position:
+                        bytes: 68
+                        line: 3
+                        character: 33
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 68
+                      line: 3
+                      character: 33
+                    end_position:
+                      bytes: 69
+                      line: 3
+                      character: 34
+                    token_type:
+                      type: Number
+                      text: "2"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 69
+                        line: 3
+                        character: 34
+                      end_position:
+                        bytes: 70
+                        line: 3
+                        character: 34
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 70
+              line: 4
+              character: 1
+            end_position:
+              bytes: 75
+              line: 4
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 75
+                line: 4
+                character: 6
+              end_position:
+                bytes: 76
+                line: 4
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - Punctuated:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 76
+                      line: 4
+                      character: 7
+                    end_position:
+                      bytes: 77
+                      line: 4
+                      character: 8
+                    token_type:
+                      type: Identifier
+                      identifier: g
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 77
+                        line: 4
+                        character: 8
+                      end_position:
+                        bytes: 78
+                        line: 4
+                        character: 9
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 85
+                      line: 4
+                      character: 16
+                    end_position:
+                      bytes: 86
+                      line: 4
+                      character: 17
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 86
+                        line: 4
+                        character: 17
+                      end_position:
+                        bytes: 87
+                        line: 4
+                        character: 18
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 87
+                    line: 4
+                    character: 18
+                  end_position:
+                    bytes: 88
+                    line: 4
+                    character: 19
+                  token_type:
+                    type: Identifier
+                    identifier: h
+                trailing_trivia:
+                  - start_position:
+                      bytes: 88
+                      line: 4
+                      character: 19
+                    end_position:
+                      bytes: 89
+                      line: 4
+                      character: 20
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        attributes:
+          - brackets:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 78
+                      line: 4
+                      character: 9
+                    end_position:
+                      bytes: 79
+                      line: 4
+                      character: 10
+                    token_type:
+                      type: Symbol
+                      symbol: "<"
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 84
+                      line: 4
+                      character: 15
+                    end_position:
+                      bytes: 85
+                      line: 4
+                      character: 16
+                    token_type:
+                      type: Symbol
+                      symbol: ">"
+                  trailing_trivia: []
+            name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 79
+                  line: 4
+                  character: 10
+                end_position:
+                  bytes: 84
+                  line: 4
+                  character: 15
+                token_type:
+                  type: Identifier
+                  identifier: const
+              trailing_trivia: []
+          - brackets:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 89
+                      line: 4
+                      character: 20
+                    end_position:
+                      bytes: 90
+                      line: 4
+                      character: 21
+                    token_type:
+                      type: Symbol
+                      symbol: "<"
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 95
+                      line: 4
+                      character: 26
+                    end_position:
+                      bytes: 96
+                      line: 4
+                      character: 27
+                    token_type:
+                      type: Symbol
+                      symbol: ">"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 96
+                        line: 4
+                        character: 27
+                      end_position:
+                        bytes: 97
+                        line: 4
+                        character: 27
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+            name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 90
+                  line: 4
+                  character: 21
+                end_position:
+                  bytes: 95
+                  line: 4
+                  character: 26
+                token_type:
+                  type: Identifier
+                  identifier: close
+              trailing_trivia: []
+        equal_token: ~
+        expr_list:
+          pairs: []
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 97
+              line: 5
+              character: 1
+            end_position:
+              bytes: 102
+              line: 5
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 102
+                line: 5
+                character: 6
+              end_position:
+                bytes: 103
+                line: 5
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - Punctuated:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 103
+                      line: 5
+                      character: 7
+                    end_position:
+                      bytes: 104
+                      line: 5
+                      character: 8
+                    token_type:
+                      type: Identifier
+                      identifier: i
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 104
+                        line: 5
+                        character: 8
+                      end_position:
+                        bytes: 105
+                        line: 5
+                        character: 9
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 112
+                      line: 5
+                      character: 16
+                    end_position:
+                      bytes: 113
+                      line: 5
+                      character: 17
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 113
+                        line: 5
+                        character: 17
+                      end_position:
+                        bytes: 114
+                        line: 5
+                        character: 18
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - Punctuated:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 114
+                      line: 5
+                      character: 18
+                    end_position:
+                      bytes: 115
+                      line: 5
+                      character: 19
+                    token_type:
+                      type: Identifier
+                      identifier: j
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 115
+                      line: 5
+                      character: 19
+                    end_position:
+                      bytes: 116
+                      line: 5
+                      character: 20
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 116
+                        line: 5
+                        character: 20
+                      end_position:
+                        bytes: 117
+                        line: 5
+                        character: 21
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 117
+                    line: 5
+                    character: 21
+                  end_position:
+                    bytes: 118
+                    line: 5
+                    character: 22
+                  token_type:
+                    type: Identifier
+                    identifier: k
+                trailing_trivia:
+                  - start_position:
+                      bytes: 118
+                      line: 5
+                      character: 22
+                    end_position:
+                      bytes: 119
+                      line: 5
+                      character: 23
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        attributes:
+          - brackets:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 105
+                      line: 5
+                      character: 9
+                    end_position:
+                      bytes: 106
+                      line: 5
+                      character: 10
+                    token_type:
+                      type: Symbol
+                      symbol: "<"
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 111
+                      line: 5
+                      character: 15
+                    end_position:
+                      bytes: 112
+                      line: 5
+                      character: 16
+                    token_type:
+                      type: Symbol
+                      symbol: ">"
+                  trailing_trivia: []
+            name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 106
+                  line: 5
+                  character: 10
+                end_position:
+                  bytes: 111
+                  line: 5
+                  character: 15
+                token_type:
+                  type: Identifier
+                  identifier: const
+              trailing_trivia: []
+          - ~
+          - brackets:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 119
+                      line: 5
+                      character: 23
+                    end_position:
+                      bytes: 120
+                      line: 5
+                      character: 24
+                    token_type:
+                      type: Symbol
+                      symbol: "<"
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 125
+                      line: 5
+                      character: 29
+                    end_position:
+                      bytes: 126
+                      line: 5
+                      character: 30
+                    token_type:
+                      type: Symbol
+                      symbol: ">"
+                  trailing_trivia: []
+            name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 120
+                  line: 5
+                  character: 24
+                end_position:
+                  bytes: 125
+                  line: 5
+                  character: 29
+                token_type:
+                  type: Identifier
+                  identifier: close
+              trailing_trivia: []
+        equal_token: ~
+        expr_list:
+          pairs: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/pass/attributes/source.lua b/src/Rust/vvs_parser/src/tests/lua54_cases/pass/attributes/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..4e1044f9347583c57a36632ec51bad583afbbc5b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/pass/attributes/source.lua
@@ -0,0 +1,5 @@
+local a <const> = 5
+local d <close>
+local e <const>, f <close> = 1, 2
+local g <const>, h <close>
+local i <const>, j, k <close>
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/lua54_cases/pass/attributes/tokens.snap b/src/Rust/vvs_parser/src/tests/lua54_cases/pass/attributes/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8acf2fa750775661ef8dfc0e96c9d503f70d0745
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/lua54_cases/pass/attributes/tokens.snap
@@ -0,0 +1,829 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- 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: a
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: const
+- 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: 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: 19
+    line: 1
+    character: 20
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 20
+    line: 1
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 20
+    line: 2
+    character: 1
+  end_position:
+    bytes: 25
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 25
+    line: 2
+    character: 6
+  end_position:
+    bytes: 26
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 26
+    line: 2
+    character: 7
+  end_position:
+    bytes: 27
+    line: 2
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: d
+- start_position:
+    bytes: 27
+    line: 2
+    character: 8
+  end_position:
+    bytes: 28
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 28
+    line: 2
+    character: 9
+  end_position:
+    bytes: 29
+    line: 2
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "<"
+- start_position:
+    bytes: 29
+    line: 2
+    character: 10
+  end_position:
+    bytes: 34
+    line: 2
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: close
+- start_position:
+    bytes: 34
+    line: 2
+    character: 15
+  end_position:
+    bytes: 35
+    line: 2
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: ">"
+- start_position:
+    bytes: 35
+    line: 2
+    character: 16
+  end_position:
+    bytes: 36
+    line: 2
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 36
+    line: 3
+    character: 1
+  end_position:
+    bytes: 41
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 41
+    line: 3
+    character: 6
+  end_position:
+    bytes: 42
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 42
+    line: 3
+    character: 7
+  end_position:
+    bytes: 43
+    line: 3
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: e
+- start_position:
+    bytes: 43
+    line: 3
+    character: 8
+  end_position:
+    bytes: 44
+    line: 3
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 44
+    line: 3
+    character: 9
+  end_position:
+    bytes: 45
+    line: 3
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "<"
+- start_position:
+    bytes: 45
+    line: 3
+    character: 10
+  end_position:
+    bytes: 50
+    line: 3
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: const
+- start_position:
+    bytes: 50
+    line: 3
+    character: 15
+  end_position:
+    bytes: 51
+    line: 3
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: ">"
+- start_position:
+    bytes: 51
+    line: 3
+    character: 16
+  end_position:
+    bytes: 52
+    line: 3
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 52
+    line: 3
+    character: 17
+  end_position:
+    bytes: 53
+    line: 3
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 53
+    line: 3
+    character: 18
+  end_position:
+    bytes: 54
+    line: 3
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: f
+- start_position:
+    bytes: 54
+    line: 3
+    character: 19
+  end_position:
+    bytes: 55
+    line: 3
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 55
+    line: 3
+    character: 20
+  end_position:
+    bytes: 56
+    line: 3
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: "<"
+- start_position:
+    bytes: 56
+    line: 3
+    character: 21
+  end_position:
+    bytes: 61
+    line: 3
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: close
+- start_position:
+    bytes: 61
+    line: 3
+    character: 26
+  end_position:
+    bytes: 62
+    line: 3
+    character: 27
+  token_type:
+    type: Symbol
+    symbol: ">"
+- start_position:
+    bytes: 62
+    line: 3
+    character: 27
+  end_position:
+    bytes: 63
+    line: 3
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 63
+    line: 3
+    character: 28
+  end_position:
+    bytes: 64
+    line: 3
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 64
+    line: 3
+    character: 29
+  end_position:
+    bytes: 65
+    line: 3
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 65
+    line: 3
+    character: 30
+  end_position:
+    bytes: 66
+    line: 3
+    character: 31
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 66
+    line: 3
+    character: 31
+  end_position:
+    bytes: 67
+    line: 3
+    character: 32
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 67
+    line: 3
+    character: 32
+  end_position:
+    bytes: 68
+    line: 3
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 68
+    line: 3
+    character: 33
+  end_position:
+    bytes: 69
+    line: 3
+    character: 34
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 69
+    line: 3
+    character: 34
+  end_position:
+    bytes: 70
+    line: 3
+    character: 34
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 70
+    line: 4
+    character: 1
+  end_position:
+    bytes: 75
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 75
+    line: 4
+    character: 6
+  end_position:
+    bytes: 76
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 76
+    line: 4
+    character: 7
+  end_position:
+    bytes: 77
+    line: 4
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: g
+- start_position:
+    bytes: 77
+    line: 4
+    character: 8
+  end_position:
+    bytes: 78
+    line: 4
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 78
+    line: 4
+    character: 9
+  end_position:
+    bytes: 79
+    line: 4
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "<"
+- start_position:
+    bytes: 79
+    line: 4
+    character: 10
+  end_position:
+    bytes: 84
+    line: 4
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: const
+- start_position:
+    bytes: 84
+    line: 4
+    character: 15
+  end_position:
+    bytes: 85
+    line: 4
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: ">"
+- start_position:
+    bytes: 85
+    line: 4
+    character: 16
+  end_position:
+    bytes: 86
+    line: 4
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 86
+    line: 4
+    character: 17
+  end_position:
+    bytes: 87
+    line: 4
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 87
+    line: 4
+    character: 18
+  end_position:
+    bytes: 88
+    line: 4
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: h
+- start_position:
+    bytes: 88
+    line: 4
+    character: 19
+  end_position:
+    bytes: 89
+    line: 4
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 89
+    line: 4
+    character: 20
+  end_position:
+    bytes: 90
+    line: 4
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: "<"
+- start_position:
+    bytes: 90
+    line: 4
+    character: 21
+  end_position:
+    bytes: 95
+    line: 4
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: close
+- start_position:
+    bytes: 95
+    line: 4
+    character: 26
+  end_position:
+    bytes: 96
+    line: 4
+    character: 27
+  token_type:
+    type: Symbol
+    symbol: ">"
+- start_position:
+    bytes: 96
+    line: 4
+    character: 27
+  end_position:
+    bytes: 97
+    line: 4
+    character: 27
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 97
+    line: 5
+    character: 1
+  end_position:
+    bytes: 102
+    line: 5
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 102
+    line: 5
+    character: 6
+  end_position:
+    bytes: 103
+    line: 5
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 103
+    line: 5
+    character: 7
+  end_position:
+    bytes: 104
+    line: 5
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: i
+- start_position:
+    bytes: 104
+    line: 5
+    character: 8
+  end_position:
+    bytes: 105
+    line: 5
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 105
+    line: 5
+    character: 9
+  end_position:
+    bytes: 106
+    line: 5
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "<"
+- start_position:
+    bytes: 106
+    line: 5
+    character: 10
+  end_position:
+    bytes: 111
+    line: 5
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: const
+- start_position:
+    bytes: 111
+    line: 5
+    character: 15
+  end_position:
+    bytes: 112
+    line: 5
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: ">"
+- start_position:
+    bytes: 112
+    line: 5
+    character: 16
+  end_position:
+    bytes: 113
+    line: 5
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 113
+    line: 5
+    character: 17
+  end_position:
+    bytes: 114
+    line: 5
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 114
+    line: 5
+    character: 18
+  end_position:
+    bytes: 115
+    line: 5
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: j
+- start_position:
+    bytes: 115
+    line: 5
+    character: 19
+  end_position:
+    bytes: 116
+    line: 5
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 116
+    line: 5
+    character: 20
+  end_position:
+    bytes: 117
+    line: 5
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 117
+    line: 5
+    character: 21
+  end_position:
+    bytes: 118
+    line: 5
+    character: 22
+  token_type:
+    type: Identifier
+    identifier: k
+- start_position:
+    bytes: 118
+    line: 5
+    character: 22
+  end_position:
+    bytes: 119
+    line: 5
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 119
+    line: 5
+    character: 23
+  end_position:
+    bytes: 120
+    line: 5
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: "<"
+- start_position:
+    bytes: 120
+    line: 5
+    character: 24
+  end_position:
+    bytes: 125
+    line: 5
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: close
+- start_position:
+    bytes: 125
+    line: 5
+    character: 29
+  end_position:
+    bytes: 126
+    line: 5
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: ">"
+- start_position:
+    bytes: 126
+    line: 5
+    character: 30
+  end_position:
+    bytes: 126
+    line: 5
+    character: 30
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/mod.rs b/src/Rust/vvs_parser/src/tests/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2a2f35e8450f6a6e4dc560b4da5c346fff210d36
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/mod.rs
@@ -0,0 +1,8 @@
+mod comments_around_functions;
+mod common;
+mod derive_node;
+mod fail_cases;
+mod node;
+mod one_line_range;
+mod pass_cases;
+mod visitors;
diff --git a/src/Rust/vvs_parser/src/tests/node.rs b/src/Rust/vvs_parser/src/tests/node.rs
new file mode 100644
index 0000000000000000000000000000000000000000..35651ccc32ad6106b79922736408ab2f18a01603
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/node.rs
@@ -0,0 +1,38 @@
+use crate::{node::Node, prelude::parser::parse_lua_tree as parse};
+
+#[test]
+fn surrounding_trivia() {
+    let ast = parse(include_str!("cases/pass/local-assignment-5/source.lua")).unwrap();
+    let stmt = ast.nodes().stmts().nth(1);
+
+    let (prev, _) = stmt.surrounding_trivia();
+
+    let mut prev = prev.into_iter();
+    assert_eq!(prev.next().unwrap().to_string(), "-- Then a comment");
+    assert_eq!(prev.next().unwrap().to_string(), "\n");
+    assert_eq!(prev.next(), None);
+}
+
+#[test]
+fn test_similar() {
+    let ast = parse("local x = 1; --[[ uh oh, filler ]] local x = 1; local x = 2;").unwrap();
+    let stmts = ast.nodes().stmts().collect::<Vec<_>>();
+
+    assert!(stmts[0].similar(stmts[1]));
+    assert!(stmts[1].similar(stmts[0]));
+    assert!(!stmts[0].similar(stmts[2]));
+}
+
+#[test]
+fn test_tokens_collect() {
+    let source = parse("local abcd = 1").unwrap();
+    let tokens = source.nodes().tokens();
+    assert_eq!(tokens.count(), 4);
+}
+
+#[test]
+fn test_tokens_back() {
+    let source = parse("local abcd = 1").unwrap();
+    let mut tokens = source.nodes().tokens();
+    assert_eq!(tokens.next_back().unwrap().to_string(), "1");
+}
diff --git a/src/Rust/vvs_parser/src/tests/one_line_range.rs b/src/Rust/vvs_parser/src/tests/one_line_range.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5534228938c46718eddf5e62d4f3bf5f52a84905
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/one_line_range.rs
@@ -0,0 +1,26 @@
+use crate::{node::Node, prelude::parser::parse_lua_tree as parse};
+
+#[test]
+fn test_one_line_range() {
+    let ast = parse(
+        r#"
+
+	local x = 1
+
+	local y = 1
+
+	local function x() print(1) end
+
+	function x() print(1) end
+
+	for index, value in pairs(list) do print(index, value) end
+
+	"#,
+    )
+    .unwrap();
+
+    for stmt in ast.nodes().stmts() {
+        let (start, end) = stmt.range().unwrap();
+        assert_eq!(end.line() - start.line(), 0, "node {stmt:?} does not have a range on the same line");
+    }
+}
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/error_display.snap b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a1f2e073376f0c2e61e48179960951db9707e821
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/error_display.snap
@@ -0,0 +1,10 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: "String::from_utf8(output.into_inner()).unwrap()"
+input_file: vvs_parser/tests/option_cases/fail/parser/keyword1
+---
+error[ast]: expected the name of an option
+  ┌─ source.ini:2:1
+  │
+2 │ option = 1
+  │ ^^^^^^
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/errors.snap b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3d699fbc13489f352d4321e99b95ca679d17813f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/errors.snap
@@ -0,0 +1,19 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.errors()
+input_file: vvs_parser/tests/option_cases/fail/parser/keyword1
+---
+- AstError:
+    token:
+      start_position:
+        bytes: 9
+        line: 2
+        character: 1
+      end_position:
+        bytes: 15
+        line: 2
+        character: 7
+      token_type:
+        type: Symbol
+        symbol: option
+    additional: expected the name of an option
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/option_table.snap b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/option_table.snap
new file mode 100644
index 0000000000000000000000000000000000000000..32091d523dc80a4b6a0d9b9cb6d5fd2ec15c8f9e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/option_table.snap
@@ -0,0 +1,6 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.option_table()
+input_file: vvs_parser/tests/option_cases/fail/parser/keyword1
+---
+modules: []
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/source.ini b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/source.ini
new file mode 100644
index 0000000000000000000000000000000000000000..c0348e2fe530a08dfd13b7634e505815116a8584
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/source.ini
@@ -0,0 +1,2 @@
+[module]
+option = 1
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/tokens.snap b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2098a5353a38485707a99621284b69245bc8c3ff
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword1/tokens.snap
@@ -0,0 +1,125 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/option_cases/fail/parser/keyword1
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 1
+    line: 1
+    character: 2
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: module
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "]"
+- 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: 15
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: option
+- start_position:
+    bytes: 15
+    line: 2
+    character: 7
+  end_position:
+    bytes: 16
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 16
+    line: 2
+    character: 8
+  end_position:
+    bytes: 17
+    line: 2
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 17
+    line: 2
+    character: 9
+  end_position:
+    bytes: 18
+    line: 2
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 18
+    line: 2
+    character: 10
+  end_position:
+    bytes: 19
+    line: 2
+    character: 11
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 19
+    line: 2
+    character: 11
+  end_position:
+    bytes: 20
+    line: 2
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 20
+    line: 3
+    character: 1
+  end_position:
+    bytes: 20
+    line: 3
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/error_display.snap b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5dcc37a4ed30f83b4942670ce4491d729519f41b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/error_display.snap
@@ -0,0 +1,16 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: "String::from_utf8(output.into_inner()).unwrap()"
+input_file: vvs_parser/tests/option_cases/fail/parser/keyword2
+---
+error[ast]: expected an identifier
+  ┌─ source.ini:1:2
+  │
+1 │ [option]
+  │  ^^^^^^
+
+error[ast]: expected an identifier as the option section name
+  ┌─ source.ini:1:1
+  │
+1 │ [option]
+  │ ^
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/errors.snap b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c45dd138c4d3764c5fc290c990b821bfa62eba4f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/errors.snap
@@ -0,0 +1,33 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.errors()
+input_file: vvs_parser/tests/option_cases/fail/parser/keyword2
+---
+- AstError:
+    token:
+      start_position:
+        bytes: 1
+        line: 1
+        character: 2
+      end_position:
+        bytes: 7
+        line: 1
+        character: 8
+      token_type:
+        type: Symbol
+        symbol: option
+    additional: expected an identifier
+- AstError:
+    token:
+      start_position:
+        bytes: 0
+        line: 1
+        character: 1
+      end_position:
+        bytes: 1
+        line: 1
+        character: 2
+      token_type:
+        type: Symbol
+        symbol: "["
+    additional: expected an identifier as the option section name
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/option_table.snap b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/option_table.snap
new file mode 100644
index 0000000000000000000000000000000000000000..14a4c7681464af5bed61cb7adb83525e99bb6a98
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/option_table.snap
@@ -0,0 +1,6 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.option_table()
+input_file: vvs_parser/tests/option_cases/fail/parser/keyword2
+---
+modules: []
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/source.ini b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/source.ini
new file mode 100644
index 0000000000000000000000000000000000000000..dec450e72ea9c39d709794f78466cdd6b7b7747a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/source.ini
@@ -0,0 +1,2 @@
+[option]
+opt1 = 1
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/tokens.snap b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c553ebbb2efa521137eccff444bf87675cec0879
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/fail/parser/keyword2/tokens.snap
@@ -0,0 +1,125 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/option_cases/fail/parser/keyword2
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 1
+    line: 1
+    character: 2
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: option
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "]"
+- 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: 13
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: opt1
+- start_position:
+    bytes: 13
+    line: 2
+    character: 5
+  end_position:
+    bytes: 14
+    line: 2
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 14
+    line: 2
+    character: 6
+  end_position:
+    bytes: 15
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 15
+    line: 2
+    character: 7
+  end_position:
+    bytes: 16
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 16
+    line: 2
+    character: 8
+  end_position:
+    bytes: 17
+    line: 2
+    character: 9
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 17
+    line: 2
+    character: 9
+  end_position:
+    bytes: 18
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 18
+    line: 3
+    character: 1
+  end_position:
+    bytes: 18
+    line: 3
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/pass/complex/options.snap b/src/Rust/vvs_parser/src/tests/option_cases/pass/complex/options.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ddd63fa80fffc209960c5b6a26a6ea2c493ea5ed
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/pass/complex/options.snap
@@ -0,0 +1,90 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: options
+input_file: vvs_parser/tests/option_cases/pass/complex
+---
+modules:
+  - - module
+    - - - option1
+        - BinaryOperator:
+            lhs:
+              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: 13
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+            binop:
+              Plus:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 21
+                    line: 2
+                    character: 13
+                  end_position:
+                    bytes: 22
+                    line: 2
+                    character: 14
+                  token_type:
+                    type: Symbol
+                    symbol: +
+                trailing_trivia:
+                  - start_position:
+                      bytes: 22
+                      line: 2
+                      character: 14
+                    end_position:
+                      bytes: 23
+                      line: 2
+                      character: 15
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+            rhs:
+              Number:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 23
+                    line: 2
+                    character: 15
+                  end_position:
+                    bytes: 24
+                    line: 2
+                    character: 16
+                  token_type:
+                    type: Number
+                    text: "1"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 24
+                      line: 2
+                      character: 16
+                    end_position:
+                      bytes: 25
+                      line: 2
+                      character: 16
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/pass/complex/source.ini b/src/Rust/vvs_parser/src/tests/option_cases/pass/complex/source.ini
new file mode 100644
index 0000000000000000000000000000000000000000..188259f9831f7fa5ed26838cb99d99caeaeec949
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/pass/complex/source.ini
@@ -0,0 +1,2 @@
+[module]
+option1 = 1 + 1
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/pass/complex/tokens.snap b/src/Rust/vvs_parser/src/tests/option_cases/pass/complex/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..85e179ff88fa6c8f342229e403a2b524eaecda08
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/pass/complex/tokens.snap
@@ -0,0 +1,169 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/option_cases/pass/complex
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 1
+    line: 1
+    character: 2
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: module
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "]"
+- 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: 16
+    line: 2
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: option1
+- 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: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 21
+    line: 2
+    character: 13
+  end_position:
+    bytes: 22
+    line: 2
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 22
+    line: 2
+    character: 14
+  end_position:
+    bytes: 23
+    line: 2
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 23
+    line: 2
+    character: 15
+  end_position:
+    bytes: 24
+    line: 2
+    character: 16
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 24
+    line: 2
+    character: 16
+  end_position:
+    bytes: 25
+    line: 2
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 25
+    line: 3
+    character: 1
+  end_position:
+    bytes: 25
+    line: 3
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/pass/empty/options.snap b/src/Rust/vvs_parser/src/tests/option_cases/pass/empty/options.snap
new file mode 100644
index 0000000000000000000000000000000000000000..17560f8142a28bacdd649ea51304bd1b4d67578b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/pass/empty/options.snap
@@ -0,0 +1,6 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: options
+input_file: vvs_parser/tests/option_cases/pass/empty
+---
+modules: []
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/pass/empty/source.ini b/src/Rust/vvs_parser/src/tests/option_cases/pass/empty/source.ini
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/pass/empty/tokens.snap b/src/Rust/vvs_parser/src/tests/option_cases/pass/empty/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..42aa56195d76282c934c878ddaa87f21c94a11b6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/pass/empty/tokens.snap
@@ -0,0 +1,15 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/option_cases/pass/empty
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 0
+    line: 1
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/pass/simple/options.snap b/src/Rust/vvs_parser/src/tests/option_cases/pass/simple/options.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ccd02baa5a39951a66d15cd7dda1821e7b086d69
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/pass/simple/options.snap
@@ -0,0 +1,90 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: options
+input_file: vvs_parser/tests/option_cases/pass/simple
+---
+modules:
+  - - module1
+    - - - opt1
+        - Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 17
+                line: 2
+                character: 8
+              end_position:
+                bytes: 18
+                line: 2
+                character: 9
+              token_type:
+                type: Number
+                text: "1"
+            trailing_trivia:
+              - start_position:
+                  bytes: 18
+                  line: 2
+                  character: 9
+                end_position:
+                  bytes: 19
+                  line: 2
+                  character: 9
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+      - - opt2
+        - Symbol:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 26
+                line: 3
+                character: 8
+              end_position:
+                bytes: 30
+                line: 3
+                character: 12
+              token_type:
+                type: Symbol
+                symbol: "true"
+            trailing_trivia:
+              - start_position:
+                  bytes: 30
+                  line: 3
+                  character: 12
+                end_position:
+                  bytes: 31
+                  line: 3
+                  character: 12
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+  - - module2
+    - - - opt1
+        - String:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 49
+                line: 6
+                character: 8
+              end_position:
+                bytes: 60
+                line: 6
+                character: 19
+              token_type:
+                type: StringLiteral
+                literal: something
+                quote_type: Double
+            trailing_trivia:
+              - start_position:
+                  bytes: 60
+                  line: 6
+                  character: 19
+                end_position:
+                  bytes: 61
+                  line: 6
+                  character: 19
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/pass/simple/source.ini b/src/Rust/vvs_parser/src/tests/option_cases/pass/simple/source.ini
new file mode 100644
index 0000000000000000000000000000000000000000..1950245e560122075890833d3431ee04f4ba7d78
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/pass/simple/source.ini
@@ -0,0 +1,6 @@
+[module1]
+opt1 = 1
+opt2 = true
+
+[module2]
+opt1 = "something"
diff --git a/src/Rust/vvs_parser/src/tests/option_cases/pass/simple/tokens.snap b/src/Rust/vvs_parser/src/tests/option_cases/pass/simple/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..46a45bb6a8c6935a98219f38f20a374fdb88239c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/option_cases/pass/simple/tokens.snap
@@ -0,0 +1,313 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/option_cases/pass/simple
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 1
+    line: 1
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 1
+    line: 1
+    character: 2
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: module1
+- 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: 14
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: opt1
+- start_position:
+    bytes: 14
+    line: 2
+    character: 5
+  end_position:
+    bytes: 15
+    line: 2
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 15
+    line: 2
+    character: 6
+  end_position:
+    bytes: 16
+    line: 2
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 16
+    line: 2
+    character: 7
+  end_position:
+    bytes: 17
+    line: 2
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 17
+    line: 2
+    character: 8
+  end_position:
+    bytes: 18
+    line: 2
+    character: 9
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 18
+    line: 2
+    character: 9
+  end_position:
+    bytes: 19
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 19
+    line: 3
+    character: 1
+  end_position:
+    bytes: 23
+    line: 3
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: opt2
+- start_position:
+    bytes: 23
+    line: 3
+    character: 5
+  end_position:
+    bytes: 24
+    line: 3
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 24
+    line: 3
+    character: 6
+  end_position:
+    bytes: 25
+    line: 3
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 25
+    line: 3
+    character: 7
+  end_position:
+    bytes: 26
+    line: 3
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 26
+    line: 3
+    character: 8
+  end_position:
+    bytes: 30
+    line: 3
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 30
+    line: 3
+    character: 12
+  end_position:
+    bytes: 31
+    line: 3
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 31
+    line: 4
+    character: 1
+  end_position:
+    bytes: 32
+    line: 4
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 32
+    line: 5
+    character: 1
+  end_position:
+    bytes: 33
+    line: 5
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 33
+    line: 5
+    character: 2
+  end_position:
+    bytes: 40
+    line: 5
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: module2
+- start_position:
+    bytes: 40
+    line: 5
+    character: 9
+  end_position:
+    bytes: 41
+    line: 5
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 41
+    line: 5
+    character: 10
+  end_position:
+    bytes: 42
+    line: 5
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 42
+    line: 6
+    character: 1
+  end_position:
+    bytes: 46
+    line: 6
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: opt1
+- start_position:
+    bytes: 46
+    line: 6
+    character: 5
+  end_position:
+    bytes: 47
+    line: 6
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 47
+    line: 6
+    character: 6
+  end_position:
+    bytes: 48
+    line: 6
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 48
+    line: 6
+    character: 7
+  end_position:
+    bytes: 49
+    line: 6
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 49
+    line: 6
+    character: 8
+  end_position:
+    bytes: 60
+    line: 6
+    character: 19
+  token_type:
+    type: StringLiteral
+    literal: something
+    quote_type: Double
+- start_position:
+    bytes: 60
+    line: 6
+    character: 19
+  end_position:
+    bytes: 61
+    line: 6
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 61
+    line: 7
+    character: 1
+  end_position:
+    bytes: 61
+    line: 7
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/pass_cases.rs b/src/Rust/vvs_parser/src/tests/pass_cases.rs
new file mode 100644
index 0000000000000000000000000000000000000000..115b7d778835e9ed19dfaa256f80922c52fe8e8f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/pass_cases.rs
@@ -0,0 +1,87 @@
+use crate::{
+    ast::AstResult,
+    node::Node,
+    tests::common::run_test_folder,
+    tokenizer::{self, Token, TokenReference},
+};
+use insta::assert_yaml_snapshot;
+use std::{fmt, fs, path::Path};
+
+#[derive(PartialEq, Eq)]
+struct PrettyString<'a>(pub &'a str);
+
+// Make diff to display string as multi-line string
+impl<'a> fmt::Debug for PrettyString<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(self.0)
+    }
+}
+
+fn unpack_token_reference(token: &TokenReference) -> Vec<Token> {
+    token
+        .leading_trivia()
+        .chain(std::iter::once(token.token()))
+        .chain(token.trailing_trivia())
+        .cloned()
+        .collect()
+}
+
+fn test_option_case(path: &Path) {
+    let source = fs::read_to_string(path.join("source.ini")).expect("couldn't read source.ini");
+    let tokens = tokenizer::Lexer::new(&source).collect().unwrap();
+    assert_yaml_snapshot!("tokens", tokens);
+
+    let options = crate::ast::OptionTableResult::parse_fallible(&source)
+        .into_result()
+        .unwrap_or_else(|error| panic!("couldn't make option table for {path:?} - {error:#?}"));
+
+    assert_yaml_snapshot!("options", options);
+}
+
+fn test_pass_case(path: &Path) {
+    let source = fs::read_to_string(path.join("source.lua")).expect("couldn't read source.lua");
+    let tokens = tokenizer::Lexer::new(&source).collect().unwrap();
+    assert_yaml_snapshot!("tokens", tokens);
+
+    let ast = AstResult::parse_fallible(&source)
+        .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(&format!("{ast}")), PrettyString(&source));
+
+    let ast = ast.update_positions();
+    assert_eq!(old_positions, ast.tokens().flat_map(unpack_token_reference).collect::<Vec<_>>(),);
+}
+
+#[test]
+fn test_roblox_pass_cases() {
+    run_test_folder("./src/tests/roblox_cases/pass", test_pass_case);
+}
+
+#[test]
+fn test_lua52_pass_cases() {
+    run_test_folder("./src/tests/lua52_cases/pass", test_pass_case);
+}
+
+#[test]
+fn test_lua53_pass_cases() {
+    run_test_folder("./src/tests/lua53_cases/pass", test_pass_case);
+}
+
+#[test]
+fn test_lua54_pass_cases() {
+    run_test_folder("./src/tests/lua54_cases/pass", test_pass_case);
+}
+
+#[test]
+fn test_vivy_pass_cases() {
+    run_test_folder("./src/tests/vivy_cases/pass", test_pass_case);
+}
+
+#[test]
+fn test_option_pass_cases() {
+    run_test_folder("./src/tests/option_cases/pass", test_option_case);
+}
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9ea7d3465a6dea784fa0fa0be539152db79d3610
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast.snap
@@ -0,0 +1,254 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.ast()
+input_file: vvs_parser/tests/roblox_cases/fail/parser/function_return_type_thin_arrow
+---
+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:
+            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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0f74fc9b031e6ecdcefd3e969bab714cc9da5873
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+---
+"function foo() -> string\n\treturn \"\"\nend"
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/error_display.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..875e2441b20c1cb682fdd81e1f74e77f9c9bf179
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/errors.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6e7cbe6551d85ead698dd8ed605774cc91717d55
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..165392c044d41dad3195b283519c968fa3e7aee9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/function_return_type_thin_arrow/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8c807bd81e6daaab3a9b8e282794192258f55c08
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cbaa915d36a5bae50288c52541c6837f5f4a9e9c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..769004af882fd785772914ba92d85b08761bb503
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+---
+""
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/error.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/error.snap
new file mode 100644
index 0000000000000000000000000000000000000000..764e5601055ae7a2a70a0e8b031d2e569c8103eb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/error.snap
@@ -0,0 +1,19 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: error
+
+---
+UnexpectedToken:
+  token:
+    start_position:
+      bytes: 26
+      line: 1
+      character: 27
+    end_position:
+      bytes: 26
+      line: 1
+      character: 27
+    token_type:
+      type: Eof
+  additional: "expected `->` after `()` when parsing function type"
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/error_display.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9179dfeb41f017cad1d7fd851d7c885311eee38d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/errors.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ff46da5cc3f95a92de2e5b096996fa4a2adf07f8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..648860cc1ecbed21da44126f21c3a5e66e2ecd91
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/source.lua
@@ -0,0 +1 @@
+type Foo = (count: number)
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..7e27690a24f36d842d9115a862884d99e3e65f82
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/named_function_arg_types/tokens.snap
@@ -0,0 +1,148 @@
+---
+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: 17
+    line: 1
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: count
+- 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: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 25
+    line: 1
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: number
+- 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: 26
+    line: 1
+    character: 27
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..776ede7ba0fb039b89e46cef53c55bac16b8003b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/ast.snap
@@ -0,0 +1,117 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.ast()
+input_file: vvs_parser/tests/roblox_cases/fail/parser/nil_dot
+---
+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: " "
+          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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0123dfe53490a5ccca7211ae1893bb76324b8204
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/ast_to_string.snap
@@ -0,0 +1,6 @@
+---
+source: full-moon/tests/fail_cases.rs
+expression: "vvs_parser::print(&ast)"
+---
+type Foo = nil
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/error.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/error.snap
new file mode 100644
index 0000000000000000000000000000000000000000..70ed0b8bf29f058d928e52087b2c4e237a56cdd6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/error.snap
@@ -0,0 +1,22 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 58
+expression: error
+input_file: full-moon/tests/roblox_cases/fail/parser/nil_dot
+
+---
+UnexpectedToken:
+  token:
+    start_position:
+      bytes: 14
+      line: 1
+      character: 15
+    end_position:
+      bytes: 15
+      line: 1
+      character: 16
+    token_type:
+      type: Symbol
+      symbol: "."
+  additional: leftover token
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/error_display.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..0e6b920e76627d4f3f2f3a2a6ee9b49c8df7c562
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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<string>
+  │               ^
+
+error[ast]: unexpected expression when looking for a statement
+  ┌─ source.lua:1:19
+  │
+1 │ type Foo = nil.bar<string>
+  │                   ^
+
+error[ast]: unexpected token, this needs to be a statement
+  ┌─ source.lua:1:19
+  │
+1 │ type Foo = nil.bar<string>
+  │                   ^
+
+error[ast]: unexpected expression when looking for a statement
+  ┌─ source.lua:1:26
+  │
+1 │ type Foo = nil.bar<string>
+  │                          ^
+
+error[ast]: unexpected token, this needs to be a statement
+  ┌─ source.lua:1:26
+  │
+1 │ type Foo = nil.bar<string>
+  │                          ^
+
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/errors.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..47554f289157b32ea93b096b6bb04d4de4afb46f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..488795aba9f5b46368cf5a0196acfd48548a1668
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/source.lua
@@ -0,0 +1 @@
+type Foo = nil.bar<string>
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..dd8c8779e89a48066a5fcb4ffb9aa2498f55cd84
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/nil_dot/tokens.snap
@@ -0,0 +1,161 @@
+---
+source: full-moon/tests/fail_cases.rs
+assertion_line: 52
+expression: tokens
+input_file: full-moon/tests/roblox_cases/fail/parser/nil_dot
+
+---
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: nil
+- 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: 18
+    line: 1
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: bar
+- 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: 25
+    line: 1
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: string
+- 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: 27
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 27
+    line: 2
+    character: 1
+  end_position:
+    bytes: 27
+    line: 2
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ee6423cdd0b2ad7c0332328072f8843cf7586a69
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast.snap
@@ -0,0 +1,411 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.ast()
+input_file: vvs_parser/tests/roblox_cases/fail/parser/type_table_no_right_brace
+---
+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: " "
+          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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f7244cced31e99ede3d02195256ed773aaa78a67
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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: "vvs_parser::print(&ast)"
+---
+"type Foo = { x: string, y: string\n}\nlocal x = 1"
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/error_display.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..dc218d2c0c17516f12356b0b9751d178c3111a40
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/errors.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..91e6c7c666d3b48101d58f6bd14d11b4850edd0c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..c882c3351fa17a1c9f55d82c40d1074d319c0a29
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/fail/parser/type_table_no_right_brace/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..fc10df6d0f60641a799af346757587613657989b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/pass/compound_assignment/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/compound_assignment/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..23ff308a56f9b7e27530ebd2f506f961fe5f00b1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/compound_assignment/ast.snap
@@ -0,0 +1,1824 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/roblox_cases/pass/compound_assignment
+---
+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:
+                    - start_position:
+                        bytes: 11
+                        line: 1
+                        character: 12
+                      end_position:
+                        bytes: 12
+                        line: 1
+                        character: 12
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 12
+              line: 2
+              character: 1
+            end_position:
+              bytes: 17
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 17
+                line: 2
+                character: 6
+              end_position:
+                bytes: 18
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 18
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 19
+                    line: 2
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: y
+                trailing_trivia:
+                  - start_position:
+                      bytes: 19
+                      line: 2
+                      character: 8
+                    end_position:
+                      bytes: 20
+                      line: 2
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 20
+              line: 2
+              character: 9
+            end_position:
+              bytes: 21
+              line: 2
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 21
+                line: 2
+                character: 10
+              end_position:
+                bytes: 22
+                line: 2
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 22
+                      line: 2
+                      character: 11
+                    end_position:
+                      bytes: 23
+                      line: 2
+                      character: 12
+                    token_type:
+                      type: Number
+                      text: "2"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 23
+                        line: 2
+                        character: 12
+                      end_position:
+                        bytes: 24
+                        line: 2
+                        character: 12
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia:
+              - start_position:
+                  bytes: 24
+                  line: 3
+                  character: 1
+                end_position:
+                  bytes: 25
+                  line: 3
+                  character: 1
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+            token:
+              start_position:
+                bytes: 25
+                line: 4
+                character: 1
+              end_position:
+                bytes: 26
+                line: 4
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 26
+                  line: 4
+                  character: 2
+                end_position:
+                  bytes: 27
+                  line: 4
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          PlusEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 27
+                line: 4
+                character: 3
+              end_position:
+                bytes: 29
+                line: 4
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: +=
+            trailing_trivia:
+              - start_position:
+                  bytes: 29
+                  line: 4
+                  character: 5
+                end_position:
+                  bytes: 30
+                  line: 4
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 30
+                line: 4
+                character: 6
+              end_position:
+                bytes: 31
+                line: 4
+                character: 7
+              token_type:
+                type: Number
+                text: "5"
+            trailing_trivia:
+              - start_position:
+                  bytes: 31
+                  line: 4
+                  character: 7
+                end_position:
+                  bytes: 32
+                  line: 4
+                  character: 7
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 32
+                line: 5
+                character: 1
+              end_position:
+                bytes: 33
+                line: 5
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 33
+                  line: 5
+                  character: 2
+                end_position:
+                  bytes: 34
+                  line: 5
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          MinusEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 34
+                line: 5
+                character: 3
+              end_position:
+                bytes: 36
+                line: 5
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: "-="
+            trailing_trivia:
+              - start_position:
+                  bytes: 36
+                  line: 5
+                  character: 5
+                end_position:
+                  bytes: 37
+                  line: 5
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 37
+                line: 5
+                character: 6
+              end_position:
+                bytes: 38
+                line: 5
+                character: 7
+              token_type:
+                type: Number
+                text: "5"
+            trailing_trivia:
+              - start_position:
+                  bytes: 38
+                  line: 5
+                  character: 7
+                end_position:
+                  bytes: 39
+                  line: 5
+                  character: 7
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 39
+                line: 6
+                character: 1
+              end_position:
+                bytes: 40
+                line: 6
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 40
+                  line: 6
+                  character: 2
+                end_position:
+                  bytes: 41
+                  line: 6
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          StarEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 41
+                line: 6
+                character: 3
+              end_position:
+                bytes: 43
+                line: 6
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: "*="
+            trailing_trivia:
+              - start_position:
+                  bytes: 43
+                  line: 6
+                  character: 5
+                end_position:
+                  bytes: 44
+                  line: 6
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 44
+                line: 6
+                character: 6
+              end_position:
+                bytes: 45
+                line: 6
+                character: 7
+              token_type:
+                type: Number
+                text: "5"
+            trailing_trivia:
+              - start_position:
+                  bytes: 45
+                  line: 6
+                  character: 7
+                end_position:
+                  bytes: 46
+                  line: 6
+                  character: 7
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 46
+                line: 7
+                character: 1
+              end_position:
+                bytes: 47
+                line: 7
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 47
+                  line: 7
+                  character: 2
+                end_position:
+                  bytes: 48
+                  line: 7
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          SlashEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 48
+                line: 7
+                character: 3
+              end_position:
+                bytes: 50
+                line: 7
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: /=
+            trailing_trivia:
+              - start_position:
+                  bytes: 50
+                  line: 7
+                  character: 5
+                end_position:
+                  bytes: 51
+                  line: 7
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 51
+                line: 7
+                character: 6
+              end_position:
+                bytes: 52
+                line: 7
+                character: 7
+              token_type:
+                type: Number
+                text: "5"
+            trailing_trivia:
+              - start_position:
+                  bytes: 52
+                  line: 7
+                  character: 7
+                end_position:
+                  bytes: 53
+                  line: 7
+                  character: 7
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 53
+                line: 8
+                character: 1
+              end_position:
+                bytes: 54
+                line: 8
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 54
+                  line: 8
+                  character: 2
+                end_position:
+                  bytes: 55
+                  line: 8
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          DoubleSlashEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 55
+                line: 8
+                character: 3
+              end_position:
+                bytes: 58
+                line: 8
+                character: 6
+              token_type:
+                type: Symbol
+                symbol: //=
+            trailing_trivia:
+              - start_position:
+                  bytes: 58
+                  line: 8
+                  character: 6
+                end_position:
+                  bytes: 59
+                  line: 8
+                  character: 7
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 59
+                line: 8
+                character: 7
+              end_position:
+                bytes: 60
+                line: 8
+                character: 8
+              token_type:
+                type: Number
+                text: "5"
+            trailing_trivia:
+              - start_position:
+                  bytes: 60
+                  line: 8
+                  character: 8
+                end_position:
+                  bytes: 61
+                  line: 8
+                  character: 8
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 61
+                line: 9
+                character: 1
+              end_position:
+                bytes: 62
+                line: 9
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 62
+                  line: 9
+                  character: 2
+                end_position:
+                  bytes: 63
+                  line: 9
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          PercentEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 63
+                line: 9
+                character: 3
+              end_position:
+                bytes: 65
+                line: 9
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: "%="
+            trailing_trivia:
+              - start_position:
+                  bytes: 65
+                  line: 9
+                  character: 5
+                end_position:
+                  bytes: 66
+                  line: 9
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 66
+                line: 9
+                character: 6
+              end_position:
+                bytes: 67
+                line: 9
+                character: 7
+              token_type:
+                type: Number
+                text: "5"
+            trailing_trivia:
+              - start_position:
+                  bytes: 67
+                  line: 9
+                  character: 7
+                end_position:
+                  bytes: 68
+                  line: 9
+                  character: 7
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 68
+                line: 10
+                character: 1
+              end_position:
+                bytes: 69
+                line: 10
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 69
+                  line: 10
+                  character: 2
+                end_position:
+                  bytes: 70
+                  line: 10
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          CaretEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 70
+                line: 10
+                character: 3
+              end_position:
+                bytes: 72
+                line: 10
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: ^=
+            trailing_trivia:
+              - start_position:
+                  bytes: 72
+                  line: 10
+                  character: 5
+                end_position:
+                  bytes: 73
+                  line: 10
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 73
+                line: 10
+                character: 6
+              end_position:
+                bytes: 74
+                line: 10
+                character: 7
+              token_type:
+                type: Number
+                text: "5"
+            trailing_trivia:
+              - start_position:
+                  bytes: 74
+                  line: 10
+                  character: 7
+                end_position:
+                  bytes: 75
+                  line: 10
+                  character: 7
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia:
+              - start_position:
+                  bytes: 75
+                  line: 11
+                  character: 1
+                end_position:
+                  bytes: 76
+                  line: 11
+                  character: 1
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+            token:
+              start_position:
+                bytes: 76
+                line: 12
+                character: 1
+              end_position:
+                bytes: 77
+                line: 12
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 77
+                  line: 12
+                  character: 2
+                end_position:
+                  bytes: 78
+                  line: 12
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          PlusEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 78
+                line: 12
+                character: 3
+              end_position:
+                bytes: 80
+                line: 12
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: +=
+            trailing_trivia:
+              - start_position:
+                  bytes: 80
+                  line: 12
+                  character: 5
+                end_position:
+                  bytes: 81
+                  line: 12
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 81
+                  line: 12
+                  character: 6
+                end_position:
+                  bytes: 82
+                  line: 12
+                  character: 7
+                token_type:
+                  type: Identifier
+                  identifier: y
+              trailing_trivia:
+                - start_position:
+                    bytes: 82
+                    line: 12
+                    character: 7
+                  end_position:
+                    bytes: 83
+                    line: 12
+                    character: 7
+                  token_type:
+                    type: Whitespace
+                    characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 83
+                line: 13
+                character: 1
+              end_position:
+                bytes: 84
+                line: 13
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 84
+                  line: 13
+                  character: 2
+                end_position:
+                  bytes: 85
+                  line: 13
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          MinusEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 85
+                line: 13
+                character: 3
+              end_position:
+                bytes: 87
+                line: 13
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: "-="
+            trailing_trivia:
+              - start_position:
+                  bytes: 87
+                  line: 13
+                  character: 5
+                end_position:
+                  bytes: 88
+                  line: 13
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 88
+                  line: 13
+                  character: 6
+                end_position:
+                  bytes: 89
+                  line: 13
+                  character: 7
+                token_type:
+                  type: Identifier
+                  identifier: y
+              trailing_trivia:
+                - start_position:
+                    bytes: 89
+                    line: 13
+                    character: 7
+                  end_position:
+                    bytes: 90
+                    line: 13
+                    character: 7
+                  token_type:
+                    type: Whitespace
+                    characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 90
+                line: 14
+                character: 1
+              end_position:
+                bytes: 91
+                line: 14
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 91
+                  line: 14
+                  character: 2
+                end_position:
+                  bytes: 92
+                  line: 14
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          StarEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 92
+                line: 14
+                character: 3
+              end_position:
+                bytes: 94
+                line: 14
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: "*="
+            trailing_trivia:
+              - start_position:
+                  bytes: 94
+                  line: 14
+                  character: 5
+                end_position:
+                  bytes: 95
+                  line: 14
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 95
+                  line: 14
+                  character: 6
+                end_position:
+                  bytes: 96
+                  line: 14
+                  character: 7
+                token_type:
+                  type: Identifier
+                  identifier: y
+              trailing_trivia:
+                - start_position:
+                    bytes: 96
+                    line: 14
+                    character: 7
+                  end_position:
+                    bytes: 97
+                    line: 14
+                    character: 7
+                  token_type:
+                    type: Whitespace
+                    characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 97
+                line: 15
+                character: 1
+              end_position:
+                bytes: 98
+                line: 15
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 98
+                  line: 15
+                  character: 2
+                end_position:
+                  bytes: 99
+                  line: 15
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          SlashEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 99
+                line: 15
+                character: 3
+              end_position:
+                bytes: 101
+                line: 15
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: /=
+            trailing_trivia:
+              - start_position:
+                  bytes: 101
+                  line: 15
+                  character: 5
+                end_position:
+                  bytes: 102
+                  line: 15
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 102
+                  line: 15
+                  character: 6
+                end_position:
+                  bytes: 103
+                  line: 15
+                  character: 7
+                token_type:
+                  type: Identifier
+                  identifier: y
+              trailing_trivia:
+                - start_position:
+                    bytes: 103
+                    line: 15
+                    character: 7
+                  end_position:
+                    bytes: 104
+                    line: 15
+                    character: 7
+                  token_type:
+                    type: Whitespace
+                    characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 104
+                line: 16
+                character: 1
+              end_position:
+                bytes: 105
+                line: 16
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 105
+                  line: 16
+                  character: 2
+                end_position:
+                  bytes: 106
+                  line: 16
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          DoubleSlashEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 106
+                line: 16
+                character: 3
+              end_position:
+                bytes: 109
+                line: 16
+                character: 6
+              token_type:
+                type: Symbol
+                symbol: //=
+            trailing_trivia:
+              - start_position:
+                  bytes: 109
+                  line: 16
+                  character: 6
+                end_position:
+                  bytes: 110
+                  line: 16
+                  character: 7
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 110
+                  line: 16
+                  character: 7
+                end_position:
+                  bytes: 111
+                  line: 16
+                  character: 8
+                token_type:
+                  type: Identifier
+                  identifier: y
+              trailing_trivia:
+                - start_position:
+                    bytes: 111
+                    line: 16
+                    character: 8
+                  end_position:
+                    bytes: 112
+                    line: 16
+                    character: 8
+                  token_type:
+                    type: Whitespace
+                    characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 112
+                line: 17
+                character: 1
+              end_position:
+                bytes: 113
+                line: 17
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 113
+                  line: 17
+                  character: 2
+                end_position:
+                  bytes: 114
+                  line: 17
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          PercentEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 114
+                line: 17
+                character: 3
+              end_position:
+                bytes: 116
+                line: 17
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: "%="
+            trailing_trivia:
+              - start_position:
+                  bytes: 116
+                  line: 17
+                  character: 5
+                end_position:
+                  bytes: 117
+                  line: 17
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 117
+                  line: 17
+                  character: 6
+                end_position:
+                  bytes: 118
+                  line: 17
+                  character: 7
+                token_type:
+                  type: Identifier
+                  identifier: y
+              trailing_trivia:
+                - start_position:
+                    bytes: 118
+                    line: 17
+                    character: 7
+                  end_position:
+                    bytes: 119
+                    line: 17
+                    character: 7
+                  token_type:
+                    type: Whitespace
+                    characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 119
+                line: 18
+                character: 1
+              end_position:
+                bytes: 120
+                line: 18
+                character: 2
+              token_type:
+                type: Identifier
+                identifier: x
+            trailing_trivia:
+              - start_position:
+                  bytes: 120
+                  line: 18
+                  character: 2
+                end_position:
+                  bytes: 121
+                  line: 18
+                  character: 3
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          CaretEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 121
+                line: 18
+                character: 3
+              end_position:
+                bytes: 123
+                line: 18
+                character: 5
+              token_type:
+                type: Symbol
+                symbol: ^=
+            trailing_trivia:
+              - start_position:
+                  bytes: 123
+                  line: 18
+                  character: 5
+                end_position:
+                  bytes: 124
+                  line: 18
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 124
+                  line: 18
+                  character: 6
+                end_position:
+                  bytes: 125
+                  line: 18
+                  character: 7
+                token_type:
+                  type: Identifier
+                  identifier: y
+              trailing_trivia:
+                - start_position:
+                    bytes: 125
+                    line: 18
+                    character: 7
+                  end_position:
+                    bytes: 126
+                    line: 18
+                    character: 7
+                  token_type:
+                    type: Whitespace
+                    characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 126
+                line: 19
+                character: 1
+              end_position:
+                bytes: 127
+                line: 19
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 127
+              line: 20
+              character: 1
+            end_position:
+              bytes: 132
+              line: 20
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 132
+                line: 20
+                character: 6
+              end_position:
+                bytes: 133
+                line: 20
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 133
+                    line: 20
+                    character: 7
+                  end_position:
+                    bytes: 137
+                    line: 20
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: str1
+                trailing_trivia:
+                  - start_position:
+                      bytes: 137
+                      line: 20
+                      character: 11
+                    end_position:
+                      bytes: 138
+                      line: 20
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 138
+              line: 20
+              character: 12
+            end_position:
+              bytes: 139
+              line: 20
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 139
+                line: 20
+                character: 13
+              end_position:
+                bytes: 140
+                line: 20
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                String:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 140
+                      line: 20
+                      character: 14
+                    end_position:
+                      bytes: 149
+                      line: 20
+                      character: 23
+                    token_type:
+                      type: StringLiteral
+                      literal: "Hello, "
+                      quote_type: Double
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 149
+                        line: 20
+                        character: 23
+                      end_position:
+                        bytes: 150
+                        line: 20
+                        character: 23
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 150
+              line: 21
+              character: 1
+            end_position:
+              bytes: 155
+              line: 21
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 155
+                line: 21
+                character: 6
+              end_position:
+                bytes: 156
+                line: 21
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 156
+                    line: 21
+                    character: 7
+                  end_position:
+                    bytes: 160
+                    line: 21
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: str2
+                trailing_trivia:
+                  - start_position:
+                      bytes: 160
+                      line: 21
+                      character: 11
+                    end_position:
+                      bytes: 161
+                      line: 21
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 161
+              line: 21
+              character: 12
+            end_position:
+              bytes: 162
+              line: 21
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 162
+                line: 21
+                character: 13
+              end_position:
+                bytes: 163
+                line: 21
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                String:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 163
+                      line: 21
+                      character: 14
+                    end_position:
+                      bytes: 171
+                      line: 21
+                      character: 22
+                    token_type:
+                      type: StringLiteral
+                      literal: world!
+                      quote_type: Double
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 171
+                        line: 21
+                        character: 22
+                      end_position:
+                        bytes: 172
+                        line: 21
+                        character: 22
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia:
+              - start_position:
+                  bytes: 172
+                  line: 22
+                  character: 1
+                end_position:
+                  bytes: 173
+                  line: 22
+                  character: 1
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+            token:
+              start_position:
+                bytes: 173
+                line: 23
+                character: 1
+              end_position:
+                bytes: 177
+                line: 23
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: str1
+            trailing_trivia:
+              - start_position:
+                  bytes: 177
+                  line: 23
+                  character: 5
+                end_position:
+                  bytes: 178
+                  line: 23
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          TwoDotsEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 178
+                line: 23
+                character: 6
+              end_position:
+                bytes: 181
+                line: 23
+                character: 9
+              token_type:
+                type: Symbol
+                symbol: "..="
+            trailing_trivia:
+              - start_position:
+                  bytes: 181
+                  line: 23
+                  character: 9
+                end_position:
+                  bytes: 182
+                  line: 23
+                  character: 10
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          String:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 182
+                line: 23
+                character: 10
+              end_position:
+                bytes: 190
+                line: 23
+                character: 18
+              token_type:
+                type: StringLiteral
+                literal: world!
+                quote_type: Double
+            trailing_trivia:
+              - start_position:
+                  bytes: 190
+                  line: 23
+                  character: 18
+                end_position:
+                  bytes: 191
+                  line: 23
+                  character: 18
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - CompoundAssignment:
+        lhs:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 191
+                line: 24
+                character: 1
+              end_position:
+                bytes: 195
+                line: 24
+                character: 5
+              token_type:
+                type: Identifier
+                identifier: str1
+            trailing_trivia:
+              - start_position:
+                  bytes: 195
+                  line: 24
+                  character: 5
+                end_position:
+                  bytes: 196
+                  line: 24
+                  character: 6
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        compound_operator:
+          TwoDotsEqual:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 196
+                line: 24
+                character: 6
+              end_position:
+                bytes: 199
+                line: 24
+                character: 9
+              token_type:
+                type: Symbol
+                symbol: "..="
+            trailing_trivia:
+              - start_position:
+                  bytes: 199
+                  line: 24
+                  character: 9
+                end_position:
+                  bytes: 200
+                  line: 24
+                  character: 10
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        rhs:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 200
+                  line: 24
+                  character: 10
+                end_position:
+                  bytes: 204
+                  line: 24
+                  character: 14
+                token_type:
+                  type: Identifier
+                  identifier: str2
+              trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/compound_assignment/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/compound_assignment/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..ed2ab3c8d24e0fd875d69e073e770e53ce558643
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/compound_assignment/source.lua
@@ -0,0 +1,24 @@
+local x = 1
+local y = 2
+
+x += 5
+x -= 5
+x *= 5
+x /= 5
+x //= 5
+x %= 5
+x ^= 5
+
+x += y
+x -= y
+x *= y
+x /= y
+x //= y
+x %= y
+x ^= y
+
+local str1 = "Hello, "
+local str2 = "world!"
+
+str1 ..= "world!"
+str1 ..= str2
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/compound_assignment/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/compound_assignment/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f60aed94eb2f14fccde97356f049c4ebe1ec82c5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/compound_assignment/tokens.snap
@@ -0,0 +1,1461 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 38
+expression: tokens
+input_file: full-moon/tests/roblox_cases/pass/compound_assignment
+---
+- 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: Number
+    text: "1"
+- 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: 17
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 17
+    line: 2
+    character: 6
+  end_position:
+    bytes: 18
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 18
+    line: 2
+    character: 7
+  end_position:
+    bytes: 19
+    line: 2
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: y
+- 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: 23
+    line: 2
+    character: 12
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 23
+    line: 2
+    character: 12
+  end_position:
+    bytes: 24
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 24
+    line: 3
+    character: 1
+  end_position:
+    bytes: 25
+    line: 3
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 25
+    line: 4
+    character: 1
+  end_position:
+    bytes: 26
+    line: 4
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 26
+    line: 4
+    character: 2
+  end_position:
+    bytes: 27
+    line: 4
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 27
+    line: 4
+    character: 3
+  end_position:
+    bytes: 29
+    line: 4
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: +=
+- start_position:
+    bytes: 29
+    line: 4
+    character: 5
+  end_position:
+    bytes: 30
+    line: 4
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 30
+    line: 4
+    character: 6
+  end_position:
+    bytes: 31
+    line: 4
+    character: 7
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 31
+    line: 4
+    character: 7
+  end_position:
+    bytes: 32
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 32
+    line: 5
+    character: 1
+  end_position:
+    bytes: 33
+    line: 5
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 33
+    line: 5
+    character: 2
+  end_position:
+    bytes: 34
+    line: 5
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 34
+    line: 5
+    character: 3
+  end_position:
+    bytes: 36
+    line: 5
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "-="
+- start_position:
+    bytes: 36
+    line: 5
+    character: 5
+  end_position:
+    bytes: 37
+    line: 5
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 37
+    line: 5
+    character: 6
+  end_position:
+    bytes: 38
+    line: 5
+    character: 7
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 38
+    line: 5
+    character: 7
+  end_position:
+    bytes: 39
+    line: 5
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 39
+    line: 6
+    character: 1
+  end_position:
+    bytes: 40
+    line: 6
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 40
+    line: 6
+    character: 2
+  end_position:
+    bytes: 41
+    line: 6
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 41
+    line: 6
+    character: 3
+  end_position:
+    bytes: 43
+    line: 6
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "*="
+- start_position:
+    bytes: 43
+    line: 6
+    character: 5
+  end_position:
+    bytes: 44
+    line: 6
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 44
+    line: 6
+    character: 6
+  end_position:
+    bytes: 45
+    line: 6
+    character: 7
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 45
+    line: 6
+    character: 7
+  end_position:
+    bytes: 46
+    line: 6
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 46
+    line: 7
+    character: 1
+  end_position:
+    bytes: 47
+    line: 7
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 47
+    line: 7
+    character: 2
+  end_position:
+    bytes: 48
+    line: 7
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 48
+    line: 7
+    character: 3
+  end_position:
+    bytes: 50
+    line: 7
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: /=
+- start_position:
+    bytes: 50
+    line: 7
+    character: 5
+  end_position:
+    bytes: 51
+    line: 7
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 51
+    line: 7
+    character: 6
+  end_position:
+    bytes: 52
+    line: 7
+    character: 7
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 52
+    line: 7
+    character: 7
+  end_position:
+    bytes: 53
+    line: 7
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 53
+    line: 8
+    character: 1
+  end_position:
+    bytes: 54
+    line: 8
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 54
+    line: 8
+    character: 2
+  end_position:
+    bytes: 55
+    line: 8
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 55
+    line: 8
+    character: 3
+  end_position:
+    bytes: 58
+    line: 8
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: //=
+- start_position:
+    bytes: 58
+    line: 8
+    character: 6
+  end_position:
+    bytes: 59
+    line: 8
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 59
+    line: 8
+    character: 7
+  end_position:
+    bytes: 60
+    line: 8
+    character: 8
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 60
+    line: 8
+    character: 8
+  end_position:
+    bytes: 61
+    line: 8
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 61
+    line: 9
+    character: 1
+  end_position:
+    bytes: 62
+    line: 9
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 62
+    line: 9
+    character: 2
+  end_position:
+    bytes: 63
+    line: 9
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 63
+    line: 9
+    character: 3
+  end_position:
+    bytes: 65
+    line: 9
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "%="
+- start_position:
+    bytes: 65
+    line: 9
+    character: 5
+  end_position:
+    bytes: 66
+    line: 9
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 66
+    line: 9
+    character: 6
+  end_position:
+    bytes: 67
+    line: 9
+    character: 7
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 67
+    line: 9
+    character: 7
+  end_position:
+    bytes: 68
+    line: 9
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 68
+    line: 10
+    character: 1
+  end_position:
+    bytes: 69
+    line: 10
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 69
+    line: 10
+    character: 2
+  end_position:
+    bytes: 70
+    line: 10
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 70
+    line: 10
+    character: 3
+  end_position:
+    bytes: 72
+    line: 10
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: ^=
+- start_position:
+    bytes: 72
+    line: 10
+    character: 5
+  end_position:
+    bytes: 73
+    line: 10
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 73
+    line: 10
+    character: 6
+  end_position:
+    bytes: 74
+    line: 10
+    character: 7
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 74
+    line: 10
+    character: 7
+  end_position:
+    bytes: 75
+    line: 10
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 75
+    line: 11
+    character: 1
+  end_position:
+    bytes: 76
+    line: 11
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 76
+    line: 12
+    character: 1
+  end_position:
+    bytes: 77
+    line: 12
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 77
+    line: 12
+    character: 2
+  end_position:
+    bytes: 78
+    line: 12
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 78
+    line: 12
+    character: 3
+  end_position:
+    bytes: 80
+    line: 12
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: +=
+- start_position:
+    bytes: 80
+    line: 12
+    character: 5
+  end_position:
+    bytes: 81
+    line: 12
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 81
+    line: 12
+    character: 6
+  end_position:
+    bytes: 82
+    line: 12
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 82
+    line: 12
+    character: 7
+  end_position:
+    bytes: 83
+    line: 12
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 83
+    line: 13
+    character: 1
+  end_position:
+    bytes: 84
+    line: 13
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 84
+    line: 13
+    character: 2
+  end_position:
+    bytes: 85
+    line: 13
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 85
+    line: 13
+    character: 3
+  end_position:
+    bytes: 87
+    line: 13
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "-="
+- start_position:
+    bytes: 87
+    line: 13
+    character: 5
+  end_position:
+    bytes: 88
+    line: 13
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 88
+    line: 13
+    character: 6
+  end_position:
+    bytes: 89
+    line: 13
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 89
+    line: 13
+    character: 7
+  end_position:
+    bytes: 90
+    line: 13
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 90
+    line: 14
+    character: 1
+  end_position:
+    bytes: 91
+    line: 14
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 91
+    line: 14
+    character: 2
+  end_position:
+    bytes: 92
+    line: 14
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 92
+    line: 14
+    character: 3
+  end_position:
+    bytes: 94
+    line: 14
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "*="
+- start_position:
+    bytes: 94
+    line: 14
+    character: 5
+  end_position:
+    bytes: 95
+    line: 14
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 95
+    line: 14
+    character: 6
+  end_position:
+    bytes: 96
+    line: 14
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 96
+    line: 14
+    character: 7
+  end_position:
+    bytes: 97
+    line: 14
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 97
+    line: 15
+    character: 1
+  end_position:
+    bytes: 98
+    line: 15
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 98
+    line: 15
+    character: 2
+  end_position:
+    bytes: 99
+    line: 15
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 99
+    line: 15
+    character: 3
+  end_position:
+    bytes: 101
+    line: 15
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: /=
+- start_position:
+    bytes: 101
+    line: 15
+    character: 5
+  end_position:
+    bytes: 102
+    line: 15
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 102
+    line: 15
+    character: 6
+  end_position:
+    bytes: 103
+    line: 15
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 103
+    line: 15
+    character: 7
+  end_position:
+    bytes: 104
+    line: 15
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 104
+    line: 16
+    character: 1
+  end_position:
+    bytes: 105
+    line: 16
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 105
+    line: 16
+    character: 2
+  end_position:
+    bytes: 106
+    line: 16
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 106
+    line: 16
+    character: 3
+  end_position:
+    bytes: 109
+    line: 16
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: //=
+- start_position:
+    bytes: 109
+    line: 16
+    character: 6
+  end_position:
+    bytes: 110
+    line: 16
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 110
+    line: 16
+    character: 7
+  end_position:
+    bytes: 111
+    line: 16
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 111
+    line: 16
+    character: 8
+  end_position:
+    bytes: 112
+    line: 16
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 112
+    line: 17
+    character: 1
+  end_position:
+    bytes: 113
+    line: 17
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 113
+    line: 17
+    character: 2
+  end_position:
+    bytes: 114
+    line: 17
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 114
+    line: 17
+    character: 3
+  end_position:
+    bytes: 116
+    line: 17
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: "%="
+- start_position:
+    bytes: 116
+    line: 17
+    character: 5
+  end_position:
+    bytes: 117
+    line: 17
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 117
+    line: 17
+    character: 6
+  end_position:
+    bytes: 118
+    line: 17
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 118
+    line: 17
+    character: 7
+  end_position:
+    bytes: 119
+    line: 17
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 119
+    line: 18
+    character: 1
+  end_position:
+    bytes: 120
+    line: 18
+    character: 2
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 120
+    line: 18
+    character: 2
+  end_position:
+    bytes: 121
+    line: 18
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 121
+    line: 18
+    character: 3
+  end_position:
+    bytes: 123
+    line: 18
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: ^=
+- start_position:
+    bytes: 123
+    line: 18
+    character: 5
+  end_position:
+    bytes: 124
+    line: 18
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 124
+    line: 18
+    character: 6
+  end_position:
+    bytes: 125
+    line: 18
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 125
+    line: 18
+    character: 7
+  end_position:
+    bytes: 126
+    line: 18
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 126
+    line: 19
+    character: 1
+  end_position:
+    bytes: 127
+    line: 19
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 127
+    line: 20
+    character: 1
+  end_position:
+    bytes: 132
+    line: 20
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 132
+    line: 20
+    character: 6
+  end_position:
+    bytes: 133
+    line: 20
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 133
+    line: 20
+    character: 7
+  end_position:
+    bytes: 137
+    line: 20
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: str1
+- start_position:
+    bytes: 137
+    line: 20
+    character: 11
+  end_position:
+    bytes: 138
+    line: 20
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 138
+    line: 20
+    character: 12
+  end_position:
+    bytes: 139
+    line: 20
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 139
+    line: 20
+    character: 13
+  end_position:
+    bytes: 140
+    line: 20
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 140
+    line: 20
+    character: 14
+  end_position:
+    bytes: 149
+    line: 20
+    character: 23
+  token_type:
+    type: StringLiteral
+    literal: "Hello, "
+    quote_type: Double
+- start_position:
+    bytes: 149
+    line: 20
+    character: 23
+  end_position:
+    bytes: 150
+    line: 20
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 150
+    line: 21
+    character: 1
+  end_position:
+    bytes: 155
+    line: 21
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 155
+    line: 21
+    character: 6
+  end_position:
+    bytes: 156
+    line: 21
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 156
+    line: 21
+    character: 7
+  end_position:
+    bytes: 160
+    line: 21
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: str2
+- start_position:
+    bytes: 160
+    line: 21
+    character: 11
+  end_position:
+    bytes: 161
+    line: 21
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 161
+    line: 21
+    character: 12
+  end_position:
+    bytes: 162
+    line: 21
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 162
+    line: 21
+    character: 13
+  end_position:
+    bytes: 163
+    line: 21
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 163
+    line: 21
+    character: 14
+  end_position:
+    bytes: 171
+    line: 21
+    character: 22
+  token_type:
+    type: StringLiteral
+    literal: world!
+    quote_type: Double
+- start_position:
+    bytes: 171
+    line: 21
+    character: 22
+  end_position:
+    bytes: 172
+    line: 21
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 172
+    line: 22
+    character: 1
+  end_position:
+    bytes: 173
+    line: 22
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 173
+    line: 23
+    character: 1
+  end_position:
+    bytes: 177
+    line: 23
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: str1
+- start_position:
+    bytes: 177
+    line: 23
+    character: 5
+  end_position:
+    bytes: 178
+    line: 23
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 178
+    line: 23
+    character: 6
+  end_position:
+    bytes: 181
+    line: 23
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "..="
+- start_position:
+    bytes: 181
+    line: 23
+    character: 9
+  end_position:
+    bytes: 182
+    line: 23
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 182
+    line: 23
+    character: 10
+  end_position:
+    bytes: 190
+    line: 23
+    character: 18
+  token_type:
+    type: StringLiteral
+    literal: world!
+    quote_type: Double
+- start_position:
+    bytes: 190
+    line: 23
+    character: 18
+  end_position:
+    bytes: 191
+    line: 23
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 191
+    line: 24
+    character: 1
+  end_position:
+    bytes: 195
+    line: 24
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: str1
+- start_position:
+    bytes: 195
+    line: 24
+    character: 5
+  end_position:
+    bytes: 196
+    line: 24
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 196
+    line: 24
+    character: 6
+  end_position:
+    bytes: 199
+    line: 24
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: "..="
+- start_position:
+    bytes: 199
+    line: 24
+    character: 9
+  end_position:
+    bytes: 200
+    line: 24
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 200
+    line: 24
+    character: 10
+  end_position:
+    bytes: 204
+    line: 24
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: str2
+- start_position:
+    bytes: 204
+    line: 24
+    character: 14
+  end_position:
+    bytes: 204
+    line: 24
+    character: 14
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/continue/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/continue/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..54eb84aad681b63d2f7ab48b6c71a1182ea4cc29
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/continue/ast.snap
@@ -0,0 +1,365 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/roblox_cases/pass/continue
+---
+stmts:
+  - - While:
+        while_token:
+          leading_trivia:
+            - start_position:
+                bytes: 0
+                line: 1
+                character: 1
+              end_position:
+                bytes: 27
+                line: 1
+                character: 28
+              token_type:
+                type: SingleLineComment
+                comment: " Very important loop here"
+            - start_position:
+                bytes: 27
+                line: 1
+                character: 28
+              end_position:
+                bytes: 28
+                line: 1
+                character: 28
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 28
+              line: 2
+              character: 1
+            end_position:
+              bytes: 33
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: while
+          trailing_trivia:
+            - start_position:
+                bytes: 33
+                line: 2
+                character: 6
+              end_position:
+                bytes: 34
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        condition:
+          Symbol:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 34
+                line: 2
+                character: 7
+              end_position:
+                bytes: 38
+                line: 2
+                character: 11
+              token_type:
+                type: Symbol
+                symbol: "true"
+            trailing_trivia:
+              - start_position:
+                  bytes: 38
+                  line: 2
+                  character: 11
+                end_position:
+                  bytes: 39
+                  line: 2
+                  character: 12
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        do_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 39
+              line: 2
+              character: 12
+            end_position:
+              bytes: 41
+              line: 2
+              character: 14
+            token_type:
+              type: Symbol
+              symbol: do
+          trailing_trivia:
+            - start_position:
+                bytes: 41
+                line: 2
+                character: 14
+              end_position:
+                bytes: 42
+                line: 2
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        block:
+          stmts: []
+          last_stmt:
+            - Continue:
+                leading_trivia:
+                  - start_position:
+                      bytes: 42
+                      line: 3
+                      character: 1
+                    end_position:
+                      bytes: 43
+                      line: 3
+                      character: 2
+                    token_type:
+                      type: Whitespace
+                      characters: "\t"
+                token:
+                  start_position:
+                    bytes: 43
+                    line: 3
+                    character: 2
+                  end_position:
+                    bytes: 51
+                    line: 3
+                    character: 10
+                  token_type:
+                    type: Identifier
+                    identifier: continue
+                trailing_trivia:
+                  - start_position:
+                      bytes: 51
+                      line: 3
+                      character: 10
+                    end_position:
+                      bytes: 52
+                      line: 3
+                      character: 10
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+            - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 52
+              line: 4
+              character: 1
+            end_position:
+              bytes: 55
+              line: 4
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 55
+                line: 4
+                character: 4
+              end_position:
+                bytes: 56
+                line: 4
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia:
+              - start_position:
+                  bytes: 56
+                  line: 5
+                  character: 1
+                end_position:
+                  bytes: 57
+                  line: 5
+                  character: 1
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+            token:
+              start_position:
+                bytes: 57
+                line: 6
+                character: 1
+              end_position:
+                bytes: 65
+                line: 6
+                character: 9
+              token_type:
+                type: Identifier
+                identifier: continue
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 65
+                            line: 6
+                            character: 9
+                          end_position:
+                            bytes: 66
+                            line: 6
+                            character: 10
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 66
+                            line: 6
+                            character: 10
+                          end_position:
+                            bytes: 67
+                            line: 6
+                            character: 11
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 67
+                              line: 6
+                              character: 11
+                            end_position:
+                              bytes: 68
+                              line: 6
+                              character: 11
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  arguments:
+                    pairs: []
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 68
+              line: 7
+              character: 1
+            end_position:
+              bytes: 73
+              line: 7
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 73
+                line: 7
+                character: 6
+              end_position:
+                bytes: 74
+                line: 7
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 74
+                    line: 7
+                    character: 7
+                  end_position:
+                    bytes: 82
+                    line: 7
+                    character: 15
+                  token_type:
+                    type: Identifier
+                    identifier: continue
+                trailing_trivia:
+                  - start_position:
+                      bytes: 82
+                      line: 7
+                      character: 15
+                    end_position:
+                      bytes: 83
+                      line: 7
+                      character: 16
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 83
+              line: 7
+              character: 16
+            end_position:
+              bytes: 84
+              line: 7
+              character: 17
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 84
+                line: 7
+                character: 17
+              end_position:
+                bytes: 85
+                line: 7
+                character: 18
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 85
+                      line: 7
+                      character: 18
+                    end_position:
+                      bytes: 86
+                      line: 7
+                      character: 19
+                    token_type:
+                      type: Number
+                      text: "4"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 86
+                        line: 7
+                        character: 19
+                      end_position:
+                        bytes: 87
+                        line: 7
+                        character: 19
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/continue/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/continue/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..f712f24d06598eeeccc8bdb563074118aec71938
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/continue/source.lua
@@ -0,0 +1,7 @@
+-- Very important loop here
+while true do
+	continue
+end
+
+continue()
+local continue = 4
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/continue/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/continue/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..58a1adabf33efa6ef7b58e1e760320c86568f665
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/continue/tokens.snap
@@ -0,0 +1,303 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/roblox_cases/pass/continue
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 27
+    line: 1
+    character: 28
+  token_type:
+    type: SingleLineComment
+    comment: " Very important loop here"
+- start_position:
+    bytes: 27
+    line: 1
+    character: 28
+  end_position:
+    bytes: 28
+    line: 1
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 28
+    line: 2
+    character: 1
+  end_position:
+    bytes: 33
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: while
+- start_position:
+    bytes: 33
+    line: 2
+    character: 6
+  end_position:
+    bytes: 34
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 34
+    line: 2
+    character: 7
+  end_position:
+    bytes: 38
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 38
+    line: 2
+    character: 11
+  end_position:
+    bytes: 39
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 39
+    line: 2
+    character: 12
+  end_position:
+    bytes: 41
+    line: 2
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 41
+    line: 2
+    character: 14
+  end_position:
+    bytes: 42
+    line: 2
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 42
+    line: 3
+    character: 1
+  end_position:
+    bytes: 43
+    line: 3
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 43
+    line: 3
+    character: 2
+  end_position:
+    bytes: 51
+    line: 3
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: continue
+- start_position:
+    bytes: 51
+    line: 3
+    character: 10
+  end_position:
+    bytes: 52
+    line: 3
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 52
+    line: 4
+    character: 1
+  end_position:
+    bytes: 55
+    line: 4
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 55
+    line: 4
+    character: 4
+  end_position:
+    bytes: 56
+    line: 4
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 56
+    line: 5
+    character: 1
+  end_position:
+    bytes: 57
+    line: 5
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 57
+    line: 6
+    character: 1
+  end_position:
+    bytes: 65
+    line: 6
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: continue
+- start_position:
+    bytes: 65
+    line: 6
+    character: 9
+  end_position:
+    bytes: 66
+    line: 6
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 66
+    line: 6
+    character: 10
+  end_position:
+    bytes: 67
+    line: 6
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 67
+    line: 6
+    character: 11
+  end_position:
+    bytes: 68
+    line: 6
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 68
+    line: 7
+    character: 1
+  end_position:
+    bytes: 73
+    line: 7
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 73
+    line: 7
+    character: 6
+  end_position:
+    bytes: 74
+    line: 7
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 74
+    line: 7
+    character: 7
+  end_position:
+    bytes: 82
+    line: 7
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: continue
+- start_position:
+    bytes: 82
+    line: 7
+    character: 15
+  end_position:
+    bytes: 83
+    line: 7
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 83
+    line: 7
+    character: 16
+  end_position:
+    bytes: 84
+    line: 7
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 84
+    line: 7
+    character: 17
+  end_position:
+    bytes: 85
+    line: 7
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 85
+    line: 7
+    character: 18
+  end_position:
+    bytes: 86
+    line: 7
+    character: 19
+  token_type:
+    type: Number
+    text: "4"
+- start_position:
+    bytes: 86
+    line: 7
+    character: 19
+  end_position:
+    bytes: 87
+    line: 7
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 87
+    line: 8
+    character: 1
+  end_position:
+    bytes: 87
+    line: 8
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/decimal_seperators/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/decimal_seperators/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8a2bf0d50411fecd2adc11f35291c558d1bd51b9
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/decimal_seperators/ast.snap
@@ -0,0 +1,663 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/roblox_cases/pass/decimal_seperators
+---
+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: num1
+                trailing_trivia:
+                  - start_position:
+                      bytes: 10
+                      line: 1
+                      character: 11
+                    end_position:
+                      bytes: 11
+                      line: 1
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        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: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 13
+                      line: 1
+                      character: 14
+                    end_position:
+                      bytes: 22
+                      line: 1
+                      character: 23
+                    token_type:
+                      type: Number
+                      text: 1_048_576
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 22
+                        line: 1
+                        character: 23
+                      end_position:
+                        bytes: 23
+                        line: 1
+                        character: 23
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 23
+              line: 2
+              character: 1
+            end_position:
+              bytes: 28
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 28
+                line: 2
+                character: 6
+              end_position:
+                bytes: 29
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 29
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 33
+                    line: 2
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: num2
+                trailing_trivia:
+                  - start_position:
+                      bytes: 33
+                      line: 2
+                      character: 11
+                    end_position:
+                      bytes: 34
+                      line: 2
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 34
+              line: 2
+              character: 12
+            end_position:
+              bytes: 35
+              line: 2
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 35
+                line: 2
+                character: 13
+              end_position:
+                bytes: 36
+                line: 2
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 36
+                      line: 2
+                      character: 14
+                    end_position:
+                      bytes: 47
+                      line: 2
+                      character: 25
+                    token_type:
+                      type: Number
+                      text: "0xFFFF_FFFF"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 47
+                        line: 2
+                        character: 25
+                      end_position:
+                        bytes: 48
+                        line: 2
+                        character: 25
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 48
+              line: 3
+              character: 1
+            end_position:
+              bytes: 53
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 53
+                line: 3
+                character: 6
+              end_position:
+                bytes: 54
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 54
+                    line: 3
+                    character: 7
+                  end_position:
+                    bytes: 58
+                    line: 3
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: num3
+                trailing_trivia:
+                  - start_position:
+                      bytes: 58
+                      line: 3
+                      character: 11
+                    end_position:
+                      bytes: 59
+                      line: 3
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 59
+              line: 3
+              character: 12
+            end_position:
+              bytes: 60
+              line: 3
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 60
+                line: 3
+                character: 13
+              end_position:
+                bytes: 61
+                line: 3
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 61
+                      line: 3
+                      character: 14
+                    end_position:
+                      bytes: 73
+                      line: 3
+                      character: 26
+                    token_type:
+                      type: Number
+                      text: 0b_0101_0101
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 73
+                        line: 3
+                        character: 26
+                      end_position:
+                        bytes: 74
+                        line: 3
+                        character: 26
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 74
+              line: 4
+              character: 1
+            end_position:
+              bytes: 79
+              line: 4
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 79
+                line: 4
+                character: 6
+              end_position:
+                bytes: 80
+                line: 4
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 80
+                    line: 4
+                    character: 7
+                  end_position:
+                    bytes: 84
+                    line: 4
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: num4
+                trailing_trivia:
+                  - start_position:
+                      bytes: 84
+                      line: 4
+                      character: 11
+                    end_position:
+                      bytes: 85
+                      line: 4
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 85
+              line: 4
+              character: 12
+            end_position:
+              bytes: 86
+              line: 4
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 86
+                line: 4
+                character: 13
+              end_position:
+                bytes: 87
+                line: 4
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 87
+                      line: 4
+                      character: 14
+                    end_position:
+                      bytes: 108
+                      line: 4
+                      character: 35
+                    token_type:
+                      type: Number
+                      text: 1_523_423.132_452_312
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 108
+                        line: 4
+                        character: 35
+                      end_position:
+                        bytes: 109
+                        line: 4
+                        character: 35
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 109
+              line: 5
+              character: 1
+            end_position:
+              bytes: 114
+              line: 5
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 114
+                line: 5
+                character: 6
+              end_position:
+                bytes: 115
+                line: 5
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 115
+                    line: 5
+                    character: 7
+                  end_position:
+                    bytes: 119
+                    line: 5
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: num5
+                trailing_trivia:
+                  - start_position:
+                      bytes: 119
+                      line: 5
+                      character: 11
+                    end_position:
+                      bytes: 120
+                      line: 5
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 120
+              line: 5
+              character: 12
+            end_position:
+              bytes: 121
+              line: 5
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 121
+                line: 5
+                character: 13
+              end_position:
+                bytes: 122
+                line: 5
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 122
+                      line: 5
+                      character: 14
+                    end_position:
+                      bytes: 131
+                      line: 5
+                      character: 23
+                    token_type:
+                      type: Number
+                      text: 1e512_412
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 131
+                        line: 5
+                        character: 23
+                      end_position:
+                        bytes: 132
+                        line: 5
+                        character: 23
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 132
+              line: 6
+              character: 1
+            end_position:
+              bytes: 137
+              line: 6
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 137
+                line: 6
+                character: 6
+              end_position:
+                bytes: 138
+                line: 6
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 138
+                    line: 6
+                    character: 7
+                  end_position:
+                    bytes: 142
+                    line: 6
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: num6
+                trailing_trivia:
+                  - start_position:
+                      bytes: 142
+                      line: 6
+                      character: 11
+                    end_position:
+                      bytes: 143
+                      line: 6
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 143
+              line: 6
+              character: 12
+            end_position:
+              bytes: 144
+              line: 6
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 144
+                line: 6
+                character: 13
+              end_position:
+                bytes: 145
+                line: 6
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 145
+                      line: 6
+                      character: 14
+                    end_position:
+                      bytes: 155
+                      line: 6
+                      character: 24
+                    token_type:
+                      type: Number
+                      text: 1e-512_412
+                  trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/decimal_seperators/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/decimal_seperators/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..b1bcb502862df1484d6f5f0894b19273cf9c93d5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/decimal_seperators/source.lua
@@ -0,0 +1,6 @@
+local num1 = 1_048_576
+local num2 = 0xFFFF_FFFF
+local num3 = 0b_0101_0101
+local num4 = 1_523_423.132_452_312
+local num5 = 1e512_412
+local num6 = 1e-512_412
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/decimal_seperators/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/decimal_seperators/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..83883aabaaef46ff48b1b147ccb612ebafc7cb7e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/decimal_seperators/tokens.snap
@@ -0,0 +1,534 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/roblox_cases/pass/decimal_seperators
+
+---
+- 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: 10
+    line: 1
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num1
+- 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: 22
+    line: 1
+    character: 23
+  token_type:
+    type: Number
+    text: 1_048_576
+- start_position:
+    bytes: 22
+    line: 1
+    character: 23
+  end_position:
+    bytes: 23
+    line: 1
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 23
+    line: 2
+    character: 1
+  end_position:
+    bytes: 28
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 28
+    line: 2
+    character: 6
+  end_position:
+    bytes: 29
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 29
+    line: 2
+    character: 7
+  end_position:
+    bytes: 33
+    line: 2
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num2
+- start_position:
+    bytes: 33
+    line: 2
+    character: 11
+  end_position:
+    bytes: 34
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 34
+    line: 2
+    character: 12
+  end_position:
+    bytes: 35
+    line: 2
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 35
+    line: 2
+    character: 13
+  end_position:
+    bytes: 36
+    line: 2
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 36
+    line: 2
+    character: 14
+  end_position:
+    bytes: 47
+    line: 2
+    character: 25
+  token_type:
+    type: Number
+    text: "0xFFFF_FFFF"
+- start_position:
+    bytes: 47
+    line: 2
+    character: 25
+  end_position:
+    bytes: 48
+    line: 2
+    character: 25
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 48
+    line: 3
+    character: 1
+  end_position:
+    bytes: 53
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 53
+    line: 3
+    character: 6
+  end_position:
+    bytes: 54
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 54
+    line: 3
+    character: 7
+  end_position:
+    bytes: 58
+    line: 3
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num3
+- start_position:
+    bytes: 58
+    line: 3
+    character: 11
+  end_position:
+    bytes: 59
+    line: 3
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 59
+    line: 3
+    character: 12
+  end_position:
+    bytes: 60
+    line: 3
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 60
+    line: 3
+    character: 13
+  end_position:
+    bytes: 61
+    line: 3
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 61
+    line: 3
+    character: 14
+  end_position:
+    bytes: 73
+    line: 3
+    character: 26
+  token_type:
+    type: Number
+    text: 0b_0101_0101
+- start_position:
+    bytes: 73
+    line: 3
+    character: 26
+  end_position:
+    bytes: 74
+    line: 3
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 74
+    line: 4
+    character: 1
+  end_position:
+    bytes: 79
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 79
+    line: 4
+    character: 6
+  end_position:
+    bytes: 80
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 80
+    line: 4
+    character: 7
+  end_position:
+    bytes: 84
+    line: 4
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num4
+- start_position:
+    bytes: 84
+    line: 4
+    character: 11
+  end_position:
+    bytes: 85
+    line: 4
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 85
+    line: 4
+    character: 12
+  end_position:
+    bytes: 86
+    line: 4
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 86
+    line: 4
+    character: 13
+  end_position:
+    bytes: 87
+    line: 4
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 87
+    line: 4
+    character: 14
+  end_position:
+    bytes: 108
+    line: 4
+    character: 35
+  token_type:
+    type: Number
+    text: 1_523_423.132_452_312
+- start_position:
+    bytes: 108
+    line: 4
+    character: 35
+  end_position:
+    bytes: 109
+    line: 4
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 109
+    line: 5
+    character: 1
+  end_position:
+    bytes: 114
+    line: 5
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 114
+    line: 5
+    character: 6
+  end_position:
+    bytes: 115
+    line: 5
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 115
+    line: 5
+    character: 7
+  end_position:
+    bytes: 119
+    line: 5
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num5
+- start_position:
+    bytes: 119
+    line: 5
+    character: 11
+  end_position:
+    bytes: 120
+    line: 5
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 120
+    line: 5
+    character: 12
+  end_position:
+    bytes: 121
+    line: 5
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 121
+    line: 5
+    character: 13
+  end_position:
+    bytes: 122
+    line: 5
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 122
+    line: 5
+    character: 14
+  end_position:
+    bytes: 131
+    line: 5
+    character: 23
+  token_type:
+    type: Number
+    text: 1e512_412
+- start_position:
+    bytes: 131
+    line: 5
+    character: 23
+  end_position:
+    bytes: 132
+    line: 5
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 132
+    line: 6
+    character: 1
+  end_position:
+    bytes: 137
+    line: 6
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 137
+    line: 6
+    character: 6
+  end_position:
+    bytes: 138
+    line: 6
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 138
+    line: 6
+    character: 7
+  end_position:
+    bytes: 142
+    line: 6
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: num6
+- start_position:
+    bytes: 142
+    line: 6
+    character: 11
+  end_position:
+    bytes: 143
+    line: 6
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 143
+    line: 6
+    character: 12
+  end_position:
+    bytes: 144
+    line: 6
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 144
+    line: 6
+    character: 13
+  end_position:
+    bytes: 145
+    line: 6
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 145
+    line: 6
+    character: 14
+  end_position:
+    bytes: 155
+    line: 6
+    character: 24
+  token_type:
+    type: Number
+    text: 1e-512_412
+- start_position:
+    bytes: 155
+    line: 6
+    character: 24
+  end_position:
+    bytes: 155
+    line: 6
+    character: 24
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/floor_division/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/floor_division/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..31e67c65e8ff497c99f426f243cddb1042ffd1bb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/floor_division/ast.snap
@@ -0,0 +1,173 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: 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:
+                BinaryOperator:
+                  lhs:
+                    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:
+                        - start_position:
+                            bytes: 11
+                            line: 1
+                            character: 12
+                          end_position:
+                            bytes: 12
+                            line: 1
+                            character: 13
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  binop:
+                    DoubleSlash:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 12
+                          line: 1
+                          character: 13
+                        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: " "
+                  rhs:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 15
+                          line: 1
+                          character: 16
+                        end_position:
+                          bytes: 16
+                          line: 1
+                          character: 17
+                        token_type:
+                          type: Number
+                          text: "2"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 16
+                            line: 1
+                            character: 17
+                          end_position:
+                            bytes: 17
+                            line: 1
+                            character: 17
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/floor_division/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/floor_division/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8460eebbd5fe3f6ff2601a8e1816b07c66a6883d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/floor_division/source.lua
@@ -0,0 +1 @@
+local x = 1 // 2
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/floor_division/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/floor_division/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ec02630070d8d51c202b94d8374980b6ba22f09f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/floor_division/tokens.snap
@@ -0,0 +1,147 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- 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: Number
+    text: "1"
+- 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: 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 16
+    line: 1
+    character: 17
+  end_position:
+    bytes: 17
+    line: 1
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 17
+    line: 2
+    character: 1
+  end_position:
+    bytes: 17
+    line: 2
+    character: 1
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/if_expression/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/if_expression/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..37110dd7688286f6c24e2074d862de18a32c931f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/if_expression/ast.snap
@@ -0,0 +1,3198 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/roblox_cases/pass/if_expression
+---
+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:
+                IfExpression:
+                  if_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: if
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 12
+                          line: 1
+                          character: 13
+                        end_position:
+                          bytes: 13
+                          line: 1
+                          character: 14
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  condition:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 13
+                            line: 1
+                            character: 14
+                          end_position:
+                            bytes: 16
+                            line: 1
+                            character: 17
+                          token_type:
+                            type: Identifier
+                            identifier: foo
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 16
+                              line: 1
+                              character: 17
+                            end_position:
+                              bytes: 17
+                              line: 1
+                              character: 18
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  then_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 17
+                        line: 1
+                        character: 18
+                      end_position:
+                        bytes: 21
+                        line: 1
+                        character: 22
+                      token_type:
+                        type: Symbol
+                        symbol: then
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 21
+                          line: 1
+                          character: 22
+                        end_position:
+                          bytes: 22
+                          line: 1
+                          character: 23
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  if_expression:
+                    Var:
+                      Expression:
+                        prefix:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 22
+                                line: 1
+                                character: 23
+                              end_position:
+                                bytes: 25
+                                line: 1
+                                character: 26
+                              token_type:
+                                type: Identifier
+                                identifier: foo
+                            trailing_trivia: []
+                        suffixes:
+                          - Index:
+                              Dot:
+                                dot:
+                                  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: []
+                                name:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 26
+                                      line: 1
+                                      character: 27
+                                    end_position:
+                                      bytes: 27
+                                      line: 1
+                                      character: 28
+                                    token_type:
+                                      type: Identifier
+                                      identifier: x
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 27
+                                        line: 1
+                                        character: 28
+                                      end_position:
+                                        bytes: 28
+                                        line: 1
+                                        character: 29
+                                      token_type:
+                                        type: Whitespace
+                                        characters: " "
+                  else_if_expressions: ~
+                  else_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 28
+                        line: 1
+                        character: 29
+                      end_position:
+                        bytes: 32
+                        line: 1
+                        character: 33
+                      token_type:
+                        type: Symbol
+                        symbol: else
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 32
+                          line: 1
+                          character: 33
+                        end_position:
+                          bytes: 33
+                          line: 1
+                          character: 34
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  else_expression:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 33
+                          line: 1
+                          character: 34
+                        end_position:
+                          bytes: 34
+                          line: 1
+                          character: 35
+                        token_type:
+                          type: Number
+                          text: "5"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 34
+                            line: 1
+                            character: 35
+                          end_position:
+                            bytes: 35
+                            line: 1
+                            character: 35
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 35
+              line: 2
+              character: 1
+            end_position:
+              bytes: 40
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 40
+                line: 2
+                character: 6
+              end_position:
+                bytes: 41
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 41
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 42
+                    line: 2
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: y
+                trailing_trivia:
+                  - start_position:
+                      bytes: 42
+                      line: 2
+                      character: 8
+                    end_position:
+                      bytes: 43
+                      line: 2
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 43
+              line: 2
+              character: 9
+            end_position:
+              bytes: 44
+              line: 2
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 44
+                line: 2
+                character: 10
+              end_position:
+                bytes: 45
+                line: 2
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                FunctionCall:
+                  prefix:
+                    Expression:
+                      Parentheses:
+                        contained:
+                          tokens:
+                            - leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 45
+                                  line: 2
+                                  character: 11
+                                end_position:
+                                  bytes: 46
+                                  line: 2
+                                  character: 12
+                                token_type:
+                                  type: Symbol
+                                  symbol: (
+                              trailing_trivia: []
+                            - leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 79
+                                  line: 2
+                                  character: 45
+                                end_position:
+                                  bytes: 80
+                                  line: 2
+                                  character: 46
+                                token_type:
+                                  type: Symbol
+                                  symbol: )
+                              trailing_trivia: []
+                        expression:
+                          IfExpression:
+                            if_token:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 46
+                                  line: 2
+                                  character: 12
+                                end_position:
+                                  bytes: 48
+                                  line: 2
+                                  character: 14
+                                token_type:
+                                  type: Symbol
+                                  symbol: if
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 48
+                                    line: 2
+                                    character: 14
+                                  end_position:
+                                    bytes: 49
+                                    line: 2
+                                    character: 15
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            condition:
+                              Var:
+                                Name:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 49
+                                      line: 2
+                                      character: 15
+                                    end_position:
+                                      bytes: 50
+                                      line: 2
+                                      character: 16
+                                    token_type:
+                                      type: Identifier
+                                      identifier: x
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 50
+                                        line: 2
+                                        character: 16
+                                      end_position:
+                                        bytes: 51
+                                        line: 2
+                                        character: 17
+                                      token_type:
+                                        type: Whitespace
+                                        characters: " "
+                            then_token:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 51
+                                  line: 2
+                                  character: 17
+                                end_position:
+                                  bytes: 55
+                                  line: 2
+                                  character: 21
+                                token_type:
+                                  type: Symbol
+                                  symbol: then
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 55
+                                    line: 2
+                                    character: 21
+                                  end_position:
+                                    bytes: 56
+                                    line: 2
+                                    character: 22
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            if_expression:
+                              Var:
+                                Expression:
+                                  prefix:
+                                    Name:
+                                      leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 56
+                                          line: 2
+                                          character: 22
+                                        end_position:
+                                          bytes: 57
+                                          line: 2
+                                          character: 23
+                                        token_type:
+                                          type: Identifier
+                                          identifier: x
+                                      trailing_trivia: []
+                                  suffixes:
+                                    - Index:
+                                        Dot:
+                                          dot:
+                                            leading_trivia: []
+                                            token:
+                                              start_position:
+                                                bytes: 57
+                                                line: 2
+                                                character: 23
+                                              end_position:
+                                                bytes: 58
+                                                line: 2
+                                                character: 24
+                                              token_type:
+                                                type: Symbol
+                                                symbol: "."
+                                            trailing_trivia: []
+                                          name:
+                                            leading_trivia: []
+                                            token:
+                                              start_position:
+                                                bytes: 58
+                                                line: 2
+                                                character: 24
+                                              end_position:
+                                                bytes: 65
+                                                line: 2
+                                                character: 31
+                                              token_type:
+                                                type: Identifier
+                                                identifier: indices
+                                            trailing_trivia:
+                                              - start_position:
+                                                  bytes: 65
+                                                  line: 2
+                                                  character: 31
+                                                end_position:
+                                                  bytes: 66
+                                                  line: 2
+                                                  character: 32
+                                                token_type:
+                                                  type: Whitespace
+                                                  characters: " "
+                            else_if_expressions: ~
+                            else_token:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 66
+                                  line: 2
+                                  character: 32
+                                end_position:
+                                  bytes: 70
+                                  line: 2
+                                  character: 36
+                                token_type:
+                                  type: Symbol
+                                  symbol: else
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 70
+                                    line: 2
+                                    character: 36
+                                  end_position:
+                                    bytes: 71
+                                    line: 2
+                                    character: 37
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            else_expression:
+                              FunctionCall:
+                                prefix:
+                                  Name:
+                                    leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 71
+                                        line: 2
+                                        character: 37
+                                      end_position:
+                                        bytes: 77
+                                        line: 2
+                                        character: 43
+                                      token_type:
+                                        type: Identifier
+                                        identifier: create
+                                    trailing_trivia: []
+                                suffixes:
+                                  - Call:
+                                      AnonymousCall:
+                                        Parentheses:
+                                          parentheses:
+                                            tokens:
+                                              - leading_trivia: []
+                                                token:
+                                                  start_position:
+                                                    bytes: 77
+                                                    line: 2
+                                                    character: 43
+                                                  end_position:
+                                                    bytes: 78
+                                                    line: 2
+                                                    character: 44
+                                                  token_type:
+                                                    type: Symbol
+                                                    symbol: (
+                                                trailing_trivia: []
+                                              - leading_trivia: []
+                                                token:
+                                                  start_position:
+                                                    bytes: 78
+                                                    line: 2
+                                                    character: 44
+                                                  end_position:
+                                                    bytes: 79
+                                                    line: 2
+                                                    character: 45
+                                                  token_type:
+                                                    type: Symbol
+                                                    symbol: )
+                                                trailing_trivia: []
+                                          arguments:
+                                            pairs: []
+                  suffixes:
+                    - Call:
+                        MethodCall:
+                          colon_token:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 80
+                                line: 2
+                                character: 46
+                              end_position:
+                                bytes: 81
+                                line: 2
+                                character: 47
+                              token_type:
+                                type: Symbol
+                                symbol: ":"
+                            trailing_trivia: []
+                          name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 81
+                                line: 2
+                                character: 47
+                              end_position:
+                                bytes: 87
+                                line: 2
+                                character: 53
+                              token_type:
+                                type: Identifier
+                                identifier: update
+                            trailing_trivia: []
+                          args:
+                            Parentheses:
+                              parentheses:
+                                tokens:
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 87
+                                        line: 2
+                                        character: 53
+                                      end_position:
+                                        bytes: 88
+                                        line: 2
+                                        character: 54
+                                      token_type:
+                                        type: Symbol
+                                        symbol: (
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 134
+                                        line: 2
+                                        character: 100
+                                      end_position:
+                                        bytes: 135
+                                        line: 2
+                                        character: 101
+                                      token_type:
+                                        type: Symbol
+                                        symbol: )
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 135
+                                          line: 2
+                                          character: 101
+                                        end_position:
+                                          bytes: 136
+                                          line: 2
+                                          character: 101
+                                        token_type:
+                                          type: Whitespace
+                                          characters: "\n"
+                              arguments:
+                                pairs:
+                                  - End:
+                                      IfExpression:
+                                        if_token:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 88
+                                              line: 2
+                                              character: 54
+                                            end_position:
+                                              bytes: 90
+                                              line: 2
+                                              character: 56
+                                            token_type:
+                                              type: Symbol
+                                              symbol: if
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 90
+                                                line: 2
+                                                character: 56
+                                              end_position:
+                                                bytes: 91
+                                                line: 2
+                                                character: 57
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+                                        condition:
+                                          Var:
+                                            Name:
+                                              leading_trivia: []
+                                              token:
+                                                start_position:
+                                                  bytes: 91
+                                                  line: 2
+                                                  character: 57
+                                                end_position:
+                                                  bytes: 103
+                                                  line: 2
+                                                  character: 69
+                                                token_type:
+                                                  type: Identifier
+                                                  identifier: shouldUpdate
+                                              trailing_trivia:
+                                                - start_position:
+                                                    bytes: 103
+                                                    line: 2
+                                                    character: 69
+                                                  end_position:
+                                                    bytes: 104
+                                                    line: 2
+                                                    character: 70
+                                                  token_type:
+                                                    type: Whitespace
+                                                    characters: " "
+                                        then_token:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 104
+                                              line: 2
+                                              character: 70
+                                            end_position:
+                                              bytes: 108
+                                              line: 2
+                                              character: 74
+                                            token_type:
+                                              type: Symbol
+                                              symbol: then
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 108
+                                                line: 2
+                                                character: 74
+                                              end_position:
+                                                bytes: 109
+                                                line: 2
+                                                character: 75
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+                                        if_expression:
+                                          Var:
+                                            Name:
+                                              leading_trivia: []
+                                              token:
+                                                start_position:
+                                                  bytes: 109
+                                                  line: 2
+                                                  character: 75
+                                                end_position:
+                                                  bytes: 120
+                                                  line: 2
+                                                  character: 86
+                                                token_type:
+                                                  type: Identifier
+                                                  identifier: information
+                                              trailing_trivia:
+                                                - start_position:
+                                                    bytes: 120
+                                                    line: 2
+                                                    character: 86
+                                                  end_position:
+                                                    bytes: 121
+                                                    line: 2
+                                                    character: 87
+                                                  token_type:
+                                                    type: Whitespace
+                                                    characters: " "
+                                        else_if_expressions: ~
+                                        else_token:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 121
+                                              line: 2
+                                              character: 87
+                                            end_position:
+                                              bytes: 125
+                                              line: 2
+                                              character: 91
+                                            token_type:
+                                              type: Symbol
+                                              symbol: else
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 125
+                                                line: 2
+                                                character: 91
+                                              end_position:
+                                                bytes: 126
+                                                line: 2
+                                                character: 92
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+                                        else_expression:
+                                          Var:
+                                            Name:
+                                              leading_trivia: []
+                                              token:
+                                                start_position:
+                                                  bytes: 126
+                                                  line: 2
+                                                  character: 92
+                                                end_position:
+                                                  bytes: 134
+                                                  line: 2
+                                                  character: 100
+                                                token_type:
+                                                  type: Identifier
+                                                  identifier: defaults
+                                              trailing_trivia: []
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 136
+              line: 3
+              character: 1
+            end_position:
+              bytes: 141
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 141
+                line: 3
+                character: 6
+              end_position:
+                bytes: 142
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 142
+                    line: 3
+                    character: 7
+                  end_position:
+                    bytes: 143
+                    line: 3
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: z
+                trailing_trivia:
+                  - start_position:
+                      bytes: 143
+                      line: 3
+                      character: 8
+                    end_position:
+                      bytes: 144
+                      line: 3
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 144
+              line: 3
+              character: 9
+            end_position:
+              bytes: 145
+              line: 3
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 145
+                line: 3
+                character: 10
+              end_position:
+                bytes: 146
+                line: 3
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                TypeAssertion:
+                  expression:
+                    Parentheses:
+                      contained:
+                        tokens:
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 146
+                                line: 3
+                                character: 11
+                              end_position:
+                                bytes: 147
+                                line: 3
+                                character: 12
+                              token_type:
+                                type: Symbol
+                                symbol: (
+                            trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 171
+                                line: 3
+                                character: 36
+                              end_position:
+                                bytes: 172
+                                line: 3
+                                character: 37
+                              token_type:
+                                type: Symbol
+                                symbol: )
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 172
+                                  line: 3
+                                  character: 37
+                                end_position:
+                                  bytes: 173
+                                  line: 3
+                                  character: 38
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      expression:
+                        IfExpression:
+                          if_token:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 147
+                                line: 3
+                                character: 12
+                              end_position:
+                                bytes: 149
+                                line: 3
+                                character: 14
+                              token_type:
+                                type: Symbol
+                                symbol: if
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 149
+                                  line: 3
+                                  character: 14
+                                end_position:
+                                  bytes: 150
+                                  line: 3
+                                  character: 15
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                          condition:
+                            Var:
+                              Name:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 150
+                                    line: 3
+                                    character: 15
+                                  end_position:
+                                    bytes: 153
+                                    line: 3
+                                    character: 18
+                                  token_type:
+                                    type: Identifier
+                                    identifier: bar
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 153
+                                      line: 3
+                                      character: 18
+                                    end_position:
+                                      bytes: 154
+                                      line: 3
+                                      character: 19
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                          then_token:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 154
+                                line: 3
+                                character: 19
+                              end_position:
+                                bytes: 158
+                                line: 3
+                                character: 23
+                              token_type:
+                                type: Symbol
+                                symbol: then
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 158
+                                  line: 3
+                                  character: 23
+                                end_position:
+                                  bytes: 159
+                                  line: 3
+                                  character: 24
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                          if_expression:
+                            Var:
+                              Expression:
+                                prefix:
+                                  Name:
+                                    leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 159
+                                        line: 3
+                                        character: 24
+                                      end_position:
+                                        bytes: 162
+                                        line: 3
+                                        character: 27
+                                      token_type:
+                                        type: Identifier
+                                        identifier: foo
+                                    trailing_trivia: []
+                                suffixes:
+                                  - Index:
+                                      Dot:
+                                        dot:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 162
+                                              line: 3
+                                              character: 27
+                                            end_position:
+                                              bytes: 163
+                                              line: 3
+                                              character: 28
+                                            token_type:
+                                              type: Symbol
+                                              symbol: "."
+                                          trailing_trivia: []
+                                        name:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 163
+                                              line: 3
+                                              character: 28
+                                            end_position:
+                                              bytes: 164
+                                              line: 3
+                                              character: 29
+                                            token_type:
+                                              type: Identifier
+                                              identifier: y
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 164
+                                                line: 3
+                                                character: 29
+                                              end_position:
+                                                bytes: 165
+                                                line: 3
+                                                character: 30
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+                          else_if_expressions: ~
+                          else_token:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 165
+                                line: 3
+                                character: 30
+                              end_position:
+                                bytes: 169
+                                line: 3
+                                character: 34
+                              token_type:
+                                type: Symbol
+                                symbol: else
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 169
+                                  line: 3
+                                  character: 34
+                                end_position:
+                                  bytes: 170
+                                  line: 3
+                                  character: 35
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                          else_expression:
+                            Number:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 170
+                                  line: 3
+                                  character: 35
+                                end_position:
+                                  bytes: 171
+                                  line: 3
+                                  character: 36
+                                token_type:
+                                  type: Number
+                                  text: "5"
+                              trailing_trivia: []
+                  type_assertion:
+                    assertion_op:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 173
+                          line: 3
+                          character: 38
+                        end_position:
+                          bytes: 175
+                          line: 3
+                          character: 40
+                        token_type:
+                          type: Symbol
+                          symbol: "::"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 175
+                            line: 3
+                            character: 40
+                          end_position:
+                            bytes: 176
+                            line: 3
+                            character: 41
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                    cast_to:
+                      Basic:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 176
+                            line: 3
+                            character: 41
+                          end_position:
+                            bytes: 182
+                            line: 3
+                            character: 47
+                          token_type:
+                            type: Identifier
+                            identifier: number
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 182
+                              line: 3
+                              character: 47
+                            end_position:
+                              bytes: 183
+                              line: 3
+                              character: 47
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 183
+                line: 4
+                character: 1
+              end_position:
+                bytes: 184
+                line: 4
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 184
+              line: 5
+              character: 1
+            end_position:
+              bytes: 189
+              line: 5
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 189
+                line: 5
+                character: 6
+              end_position:
+                bytes: 190
+                line: 5
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 190
+                    line: 5
+                    character: 7
+                  end_position:
+                    bytes: 191
+                    line: 5
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: a
+                trailing_trivia:
+                  - start_position:
+                      bytes: 191
+                      line: 5
+                      character: 8
+                    end_position:
+                      bytes: 192
+                      line: 5
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 192
+              line: 5
+              character: 9
+            end_position:
+              bytes: 193
+              line: 5
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 193
+                line: 5
+                character: 10
+              end_position:
+                bytes: 194
+                line: 5
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                IfExpression:
+                  if_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 194
+                        line: 5
+                        character: 11
+                      end_position:
+                        bytes: 196
+                        line: 5
+                        character: 13
+                      token_type:
+                        type: Symbol
+                        symbol: if
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 196
+                          line: 5
+                          character: 13
+                        end_position:
+                          bytes: 197
+                          line: 5
+                          character: 14
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  condition:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 197
+                            line: 5
+                            character: 14
+                          end_position:
+                            bytes: 200
+                            line: 5
+                            character: 17
+                          token_type:
+                            type: Identifier
+                            identifier: foo
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 200
+                              line: 5
+                              character: 17
+                            end_position:
+                              bytes: 201
+                              line: 5
+                              character: 18
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  then_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 201
+                        line: 5
+                        character: 18
+                      end_position:
+                        bytes: 205
+                        line: 5
+                        character: 22
+                      token_type:
+                        type: Symbol
+                        symbol: then
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 205
+                          line: 5
+                          character: 22
+                        end_position:
+                          bytes: 206
+                          line: 5
+                          character: 23
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  if_expression:
+                    Var:
+                      Expression:
+                        prefix:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 206
+                                line: 5
+                                character: 23
+                              end_position:
+                                bytes: 209
+                                line: 5
+                                character: 26
+                              token_type:
+                                type: Identifier
+                                identifier: foo
+                            trailing_trivia: []
+                        suffixes:
+                          - Index:
+                              Dot:
+                                dot:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 209
+                                      line: 5
+                                      character: 26
+                                    end_position:
+                                      bytes: 210
+                                      line: 5
+                                      character: 27
+                                    token_type:
+                                      type: Symbol
+                                      symbol: "."
+                                  trailing_trivia: []
+                                name:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 210
+                                      line: 5
+                                      character: 27
+                                    end_position:
+                                      bytes: 211
+                                      line: 5
+                                      character: 28
+                                    token_type:
+                                      type: Identifier
+                                      identifier: x
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 211
+                                        line: 5
+                                        character: 28
+                                      end_position:
+                                        bytes: 212
+                                        line: 5
+                                        character: 29
+                                      token_type:
+                                        type: Whitespace
+                                        characters: " "
+                  else_if_expressions:
+                    - else_if_token:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 212
+                            line: 5
+                            character: 29
+                          end_position:
+                            bytes: 218
+                            line: 5
+                            character: 35
+                          token_type:
+                            type: Symbol
+                            symbol: elseif
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 218
+                              line: 5
+                              character: 35
+                            end_position:
+                              bytes: 219
+                              line: 5
+                              character: 36
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      condition:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 219
+                                line: 5
+                                character: 36
+                              end_position:
+                                bytes: 222
+                                line: 5
+                                character: 39
+                              token_type:
+                                type: Identifier
+                                identifier: bar
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 222
+                                  line: 5
+                                  character: 39
+                                end_position:
+                                  bytes: 223
+                                  line: 5
+                                  character: 40
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      then_token:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 223
+                            line: 5
+                            character: 40
+                          end_position:
+                            bytes: 227
+                            line: 5
+                            character: 44
+                          token_type:
+                            type: Symbol
+                            symbol: then
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 227
+                              line: 5
+                              character: 44
+                            end_position:
+                              bytes: 228
+                              line: 5
+                              character: 45
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      expression:
+                        Var:
+                          Expression:
+                            prefix:
+                              Name:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 228
+                                    line: 5
+                                    character: 45
+                                  end_position:
+                                    bytes: 231
+                                    line: 5
+                                    character: 48
+                                  token_type:
+                                    type: Identifier
+                                    identifier: bar
+                                trailing_trivia: []
+                            suffixes:
+                              - Index:
+                                  Dot:
+                                    dot:
+                                      leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 231
+                                          line: 5
+                                          character: 48
+                                        end_position:
+                                          bytes: 232
+                                          line: 5
+                                          character: 49
+                                        token_type:
+                                          type: Symbol
+                                          symbol: "."
+                                      trailing_trivia: []
+                                    name:
+                                      leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 232
+                                          line: 5
+                                          character: 49
+                                        end_position:
+                                          bytes: 233
+                                          line: 5
+                                          character: 50
+                                        token_type:
+                                          type: Identifier
+                                          identifier: x
+                                      trailing_trivia:
+                                        - start_position:
+                                            bytes: 233
+                                            line: 5
+                                            character: 50
+                                          end_position:
+                                            bytes: 234
+                                            line: 5
+                                            character: 51
+                                          token_type:
+                                            type: Whitespace
+                                            characters: " "
+                  else_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 234
+                        line: 5
+                        character: 51
+                      end_position:
+                        bytes: 238
+                        line: 5
+                        character: 55
+                      token_type:
+                        type: Symbol
+                        symbol: else
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 238
+                          line: 5
+                          character: 55
+                        end_position:
+                          bytes: 239
+                          line: 5
+                          character: 56
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  else_expression:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 239
+                          line: 5
+                          character: 56
+                        end_position:
+                          bytes: 240
+                          line: 5
+                          character: 57
+                        token_type:
+                          type: Number
+                          text: "5"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 240
+                            line: 5
+                            character: 57
+                          end_position:
+                            bytes: 241
+                            line: 5
+                            character: 57
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 241
+              line: 6
+              character: 1
+            end_position:
+              bytes: 246
+              line: 6
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 246
+                line: 6
+                character: 6
+              end_position:
+                bytes: 247
+                line: 6
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 247
+                    line: 6
+                    character: 7
+                  end_position:
+                    bytes: 248
+                    line: 6
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: b
+                trailing_trivia:
+                  - start_position:
+                      bytes: 248
+                      line: 6
+                      character: 8
+                    end_position:
+                      bytes: 249
+                      line: 6
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 249
+              line: 6
+              character: 9
+            end_position:
+              bytes: 250
+              line: 6
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 250
+                line: 6
+                character: 10
+              end_position:
+                bytes: 251
+                line: 6
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                IfExpression:
+                  if_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 251
+                        line: 6
+                        character: 11
+                      end_position:
+                        bytes: 253
+                        line: 6
+                        character: 13
+                      token_type:
+                        type: Symbol
+                        symbol: if
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 253
+                          line: 6
+                          character: 13
+                        end_position:
+                          bytes: 254
+                          line: 6
+                          character: 14
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  condition:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 254
+                            line: 6
+                            character: 14
+                          end_position:
+                            bytes: 257
+                            line: 6
+                            character: 17
+                          token_type:
+                            type: Identifier
+                            identifier: foo
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 257
+                              line: 6
+                              character: 17
+                            end_position:
+                              bytes: 258
+                              line: 6
+                              character: 18
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  then_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 258
+                        line: 6
+                        character: 18
+                      end_position:
+                        bytes: 262
+                        line: 6
+                        character: 22
+                      token_type:
+                        type: Symbol
+                        symbol: then
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 262
+                          line: 6
+                          character: 22
+                        end_position:
+                          bytes: 263
+                          line: 6
+                          character: 23
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  if_expression:
+                    IfExpression:
+                      if_token:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 263
+                            line: 6
+                            character: 23
+                          end_position:
+                            bytes: 265
+                            line: 6
+                            character: 25
+                          token_type:
+                            type: Symbol
+                            symbol: if
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 265
+                              line: 6
+                              character: 25
+                            end_position:
+                              bytes: 266
+                              line: 6
+                              character: 26
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      condition:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 266
+                                line: 6
+                                character: 26
+                              end_position:
+                                bytes: 269
+                                line: 6
+                                character: 29
+                              token_type:
+                                type: Identifier
+                                identifier: bar
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 269
+                                  line: 6
+                                  character: 29
+                                end_position:
+                                  bytes: 270
+                                  line: 6
+                                  character: 30
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      then_token:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 270
+                            line: 6
+                            character: 30
+                          end_position:
+                            bytes: 274
+                            line: 6
+                            character: 34
+                          token_type:
+                            type: Symbol
+                            symbol: then
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 274
+                              line: 6
+                              character: 34
+                            end_position:
+                              bytes: 275
+                              line: 6
+                              character: 35
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      if_expression:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 275
+                                line: 6
+                                character: 35
+                              end_position:
+                                bytes: 278
+                                line: 6
+                                character: 38
+                              token_type:
+                                type: Identifier
+                                identifier: bar
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 278
+                                  line: 6
+                                  character: 38
+                                end_position:
+                                  bytes: 279
+                                  line: 6
+                                  character: 39
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      else_if_expressions: ~
+                      else_token:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 279
+                            line: 6
+                            character: 39
+                          end_position:
+                            bytes: 283
+                            line: 6
+                            character: 43
+                          token_type:
+                            type: Symbol
+                            symbol: else
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 283
+                              line: 6
+                              character: 43
+                            end_position:
+                              bytes: 284
+                              line: 6
+                              character: 44
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      else_expression:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 284
+                                line: 6
+                                character: 44
+                              end_position:
+                                bytes: 287
+                                line: 6
+                                character: 47
+                              token_type:
+                                type: Identifier
+                                identifier: foo
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 287
+                                  line: 6
+                                  character: 47
+                                end_position:
+                                  bytes: 288
+                                  line: 6
+                                  character: 48
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                  else_if_expressions: ~
+                  else_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 288
+                        line: 6
+                        character: 48
+                      end_position:
+                        bytes: 292
+                        line: 6
+                        character: 52
+                      token_type:
+                        type: Symbol
+                        symbol: else
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 292
+                          line: 6
+                          character: 52
+                        end_position:
+                          bytes: 293
+                          line: 6
+                          character: 53
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  else_expression:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 293
+                          line: 6
+                          character: 53
+                        end_position:
+                          bytes: 294
+                          line: 6
+                          character: 54
+                        token_type:
+                          type: Number
+                          text: "5"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 294
+                            line: 6
+                            character: 54
+                          end_position:
+                            bytes: 295
+                            line: 6
+                            character: 54
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 295
+              line: 7
+              character: 1
+            end_position:
+              bytes: 300
+              line: 7
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 300
+                line: 7
+                character: 6
+              end_position:
+                bytes: 301
+                line: 7
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 301
+                    line: 7
+                    character: 7
+                  end_position:
+                    bytes: 302
+                    line: 7
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: c
+                trailing_trivia:
+                  - start_position:
+                      bytes: 302
+                      line: 7
+                      character: 8
+                    end_position:
+                      bytes: 303
+                      line: 7
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 303
+              line: 7
+              character: 9
+            end_position:
+              bytes: 304
+              line: 7
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 304
+                line: 7
+                character: 10
+              end_position:
+                bytes: 305
+                line: 7
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                IfExpression:
+                  if_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 305
+                        line: 7
+                        character: 11
+                      end_position:
+                        bytes: 307
+                        line: 7
+                        character: 13
+                      token_type:
+                        type: Symbol
+                        symbol: if
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 307
+                          line: 7
+                          character: 13
+                        end_position:
+                          bytes: 308
+                          line: 7
+                          character: 14
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  condition:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 308
+                            line: 7
+                            character: 14
+                          end_position:
+                            bytes: 311
+                            line: 7
+                            character: 17
+                          token_type:
+                            type: Identifier
+                            identifier: foo
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 311
+                              line: 7
+                              character: 17
+                            end_position:
+                              bytes: 312
+                              line: 7
+                              character: 18
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  then_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 312
+                        line: 7
+                        character: 18
+                      end_position:
+                        bytes: 316
+                        line: 7
+                        character: 22
+                      token_type:
+                        type: Symbol
+                        symbol: then
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 316
+                          line: 7
+                          character: 22
+                        end_position:
+                          bytes: 317
+                          line: 7
+                          character: 23
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  if_expression:
+                    Parentheses:
+                      contained:
+                        tokens:
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 317
+                                line: 7
+                                character: 23
+                              end_position:
+                                bytes: 318
+                                line: 7
+                                character: 24
+                              token_type:
+                                type: Symbol
+                                symbol: (
+                            trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 333
+                                line: 7
+                                character: 39
+                              end_position:
+                                bytes: 334
+                                line: 7
+                                character: 40
+                              token_type:
+                                type: Symbol
+                                symbol: )
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 334
+                                  line: 7
+                                  character: 40
+                                end_position:
+                                  bytes: 335
+                                  line: 7
+                                  character: 41
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      expression:
+                        TypeAssertion:
+                          expression:
+                            Var:
+                              Expression:
+                                prefix:
+                                  Name:
+                                    leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 318
+                                        line: 7
+                                        character: 24
+                                      end_position:
+                                        bytes: 321
+                                        line: 7
+                                        character: 27
+                                      token_type:
+                                        type: Identifier
+                                        identifier: foo
+                                    trailing_trivia: []
+                                suffixes:
+                                  - Index:
+                                      Dot:
+                                        dot:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 321
+                                              line: 7
+                                              character: 27
+                                            end_position:
+                                              bytes: 322
+                                              line: 7
+                                              character: 28
+                                            token_type:
+                                              type: Symbol
+                                              symbol: "."
+                                          trailing_trivia: []
+                                        name:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 322
+                                              line: 7
+                                              character: 28
+                                            end_position:
+                                              bytes: 323
+                                              line: 7
+                                              character: 29
+                                            token_type:
+                                              type: Identifier
+                                              identifier: x
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 323
+                                                line: 7
+                                                character: 29
+                                              end_position:
+                                                bytes: 324
+                                                line: 7
+                                                character: 30
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+                          type_assertion:
+                            assertion_op:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 324
+                                  line: 7
+                                  character: 30
+                                end_position:
+                                  bytes: 326
+                                  line: 7
+                                  character: 32
+                                token_type:
+                                  type: Symbol
+                                  symbol: "::"
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 326
+                                    line: 7
+                                    character: 32
+                                  end_position:
+                                    bytes: 327
+                                    line: 7
+                                    character: 33
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            cast_to:
+                              Basic:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 327
+                                    line: 7
+                                    character: 33
+                                  end_position:
+                                    bytes: 333
+                                    line: 7
+                                    character: 39
+                                  token_type:
+                                    type: Identifier
+                                    identifier: number
+                                trailing_trivia: []
+                  else_if_expressions:
+                    - else_if_token:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 335
+                            line: 7
+                            character: 41
+                          end_position:
+                            bytes: 341
+                            line: 7
+                            character: 47
+                          token_type:
+                            type: Symbol
+                            symbol: elseif
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 341
+                              line: 7
+                              character: 47
+                            end_position:
+                              bytes: 342
+                              line: 7
+                              character: 48
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      condition:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 342
+                                line: 7
+                                character: 48
+                              end_position:
+                                bytes: 345
+                                line: 7
+                                character: 51
+                              token_type:
+                                type: Identifier
+                                identifier: bar
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 345
+                                  line: 7
+                                  character: 51
+                                end_position:
+                                  bytes: 346
+                                  line: 7
+                                  character: 52
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      then_token:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 346
+                            line: 7
+                            character: 52
+                          end_position:
+                            bytes: 350
+                            line: 7
+                            character: 56
+                          token_type:
+                            type: Symbol
+                            symbol: then
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 350
+                              line: 7
+                              character: 56
+                            end_position:
+                              bytes: 351
+                              line: 7
+                              character: 57
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      expression:
+                        FunctionCall:
+                          prefix:
+                            Name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 351
+                                  line: 7
+                                  character: 57
+                                end_position:
+                                  bytes: 354
+                                  line: 7
+                                  character: 60
+                                token_type:
+                                  type: Identifier
+                                  identifier: bar
+                              trailing_trivia: []
+                          suffixes:
+                            - Index:
+                                Dot:
+                                  dot:
+                                    leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 354
+                                        line: 7
+                                        character: 60
+                                      end_position:
+                                        bytes: 355
+                                        line: 7
+                                        character: 61
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "."
+                                    trailing_trivia: []
+                                  name:
+                                    leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 355
+                                        line: 7
+                                        character: 61
+                                      end_position:
+                                        bytes: 356
+                                        line: 7
+                                        character: 62
+                                      token_type:
+                                        type: Identifier
+                                        identifier: x
+                                    trailing_trivia: []
+                            - Call:
+                                AnonymousCall:
+                                  Parentheses:
+                                    parentheses:
+                                      tokens:
+                                        - leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 356
+                                              line: 7
+                                              character: 62
+                                            end_position:
+                                              bytes: 357
+                                              line: 7
+                                              character: 63
+                                            token_type:
+                                              type: Symbol
+                                              symbol: (
+                                          trailing_trivia: []
+                                        - leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 357
+                                              line: 7
+                                              character: 63
+                                            end_position:
+                                              bytes: 358
+                                              line: 7
+                                              character: 64
+                                            token_type:
+                                              type: Symbol
+                                              symbol: )
+                                          trailing_trivia: []
+                                    arguments:
+                                      pairs: []
+                            - Call:
+                                AnonymousCall:
+                                  Parentheses:
+                                    parentheses:
+                                      tokens:
+                                        - leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 358
+                                              line: 7
+                                              character: 64
+                                            end_position:
+                                              bytes: 359
+                                              line: 7
+                                              character: 65
+                                            token_type:
+                                              type: Symbol
+                                              symbol: (
+                                          trailing_trivia: []
+                                        - leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 359
+                                              line: 7
+                                              character: 65
+                                            end_position:
+                                              bytes: 360
+                                              line: 7
+                                              character: 66
+                                            token_type:
+                                              type: Symbol
+                                              symbol: )
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 360
+                                                line: 7
+                                                character: 66
+                                              end_position:
+                                                bytes: 361
+                                                line: 7
+                                                character: 67
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+                                    arguments:
+                                      pairs: []
+                  else_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 361
+                        line: 7
+                        character: 67
+                      end_position:
+                        bytes: 365
+                        line: 7
+                        character: 71
+                      token_type:
+                        type: Symbol
+                        symbol: else
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 365
+                          line: 7
+                          character: 71
+                        end_position:
+                          bytes: 366
+                          line: 7
+                          character: 72
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  else_expression:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 366
+                          line: 7
+                          character: 72
+                        end_position:
+                          bytes: 367
+                          line: 7
+                          character: 73
+                        token_type:
+                          type: Number
+                          text: "5"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 367
+                            line: 7
+                            character: 73
+                          end_position:
+                            bytes: 368
+                            line: 7
+                            character: 73
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 368
+              line: 8
+              character: 1
+            end_position:
+              bytes: 373
+              line: 8
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 373
+                line: 8
+                character: 6
+              end_position:
+                bytes: 374
+                line: 8
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 374
+                    line: 8
+                    character: 7
+                  end_position:
+                    bytes: 375
+                    line: 8
+                    character: 8
+                  token_type:
+                    type: Identifier
+                    identifier: d
+                trailing_trivia:
+                  - start_position:
+                      bytes: 375
+                      line: 8
+                      character: 8
+                    end_position:
+                      bytes: 376
+                      line: 8
+                      character: 9
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 376
+              line: 8
+              character: 9
+            end_position:
+              bytes: 377
+              line: 8
+              character: 10
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 377
+                line: 8
+                character: 10
+              end_position:
+                bytes: 378
+                line: 8
+                character: 11
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                IfExpression:
+                  if_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 378
+                        line: 8
+                        character: 11
+                      end_position:
+                        bytes: 380
+                        line: 8
+                        character: 13
+                      token_type:
+                        type: Symbol
+                        symbol: if
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 380
+                          line: 8
+                          character: 13
+                        end_position:
+                          bytes: 381
+                          line: 8
+                          character: 14
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  condition:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 381
+                            line: 8
+                            character: 14
+                          end_position:
+                            bytes: 384
+                            line: 8
+                            character: 17
+                          token_type:
+                            type: Identifier
+                            identifier: foo
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 384
+                              line: 8
+                              character: 17
+                            end_position:
+                              bytes: 385
+                              line: 8
+                              character: 18
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  then_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 385
+                        line: 8
+                        character: 18
+                      end_position:
+                        bytes: 389
+                        line: 8
+                        character: 22
+                      token_type:
+                        type: Symbol
+                        symbol: then
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 389
+                          line: 8
+                          character: 22
+                        end_position:
+                          bytes: 390
+                          line: 8
+                          character: 23
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  if_expression:
+                    Number:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 390
+                          line: 8
+                          character: 23
+                        end_position:
+                          bytes: 391
+                          line: 8
+                          character: 24
+                        token_type:
+                          type: Number
+                          text: "5"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 391
+                            line: 8
+                            character: 24
+                          end_position:
+                            bytes: 392
+                            line: 8
+                            character: 25
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  else_if_expressions: ~
+                  else_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 392
+                        line: 8
+                        character: 25
+                      end_position:
+                        bytes: 396
+                        line: 8
+                        character: 29
+                      token_type:
+                        type: Symbol
+                        symbol: else
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 396
+                          line: 8
+                          character: 29
+                        end_position:
+                          bytes: 397
+                          line: 8
+                          character: 30
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  else_expression:
+                    TypeAssertion:
+                      expression:
+                        Var:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 397
+                                line: 8
+                                character: 30
+                              end_position:
+                                bytes: 400
+                                line: 8
+                                character: 33
+                              token_type:
+                                type: Identifier
+                                identifier: baz
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 400
+                                  line: 8
+                                  character: 33
+                                end_position:
+                                  bytes: 401
+                                  line: 8
+                                  character: 34
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      type_assertion:
+                        assertion_op:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 401
+                              line: 8
+                              character: 34
+                            end_position:
+                              bytes: 403
+                              line: 8
+                              character: 36
+                            token_type:
+                              type: Symbol
+                              symbol: "::"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 403
+                                line: 8
+                                character: 36
+                              end_position:
+                                bytes: 404
+                                line: 8
+                                character: 37
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                        cast_to:
+                          Basic:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 404
+                                line: 8
+                                character: 37
+                              end_position:
+                                bytes: 410
+                                line: 8
+                                character: 43
+                              token_type:
+                                type: Identifier
+                                identifier: number
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 410
+                                  line: 8
+                                  character: 43
+                                end_position:
+                                  bytes: 411
+                                  line: 8
+                                  character: 43
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+    - ~
+  - - If:
+        if_token:
+          leading_trivia:
+            - start_position:
+                bytes: 411
+                line: 9
+                character: 1
+              end_position:
+                bytes: 412
+                line: 9
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 412
+              line: 10
+              character: 1
+            end_position:
+              bytes: 414
+              line: 10
+              character: 3
+            token_type:
+              type: Symbol
+              symbol: if
+          trailing_trivia:
+            - start_position:
+                bytes: 414
+                line: 10
+                character: 3
+              end_position:
+                bytes: 415
+                line: 10
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: " "
+        condition:
+          IfExpression:
+            if_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 415
+                  line: 10
+                  character: 4
+                end_position:
+                  bytes: 417
+                  line: 10
+                  character: 6
+                token_type:
+                  type: Symbol
+                  symbol: if
+              trailing_trivia:
+                - start_position:
+                    bytes: 417
+                    line: 10
+                    character: 6
+                  end_position:
+                    bytes: 418
+                    line: 10
+                    character: 7
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            condition:
+              Var:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 418
+                      line: 10
+                      character: 7
+                    end_position:
+                      bytes: 421
+                      line: 10
+                      character: 10
+                    token_type:
+                      type: Identifier
+                      identifier: foo
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 421
+                        line: 10
+                        character: 10
+                      end_position:
+                        bytes: 422
+                        line: 10
+                        character: 11
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            then_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 422
+                  line: 10
+                  character: 11
+                end_position:
+                  bytes: 426
+                  line: 10
+                  character: 15
+                token_type:
+                  type: Symbol
+                  symbol: then
+              trailing_trivia:
+                - start_position:
+                    bytes: 426
+                    line: 10
+                    character: 15
+                  end_position:
+                    bytes: 427
+                    line: 10
+                    character: 16
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            if_expression:
+              Var:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 427
+                      line: 10
+                      character: 16
+                    end_position:
+                      bytes: 430
+                      line: 10
+                      character: 19
+                    token_type:
+                      type: Identifier
+                      identifier: bar
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 430
+                        line: 10
+                        character: 19
+                      end_position:
+                        bytes: 431
+                        line: 10
+                        character: 20
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            else_if_expressions: ~
+            else_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 431
+                  line: 10
+                  character: 20
+                end_position:
+                  bytes: 435
+                  line: 10
+                  character: 24
+                token_type:
+                  type: Symbol
+                  symbol: else
+              trailing_trivia:
+                - start_position:
+                    bytes: 435
+                    line: 10
+                    character: 24
+                  end_position:
+                    bytes: 436
+                    line: 10
+                    character: 25
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            else_expression:
+              Var:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 436
+                      line: 10
+                      character: 25
+                    end_position:
+                      bytes: 439
+                      line: 10
+                      character: 28
+                    token_type:
+                      type: Identifier
+                      identifier: baz
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 439
+                        line: 10
+                        character: 28
+                      end_position:
+                        bytes: 440
+                        line: 10
+                        character: 29
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+        then_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 440
+              line: 10
+              character: 29
+            end_position:
+              bytes: 444
+              line: 10
+              character: 33
+            token_type:
+              type: Symbol
+              symbol: then
+          trailing_trivia:
+            - start_position:
+                bytes: 444
+                line: 10
+                character: 33
+              end_position:
+                bytes: 445
+                line: 10
+                character: 33
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        block:
+          stmts: []
+        else_if: ~
+        else_token: ~
+        else: ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 445
+              line: 11
+              character: 1
+            end_position:
+              bytes: 448
+              line: 11
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/if_expression/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/if_expression/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..83f3860ad35b2f3bc1d7469b5b23e7f310714b1c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/if_expression/source.lua
@@ -0,0 +1,11 @@
+local x = if foo then foo.x else 5
+local y = (if x then x.indices else create()):update(if shouldUpdate then information else defaults)
+local z = (if bar then foo.y else 5) :: number
+
+local a = if foo then foo.x elseif bar then bar.x else 5
+local b = if foo then if bar then bar else foo else 5
+local c = if foo then (foo.x :: number) elseif bar then bar.x()() else 5
+local d = if foo then 5 else baz :: number
+
+if if foo then bar else baz then
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/if_expression/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/if_expression/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f385aa3883f7d4a7b5304c7b4cb26695df3c0acd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/if_expression/tokens.snap
@@ -0,0 +1,2480 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+
+---
+- 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: 12
+    line: 1
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: if
+- 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: foo
+- 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: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: then
+- 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: 25
+    line: 1
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: foo
+- 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: Identifier
+    identifier: x
+- start_position:
+    bytes: 27
+    line: 1
+    character: 28
+  end_position:
+    bytes: 28
+    line: 1
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 28
+    line: 1
+    character: 29
+  end_position:
+    bytes: 32
+    line: 1
+    character: 33
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 32
+    line: 1
+    character: 33
+  end_position:
+    bytes: 33
+    line: 1
+    character: 34
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 33
+    line: 1
+    character: 34
+  end_position:
+    bytes: 34
+    line: 1
+    character: 35
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 34
+    line: 1
+    character: 35
+  end_position:
+    bytes: 35
+    line: 1
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 35
+    line: 2
+    character: 1
+  end_position:
+    bytes: 40
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 40
+    line: 2
+    character: 6
+  end_position:
+    bytes: 41
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 41
+    line: 2
+    character: 7
+  end_position:
+    bytes: 42
+    line: 2
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 42
+    line: 2
+    character: 8
+  end_position:
+    bytes: 43
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 43
+    line: 2
+    character: 9
+  end_position:
+    bytes: 44
+    line: 2
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 44
+    line: 2
+    character: 10
+  end_position:
+    bytes: 45
+    line: 2
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 45
+    line: 2
+    character: 11
+  end_position:
+    bytes: 46
+    line: 2
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 46
+    line: 2
+    character: 12
+  end_position:
+    bytes: 48
+    line: 2
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 48
+    line: 2
+    character: 14
+  end_position:
+    bytes: 49
+    line: 2
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 49
+    line: 2
+    character: 15
+  end_position:
+    bytes: 50
+    line: 2
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 50
+    line: 2
+    character: 16
+  end_position:
+    bytes: 51
+    line: 2
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 51
+    line: 2
+    character: 17
+  end_position:
+    bytes: 55
+    line: 2
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 55
+    line: 2
+    character: 21
+  end_position:
+    bytes: 56
+    line: 2
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 56
+    line: 2
+    character: 22
+  end_position:
+    bytes: 57
+    line: 2
+    character: 23
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 57
+    line: 2
+    character: 23
+  end_position:
+    bytes: 58
+    line: 2
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 58
+    line: 2
+    character: 24
+  end_position:
+    bytes: 65
+    line: 2
+    character: 31
+  token_type:
+    type: Identifier
+    identifier: indices
+- start_position:
+    bytes: 65
+    line: 2
+    character: 31
+  end_position:
+    bytes: 66
+    line: 2
+    character: 32
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 66
+    line: 2
+    character: 32
+  end_position:
+    bytes: 70
+    line: 2
+    character: 36
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 70
+    line: 2
+    character: 36
+  end_position:
+    bytes: 71
+    line: 2
+    character: 37
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 71
+    line: 2
+    character: 37
+  end_position:
+    bytes: 77
+    line: 2
+    character: 43
+  token_type:
+    type: Identifier
+    identifier: create
+- start_position:
+    bytes: 77
+    line: 2
+    character: 43
+  end_position:
+    bytes: 78
+    line: 2
+    character: 44
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 78
+    line: 2
+    character: 44
+  end_position:
+    bytes: 79
+    line: 2
+    character: 45
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 79
+    line: 2
+    character: 45
+  end_position:
+    bytes: 80
+    line: 2
+    character: 46
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 80
+    line: 2
+    character: 46
+  end_position:
+    bytes: 81
+    line: 2
+    character: 47
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 81
+    line: 2
+    character: 47
+  end_position:
+    bytes: 87
+    line: 2
+    character: 53
+  token_type:
+    type: Identifier
+    identifier: update
+- start_position:
+    bytes: 87
+    line: 2
+    character: 53
+  end_position:
+    bytes: 88
+    line: 2
+    character: 54
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 88
+    line: 2
+    character: 54
+  end_position:
+    bytes: 90
+    line: 2
+    character: 56
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 90
+    line: 2
+    character: 56
+  end_position:
+    bytes: 91
+    line: 2
+    character: 57
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 91
+    line: 2
+    character: 57
+  end_position:
+    bytes: 103
+    line: 2
+    character: 69
+  token_type:
+    type: Identifier
+    identifier: shouldUpdate
+- start_position:
+    bytes: 103
+    line: 2
+    character: 69
+  end_position:
+    bytes: 104
+    line: 2
+    character: 70
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 104
+    line: 2
+    character: 70
+  end_position:
+    bytes: 108
+    line: 2
+    character: 74
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 108
+    line: 2
+    character: 74
+  end_position:
+    bytes: 109
+    line: 2
+    character: 75
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 109
+    line: 2
+    character: 75
+  end_position:
+    bytes: 120
+    line: 2
+    character: 86
+  token_type:
+    type: Identifier
+    identifier: information
+- start_position:
+    bytes: 120
+    line: 2
+    character: 86
+  end_position:
+    bytes: 121
+    line: 2
+    character: 87
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 121
+    line: 2
+    character: 87
+  end_position:
+    bytes: 125
+    line: 2
+    character: 91
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 125
+    line: 2
+    character: 91
+  end_position:
+    bytes: 126
+    line: 2
+    character: 92
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 126
+    line: 2
+    character: 92
+  end_position:
+    bytes: 134
+    line: 2
+    character: 100
+  token_type:
+    type: Identifier
+    identifier: defaults
+- start_position:
+    bytes: 134
+    line: 2
+    character: 100
+  end_position:
+    bytes: 135
+    line: 2
+    character: 101
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 135
+    line: 2
+    character: 101
+  end_position:
+    bytes: 136
+    line: 2
+    character: 101
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 136
+    line: 3
+    character: 1
+  end_position:
+    bytes: 141
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 141
+    line: 3
+    character: 6
+  end_position:
+    bytes: 142
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 142
+    line: 3
+    character: 7
+  end_position:
+    bytes: 143
+    line: 3
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: z
+- start_position:
+    bytes: 143
+    line: 3
+    character: 8
+  end_position:
+    bytes: 144
+    line: 3
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 144
+    line: 3
+    character: 9
+  end_position:
+    bytes: 145
+    line: 3
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 145
+    line: 3
+    character: 10
+  end_position:
+    bytes: 146
+    line: 3
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 146
+    line: 3
+    character: 11
+  end_position:
+    bytes: 147
+    line: 3
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 147
+    line: 3
+    character: 12
+  end_position:
+    bytes: 149
+    line: 3
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 149
+    line: 3
+    character: 14
+  end_position:
+    bytes: 150
+    line: 3
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 150
+    line: 3
+    character: 15
+  end_position:
+    bytes: 153
+    line: 3
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 153
+    line: 3
+    character: 18
+  end_position:
+    bytes: 154
+    line: 3
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 154
+    line: 3
+    character: 19
+  end_position:
+    bytes: 158
+    line: 3
+    character: 23
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 158
+    line: 3
+    character: 23
+  end_position:
+    bytes: 159
+    line: 3
+    character: 24
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 159
+    line: 3
+    character: 24
+  end_position:
+    bytes: 162
+    line: 3
+    character: 27
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 162
+    line: 3
+    character: 27
+  end_position:
+    bytes: 163
+    line: 3
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 163
+    line: 3
+    character: 28
+  end_position:
+    bytes: 164
+    line: 3
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 164
+    line: 3
+    character: 29
+  end_position:
+    bytes: 165
+    line: 3
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 165
+    line: 3
+    character: 30
+  end_position:
+    bytes: 169
+    line: 3
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 169
+    line: 3
+    character: 34
+  end_position:
+    bytes: 170
+    line: 3
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 170
+    line: 3
+    character: 35
+  end_position:
+    bytes: 171
+    line: 3
+    character: 36
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 171
+    line: 3
+    character: 36
+  end_position:
+    bytes: 172
+    line: 3
+    character: 37
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 172
+    line: 3
+    character: 37
+  end_position:
+    bytes: 173
+    line: 3
+    character: 38
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 173
+    line: 3
+    character: 38
+  end_position:
+    bytes: 175
+    line: 3
+    character: 40
+  token_type:
+    type: Symbol
+    symbol: "::"
+- start_position:
+    bytes: 175
+    line: 3
+    character: 40
+  end_position:
+    bytes: 176
+    line: 3
+    character: 41
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 176
+    line: 3
+    character: 41
+  end_position:
+    bytes: 182
+    line: 3
+    character: 47
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 182
+    line: 3
+    character: 47
+  end_position:
+    bytes: 183
+    line: 3
+    character: 47
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 183
+    line: 4
+    character: 1
+  end_position:
+    bytes: 184
+    line: 4
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 184
+    line: 5
+    character: 1
+  end_position:
+    bytes: 189
+    line: 5
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 189
+    line: 5
+    character: 6
+  end_position:
+    bytes: 190
+    line: 5
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 190
+    line: 5
+    character: 7
+  end_position:
+    bytes: 191
+    line: 5
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: a
+- start_position:
+    bytes: 191
+    line: 5
+    character: 8
+  end_position:
+    bytes: 192
+    line: 5
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 192
+    line: 5
+    character: 9
+  end_position:
+    bytes: 193
+    line: 5
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 193
+    line: 5
+    character: 10
+  end_position:
+    bytes: 194
+    line: 5
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 194
+    line: 5
+    character: 11
+  end_position:
+    bytes: 196
+    line: 5
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 196
+    line: 5
+    character: 13
+  end_position:
+    bytes: 197
+    line: 5
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 197
+    line: 5
+    character: 14
+  end_position:
+    bytes: 200
+    line: 5
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 200
+    line: 5
+    character: 17
+  end_position:
+    bytes: 201
+    line: 5
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 201
+    line: 5
+    character: 18
+  end_position:
+    bytes: 205
+    line: 5
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 205
+    line: 5
+    character: 22
+  end_position:
+    bytes: 206
+    line: 5
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 206
+    line: 5
+    character: 23
+  end_position:
+    bytes: 209
+    line: 5
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 209
+    line: 5
+    character: 26
+  end_position:
+    bytes: 210
+    line: 5
+    character: 27
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 210
+    line: 5
+    character: 27
+  end_position:
+    bytes: 211
+    line: 5
+    character: 28
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 211
+    line: 5
+    character: 28
+  end_position:
+    bytes: 212
+    line: 5
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 212
+    line: 5
+    character: 29
+  end_position:
+    bytes: 218
+    line: 5
+    character: 35
+  token_type:
+    type: Symbol
+    symbol: elseif
+- start_position:
+    bytes: 218
+    line: 5
+    character: 35
+  end_position:
+    bytes: 219
+    line: 5
+    character: 36
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 219
+    line: 5
+    character: 36
+  end_position:
+    bytes: 222
+    line: 5
+    character: 39
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 222
+    line: 5
+    character: 39
+  end_position:
+    bytes: 223
+    line: 5
+    character: 40
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 223
+    line: 5
+    character: 40
+  end_position:
+    bytes: 227
+    line: 5
+    character: 44
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 227
+    line: 5
+    character: 44
+  end_position:
+    bytes: 228
+    line: 5
+    character: 45
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 228
+    line: 5
+    character: 45
+  end_position:
+    bytes: 231
+    line: 5
+    character: 48
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 231
+    line: 5
+    character: 48
+  end_position:
+    bytes: 232
+    line: 5
+    character: 49
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 232
+    line: 5
+    character: 49
+  end_position:
+    bytes: 233
+    line: 5
+    character: 50
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 233
+    line: 5
+    character: 50
+  end_position:
+    bytes: 234
+    line: 5
+    character: 51
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 234
+    line: 5
+    character: 51
+  end_position:
+    bytes: 238
+    line: 5
+    character: 55
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 238
+    line: 5
+    character: 55
+  end_position:
+    bytes: 239
+    line: 5
+    character: 56
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 239
+    line: 5
+    character: 56
+  end_position:
+    bytes: 240
+    line: 5
+    character: 57
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 240
+    line: 5
+    character: 57
+  end_position:
+    bytes: 241
+    line: 5
+    character: 57
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 241
+    line: 6
+    character: 1
+  end_position:
+    bytes: 246
+    line: 6
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 246
+    line: 6
+    character: 6
+  end_position:
+    bytes: 247
+    line: 6
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 247
+    line: 6
+    character: 7
+  end_position:
+    bytes: 248
+    line: 6
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 248
+    line: 6
+    character: 8
+  end_position:
+    bytes: 249
+    line: 6
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 249
+    line: 6
+    character: 9
+  end_position:
+    bytes: 250
+    line: 6
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 250
+    line: 6
+    character: 10
+  end_position:
+    bytes: 251
+    line: 6
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 251
+    line: 6
+    character: 11
+  end_position:
+    bytes: 253
+    line: 6
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 253
+    line: 6
+    character: 13
+  end_position:
+    bytes: 254
+    line: 6
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 254
+    line: 6
+    character: 14
+  end_position:
+    bytes: 257
+    line: 6
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 257
+    line: 6
+    character: 17
+  end_position:
+    bytes: 258
+    line: 6
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 258
+    line: 6
+    character: 18
+  end_position:
+    bytes: 262
+    line: 6
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 262
+    line: 6
+    character: 22
+  end_position:
+    bytes: 263
+    line: 6
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 263
+    line: 6
+    character: 23
+  end_position:
+    bytes: 265
+    line: 6
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 265
+    line: 6
+    character: 25
+  end_position:
+    bytes: 266
+    line: 6
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 266
+    line: 6
+    character: 26
+  end_position:
+    bytes: 269
+    line: 6
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 269
+    line: 6
+    character: 29
+  end_position:
+    bytes: 270
+    line: 6
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 270
+    line: 6
+    character: 30
+  end_position:
+    bytes: 274
+    line: 6
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 274
+    line: 6
+    character: 34
+  end_position:
+    bytes: 275
+    line: 6
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 275
+    line: 6
+    character: 35
+  end_position:
+    bytes: 278
+    line: 6
+    character: 38
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 278
+    line: 6
+    character: 38
+  end_position:
+    bytes: 279
+    line: 6
+    character: 39
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 279
+    line: 6
+    character: 39
+  end_position:
+    bytes: 283
+    line: 6
+    character: 43
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 283
+    line: 6
+    character: 43
+  end_position:
+    bytes: 284
+    line: 6
+    character: 44
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 284
+    line: 6
+    character: 44
+  end_position:
+    bytes: 287
+    line: 6
+    character: 47
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 287
+    line: 6
+    character: 47
+  end_position:
+    bytes: 288
+    line: 6
+    character: 48
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 288
+    line: 6
+    character: 48
+  end_position:
+    bytes: 292
+    line: 6
+    character: 52
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 292
+    line: 6
+    character: 52
+  end_position:
+    bytes: 293
+    line: 6
+    character: 53
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 293
+    line: 6
+    character: 53
+  end_position:
+    bytes: 294
+    line: 6
+    character: 54
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 294
+    line: 6
+    character: 54
+  end_position:
+    bytes: 295
+    line: 6
+    character: 54
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 295
+    line: 7
+    character: 1
+  end_position:
+    bytes: 300
+    line: 7
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 300
+    line: 7
+    character: 6
+  end_position:
+    bytes: 301
+    line: 7
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 301
+    line: 7
+    character: 7
+  end_position:
+    bytes: 302
+    line: 7
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: c
+- start_position:
+    bytes: 302
+    line: 7
+    character: 8
+  end_position:
+    bytes: 303
+    line: 7
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 303
+    line: 7
+    character: 9
+  end_position:
+    bytes: 304
+    line: 7
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 304
+    line: 7
+    character: 10
+  end_position:
+    bytes: 305
+    line: 7
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 305
+    line: 7
+    character: 11
+  end_position:
+    bytes: 307
+    line: 7
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 307
+    line: 7
+    character: 13
+  end_position:
+    bytes: 308
+    line: 7
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 308
+    line: 7
+    character: 14
+  end_position:
+    bytes: 311
+    line: 7
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 311
+    line: 7
+    character: 17
+  end_position:
+    bytes: 312
+    line: 7
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 312
+    line: 7
+    character: 18
+  end_position:
+    bytes: 316
+    line: 7
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 316
+    line: 7
+    character: 22
+  end_position:
+    bytes: 317
+    line: 7
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 317
+    line: 7
+    character: 23
+  end_position:
+    bytes: 318
+    line: 7
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 318
+    line: 7
+    character: 24
+  end_position:
+    bytes: 321
+    line: 7
+    character: 27
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 321
+    line: 7
+    character: 27
+  end_position:
+    bytes: 322
+    line: 7
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 322
+    line: 7
+    character: 28
+  end_position:
+    bytes: 323
+    line: 7
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 323
+    line: 7
+    character: 29
+  end_position:
+    bytes: 324
+    line: 7
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 324
+    line: 7
+    character: 30
+  end_position:
+    bytes: 326
+    line: 7
+    character: 32
+  token_type:
+    type: Symbol
+    symbol: "::"
+- start_position:
+    bytes: 326
+    line: 7
+    character: 32
+  end_position:
+    bytes: 327
+    line: 7
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 327
+    line: 7
+    character: 33
+  end_position:
+    bytes: 333
+    line: 7
+    character: 39
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 333
+    line: 7
+    character: 39
+  end_position:
+    bytes: 334
+    line: 7
+    character: 40
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 334
+    line: 7
+    character: 40
+  end_position:
+    bytes: 335
+    line: 7
+    character: 41
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 335
+    line: 7
+    character: 41
+  end_position:
+    bytes: 341
+    line: 7
+    character: 47
+  token_type:
+    type: Symbol
+    symbol: elseif
+- start_position:
+    bytes: 341
+    line: 7
+    character: 47
+  end_position:
+    bytes: 342
+    line: 7
+    character: 48
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 342
+    line: 7
+    character: 48
+  end_position:
+    bytes: 345
+    line: 7
+    character: 51
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 345
+    line: 7
+    character: 51
+  end_position:
+    bytes: 346
+    line: 7
+    character: 52
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 346
+    line: 7
+    character: 52
+  end_position:
+    bytes: 350
+    line: 7
+    character: 56
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 350
+    line: 7
+    character: 56
+  end_position:
+    bytes: 351
+    line: 7
+    character: 57
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 351
+    line: 7
+    character: 57
+  end_position:
+    bytes: 354
+    line: 7
+    character: 60
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 354
+    line: 7
+    character: 60
+  end_position:
+    bytes: 355
+    line: 7
+    character: 61
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 355
+    line: 7
+    character: 61
+  end_position:
+    bytes: 356
+    line: 7
+    character: 62
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 356
+    line: 7
+    character: 62
+  end_position:
+    bytes: 357
+    line: 7
+    character: 63
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 357
+    line: 7
+    character: 63
+  end_position:
+    bytes: 358
+    line: 7
+    character: 64
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 358
+    line: 7
+    character: 64
+  end_position:
+    bytes: 359
+    line: 7
+    character: 65
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 359
+    line: 7
+    character: 65
+  end_position:
+    bytes: 360
+    line: 7
+    character: 66
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 360
+    line: 7
+    character: 66
+  end_position:
+    bytes: 361
+    line: 7
+    character: 67
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 361
+    line: 7
+    character: 67
+  end_position:
+    bytes: 365
+    line: 7
+    character: 71
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 365
+    line: 7
+    character: 71
+  end_position:
+    bytes: 366
+    line: 7
+    character: 72
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 366
+    line: 7
+    character: 72
+  end_position:
+    bytes: 367
+    line: 7
+    character: 73
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 367
+    line: 7
+    character: 73
+  end_position:
+    bytes: 368
+    line: 7
+    character: 73
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 368
+    line: 8
+    character: 1
+  end_position:
+    bytes: 373
+    line: 8
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 373
+    line: 8
+    character: 6
+  end_position:
+    bytes: 374
+    line: 8
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 374
+    line: 8
+    character: 7
+  end_position:
+    bytes: 375
+    line: 8
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: d
+- start_position:
+    bytes: 375
+    line: 8
+    character: 8
+  end_position:
+    bytes: 376
+    line: 8
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 376
+    line: 8
+    character: 9
+  end_position:
+    bytes: 377
+    line: 8
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 377
+    line: 8
+    character: 10
+  end_position:
+    bytes: 378
+    line: 8
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 378
+    line: 8
+    character: 11
+  end_position:
+    bytes: 380
+    line: 8
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 380
+    line: 8
+    character: 13
+  end_position:
+    bytes: 381
+    line: 8
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 381
+    line: 8
+    character: 14
+  end_position:
+    bytes: 384
+    line: 8
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 384
+    line: 8
+    character: 17
+  end_position:
+    bytes: 385
+    line: 8
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 385
+    line: 8
+    character: 18
+  end_position:
+    bytes: 389
+    line: 8
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 389
+    line: 8
+    character: 22
+  end_position:
+    bytes: 390
+    line: 8
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 390
+    line: 8
+    character: 23
+  end_position:
+    bytes: 391
+    line: 8
+    character: 24
+  token_type:
+    type: Number
+    text: "5"
+- start_position:
+    bytes: 391
+    line: 8
+    character: 24
+  end_position:
+    bytes: 392
+    line: 8
+    character: 25
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 392
+    line: 8
+    character: 25
+  end_position:
+    bytes: 396
+    line: 8
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 396
+    line: 8
+    character: 29
+  end_position:
+    bytes: 397
+    line: 8
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 397
+    line: 8
+    character: 30
+  end_position:
+    bytes: 400
+    line: 8
+    character: 33
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 400
+    line: 8
+    character: 33
+  end_position:
+    bytes: 401
+    line: 8
+    character: 34
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 401
+    line: 8
+    character: 34
+  end_position:
+    bytes: 403
+    line: 8
+    character: 36
+  token_type:
+    type: Symbol
+    symbol: "::"
+- start_position:
+    bytes: 403
+    line: 8
+    character: 36
+  end_position:
+    bytes: 404
+    line: 8
+    character: 37
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 404
+    line: 8
+    character: 37
+  end_position:
+    bytes: 410
+    line: 8
+    character: 43
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 410
+    line: 8
+    character: 43
+  end_position:
+    bytes: 411
+    line: 8
+    character: 43
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 411
+    line: 9
+    character: 1
+  end_position:
+    bytes: 412
+    line: 9
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 412
+    line: 10
+    character: 1
+  end_position:
+    bytes: 414
+    line: 10
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 414
+    line: 10
+    character: 3
+  end_position:
+    bytes: 415
+    line: 10
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 415
+    line: 10
+    character: 4
+  end_position:
+    bytes: 417
+    line: 10
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 417
+    line: 10
+    character: 6
+  end_position:
+    bytes: 418
+    line: 10
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 418
+    line: 10
+    character: 7
+  end_position:
+    bytes: 421
+    line: 10
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 421
+    line: 10
+    character: 10
+  end_position:
+    bytes: 422
+    line: 10
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 422
+    line: 10
+    character: 11
+  end_position:
+    bytes: 426
+    line: 10
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 426
+    line: 10
+    character: 15
+  end_position:
+    bytes: 427
+    line: 10
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 427
+    line: 10
+    character: 16
+  end_position:
+    bytes: 430
+    line: 10
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 430
+    line: 10
+    character: 19
+  end_position:
+    bytes: 431
+    line: 10
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 431
+    line: 10
+    character: 20
+  end_position:
+    bytes: 435
+    line: 10
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 435
+    line: 10
+    character: 24
+  end_position:
+    bytes: 436
+    line: 10
+    character: 25
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 436
+    line: 10
+    character: 25
+  end_position:
+    bytes: 439
+    line: 10
+    character: 28
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 439
+    line: 10
+    character: 28
+  end_position:
+    bytes: 440
+    line: 10
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 440
+    line: 10
+    character: 29
+  end_position:
+    bytes: 444
+    line: 10
+    character: 33
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 444
+    line: 10
+    character: 33
+  end_position:
+    bytes: 445
+    line: 10
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 445
+    line: 11
+    character: 1
+  end_position:
+    bytes: 448
+    line: 11
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 448
+    line: 11
+    character: 4
+  end_position:
+    bytes: 448
+    line: 11
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/multiline_expressions/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/multiline_expressions/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..bb4e51de24fd4f343a127ca345c8273ec537c5c7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/multiline_expressions/ast.snap
@@ -0,0 +1,2231 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: full-moon/tests/roblox_cases/pass/multiline_expressions
+---
+stmts:
+  - - Do:
+        do_token:
+          leading_trivia:
+            - start_position:
+                bytes: 0
+                line: 1
+                character: 1
+              end_position:
+                bytes: 104
+                line: 1
+                character: 105
+              token_type:
+                type: SingleLineComment
+                comment: " Taken from https://github.com/JohnnyMorganz/StyLua/blob/main/tests/inputs/multiline-expressions-3.lua"
+            - start_position:
+                bytes: 104
+                line: 1
+                character: 105
+              end_position:
+                bytes: 105
+                line: 1
+                character: 105
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 105
+              line: 2
+              character: 1
+            end_position:
+              bytes: 107
+              line: 2
+              character: 3
+            token_type:
+              type: Symbol
+              symbol: do
+          trailing_trivia:
+            - start_position:
+                bytes: 107
+                line: 2
+                character: 3
+              end_position:
+                bytes: 108
+                line: 2
+                character: 3
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        block:
+          stmts:
+            - - Do:
+                  do_token:
+                    leading_trivia:
+                      - start_position:
+                          bytes: 108
+                          line: 3
+                          character: 1
+                        end_position:
+                          bytes: 109
+                          line: 3
+                          character: 2
+                        token_type:
+                          type: Whitespace
+                          characters: "\t"
+                    token:
+                      start_position:
+                        bytes: 109
+                        line: 3
+                        character: 2
+                      end_position:
+                        bytes: 111
+                        line: 3
+                        character: 4
+                      token_type:
+                        type: Symbol
+                        symbol: do
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 111
+                          line: 3
+                          character: 4
+                        end_position:
+                          bytes: 112
+                          line: 3
+                          character: 4
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+                  block:
+                    stmts:
+                      - - Do:
+                            do_token:
+                              leading_trivia:
+                                - start_position:
+                                    bytes: 112
+                                    line: 4
+                                    character: 1
+                                  end_position:
+                                    bytes: 114
+                                    line: 4
+                                    character: 3
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\t\t"
+                              token:
+                                start_position:
+                                  bytes: 114
+                                  line: 4
+                                  character: 3
+                                end_position:
+                                  bytes: 116
+                                  line: 4
+                                  character: 5
+                                token_type:
+                                  type: Symbol
+                                  symbol: do
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 116
+                                    line: 4
+                                    character: 5
+                                  end_position:
+                                    bytes: 117
+                                    line: 4
+                                    character: 5
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\n"
+                            block:
+                              stmts:
+                                - - Do:
+                                      do_token:
+                                        leading_trivia:
+                                          - start_position:
+                                              bytes: 117
+                                              line: 5
+                                              character: 1
+                                            end_position:
+                                              bytes: 120
+                                              line: 5
+                                              character: 4
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\t\t\t"
+                                        token:
+                                          start_position:
+                                            bytes: 120
+                                            line: 5
+                                            character: 4
+                                          end_position:
+                                            bytes: 122
+                                            line: 5
+                                            character: 6
+                                          token_type:
+                                            type: Symbol
+                                            symbol: do
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 122
+                                              line: 5
+                                              character: 6
+                                            end_position:
+                                              bytes: 123
+                                              line: 5
+                                              character: 6
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\n"
+                                      block:
+                                        stmts:
+                                          - - LocalAssignment:
+                                                local_token:
+                                                  leading_trivia:
+                                                    - start_position:
+                                                        bytes: 123
+                                                        line: 6
+                                                        character: 1
+                                                      end_position:
+                                                        bytes: 127
+                                                        line: 6
+                                                        character: 5
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: "\t\t\t\t"
+                                                  token:
+                                                    start_position:
+                                                      bytes: 127
+                                                      line: 6
+                                                      character: 5
+                                                    end_position:
+                                                      bytes: 132
+                                                      line: 6
+                                                      character: 10
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: local
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 132
+                                                        line: 6
+                                                        character: 10
+                                                      end_position:
+                                                        bytes: 133
+                                                        line: 6
+                                                        character: 11
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: " "
+                                                name_list:
+                                                  pairs:
+                                                    - End:
+                                                        leading_trivia: []
+                                                        token:
+                                                          start_position:
+                                                            bytes: 133
+                                                            line: 6
+                                                            character: 11
+                                                          end_position:
+                                                            bytes: 137
+                                                            line: 6
+                                                            character: 15
+                                                          token_type:
+                                                            type: Identifier
+                                                            identifier: text
+                                                        trailing_trivia:
+                                                          - start_position:
+                                                              bytes: 137
+                                                              line: 6
+                                                              character: 15
+                                                            end_position:
+                                                              bytes: 138
+                                                              line: 6
+                                                              character: 16
+                                                            token_type:
+                                                              type: Whitespace
+                                                              characters: " "
+                                                equal_token:
+                                                  leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 138
+                                                      line: 6
+                                                      character: 16
+                                                    end_position:
+                                                      bytes: 139
+                                                      line: 6
+                                                      character: 17
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: "="
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 139
+                                                        line: 6
+                                                        character: 17
+                                                      end_position:
+                                                        bytes: 140
+                                                        line: 6
+                                                        character: 18
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: " "
+                                                expr_list:
+                                                  pairs:
+                                                    - End:
+                                                        BinaryOperator:
+                                                          lhs:
+                                                            String:
+                                                              leading_trivia: []
+                                                              token:
+                                                                start_position:
+                                                                  bytes: 140
+                                                                  line: 6
+                                                                  character: 18
+                                                                end_position:
+                                                                  bytes: 151
+                                                                  line: 6
+                                                                  character: 29
+                                                                token_type:
+                                                                  type: StringLiteral
+                                                                  literal: "Players: "
+                                                                  quote_type: Double
+                                                              trailing_trivia:
+                                                                - start_position:
+                                                                    bytes: 151
+                                                                    line: 6
+                                                                    character: 29
+                                                                  end_position:
+                                                                    bytes: 152
+                                                                    line: 6
+                                                                    character: 30
+                                                                  token_type:
+                                                                    type: Whitespace
+                                                                    characters: " "
+                                                          binop:
+                                                            TwoDots:
+                                                              leading_trivia: []
+                                                              token:
+                                                                start_position:
+                                                                  bytes: 152
+                                                                  line: 6
+                                                                  character: 30
+                                                                end_position:
+                                                                  bytes: 154
+                                                                  line: 6
+                                                                  character: 32
+                                                                token_type:
+                                                                  type: Symbol
+                                                                  symbol: ".."
+                                                              trailing_trivia:
+                                                                - start_position:
+                                                                    bytes: 154
+                                                                    line: 6
+                                                                    character: 32
+                                                                  end_position:
+                                                                    bytes: 155
+                                                                    line: 6
+                                                                    character: 33
+                                                                  token_type:
+                                                                    type: Whitespace
+                                                                    characters: " "
+                                                          rhs:
+                                                            BinaryOperator:
+                                                              lhs:
+                                                                BinaryOperator:
+                                                                  lhs:
+                                                                    UnaryOperator:
+                                                                      unop:
+                                                                        Hash:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 155
+                                                                              line: 6
+                                                                              character: 33
+                                                                            end_position:
+                                                                              bytes: 156
+                                                                              line: 6
+                                                                              character: 34
+                                                                            token_type:
+                                                                              type: Symbol
+                                                                              symbol: "#"
+                                                                          trailing_trivia: []
+                                                                      expression:
+                                                                        FunctionCall:
+                                                                          prefix:
+                                                                            Name:
+                                                                              leading_trivia: []
+                                                                              token:
+                                                                                start_position:
+                                                                                  bytes: 156
+                                                                                  line: 6
+                                                                                  character: 34
+                                                                                end_position:
+                                                                                  bytes: 172
+                                                                                  line: 6
+                                                                                  character: 50
+                                                                                token_type:
+                                                                                  type: Identifier
+                                                                                  identifier: Server_Container
+                                                                              trailing_trivia: []
+                                                                          suffixes:
+                                                                            - Index:
+                                                                                Dot:
+                                                                                  dot:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 172
+                                                                                        line: 6
+                                                                                        character: 50
+                                                                                      end_position:
+                                                                                        bytes: 173
+                                                                                        line: 6
+                                                                                        character: 51
+                                                                                      token_type:
+                                                                                        type: Symbol
+                                                                                        symbol: "."
+                                                                                    trailing_trivia: []
+                                                                                  name:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 173
+                                                                                        line: 6
+                                                                                        character: 51
+                                                                                      end_position:
+                                                                                        bytes: 235
+                                                                                        line: 6
+                                                                                        character: 113
+                                                                                      token_type:
+                                                                                        type: Identifier
+                                                                                        identifier: ARandomVariableWhichIsVeryLongSoThatThisGetsOverTheColumnLimit
+                                                                                    trailing_trivia: []
+                                                                            - Index:
+                                                                                Dot:
+                                                                                  dot:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 235
+                                                                                        line: 6
+                                                                                        character: 113
+                                                                                      end_position:
+                                                                                        bytes: 236
+                                                                                        line: 6
+                                                                                        character: 114
+                                                                                      token_type:
+                                                                                        type: Symbol
+                                                                                        symbol: "."
+                                                                                    trailing_trivia: []
+                                                                                  name:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 236
+                                                                                        line: 6
+                                                                                        character: 114
+                                                                                      end_position:
+                                                                                        bytes: 245
+                                                                                        line: 6
+                                                                                        character: 123
+                                                                                      token_type:
+                                                                                        type: Identifier
+                                                                                        identifier: Players_F
+                                                                                    trailing_trivia: []
+                                                                            - Call:
+                                                                                MethodCall:
+                                                                                  colon_token:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 245
+                                                                                        line: 6
+                                                                                        character: 123
+                                                                                      end_position:
+                                                                                        bytes: 246
+                                                                                        line: 6
+                                                                                        character: 124
+                                                                                      token_type:
+                                                                                        type: Symbol
+                                                                                        symbol: ":"
+                                                                                    trailing_trivia: []
+                                                                                  name:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 246
+                                                                                        line: 6
+                                                                                        character: 124
+                                                                                      end_position:
+                                                                                        bytes: 257
+                                                                                        line: 6
+                                                                                        character: 135
+                                                                                      token_type:
+                                                                                        type: Identifier
+                                                                                        identifier: GetChildren
+                                                                                    trailing_trivia: []
+                                                                                  args:
+                                                                                    Parentheses:
+                                                                                      parentheses:
+                                                                                        tokens:
+                                                                                          - leading_trivia: []
+                                                                                            token:
+                                                                                              start_position:
+                                                                                                bytes: 257
+                                                                                                line: 6
+                                                                                                character: 135
+                                                                                              end_position:
+                                                                                                bytes: 258
+                                                                                                line: 6
+                                                                                                character: 136
+                                                                                              token_type:
+                                                                                                type: Symbol
+                                                                                                symbol: (
+                                                                                            trailing_trivia: []
+                                                                                          - leading_trivia: []
+                                                                                            token:
+                                                                                              start_position:
+                                                                                                bytes: 258
+                                                                                                line: 6
+                                                                                                character: 136
+                                                                                              end_position:
+                                                                                                bytes: 259
+                                                                                                line: 6
+                                                                                                character: 137
+                                                                                              token_type:
+                                                                                                type: Symbol
+                                                                                                symbol: )
+                                                                                            trailing_trivia:
+                                                                                              - start_position:
+                                                                                                  bytes: 259
+                                                                                                  line: 6
+                                                                                                  character: 137
+                                                                                                end_position:
+                                                                                                  bytes: 260
+                                                                                                  line: 6
+                                                                                                  character: 138
+                                                                                                token_type:
+                                                                                                  type: Whitespace
+                                                                                                  characters: " "
+                                                                                      arguments:
+                                                                                        pairs: []
+                                                                  binop:
+                                                                    Minus:
+                                                                      leading_trivia: []
+                                                                      token:
+                                                                        start_position:
+                                                                          bytes: 260
+                                                                          line: 6
+                                                                          character: 138
+                                                                        end_position:
+                                                                          bytes: 261
+                                                                          line: 6
+                                                                          character: 139
+                                                                        token_type:
+                                                                          type: Symbol
+                                                                          symbol: "-"
+                                                                      trailing_trivia:
+                                                                        - start_position:
+                                                                            bytes: 261
+                                                                            line: 6
+                                                                            character: 139
+                                                                          end_position:
+                                                                            bytes: 262
+                                                                            line: 6
+                                                                            character: 140
+                                                                          token_type:
+                                                                            type: Whitespace
+                                                                            characters: " "
+                                                                  rhs:
+                                                                    Number:
+                                                                      leading_trivia: []
+                                                                      token:
+                                                                        start_position:
+                                                                          bytes: 262
+                                                                          line: 6
+                                                                          character: 140
+                                                                        end_position:
+                                                                          bytes: 263
+                                                                          line: 6
+                                                                          character: 141
+                                                                        token_type:
+                                                                          type: Number
+                                                                          text: "1"
+                                                                      trailing_trivia:
+                                                                        - start_position:
+                                                                            bytes: 263
+                                                                            line: 6
+                                                                            character: 141
+                                                                          end_position:
+                                                                            bytes: 264
+                                                                            line: 6
+                                                                            character: 142
+                                                                          token_type:
+                                                                            type: Whitespace
+                                                                            characters: " "
+                                                              binop:
+                                                                TwoDots:
+                                                                  leading_trivia: []
+                                                                  token:
+                                                                    start_position:
+                                                                      bytes: 264
+                                                                      line: 6
+                                                                      character: 142
+                                                                    end_position:
+                                                                      bytes: 266
+                                                                      line: 6
+                                                                      character: 144
+                                                                    token_type:
+                                                                      type: Symbol
+                                                                      symbol: ".."
+                                                                  trailing_trivia:
+                                                                    - start_position:
+                                                                        bytes: 266
+                                                                        line: 6
+                                                                        character: 144
+                                                                      end_position:
+                                                                        bytes: 267
+                                                                        line: 6
+                                                                        character: 145
+                                                                      token_type:
+                                                                        type: Whitespace
+                                                                        characters: " "
+                                                              rhs:
+                                                                String:
+                                                                  leading_trivia: []
+                                                                  token:
+                                                                    start_position:
+                                                                      bytes: 267
+                                                                      line: 6
+                                                                      character: 145
+                                                                    end_position:
+                                                                      bytes: 272
+                                                                      line: 6
+                                                                      character: 150
+                                                                    token_type:
+                                                                      type: StringLiteral
+                                                                      literal: /20
+                                                                      quote_type: Double
+                                                                  trailing_trivia:
+                                                                    - start_position:
+                                                                        bytes: 272
+                                                                        line: 6
+                                                                        character: 150
+                                                                      end_position:
+                                                                        bytes: 273
+                                                                        line: 6
+                                                                        character: 150
+                                                                      token_type:
+                                                                        type: Whitespace
+                                                                        characters: "\n"
+                                            - ~
+                                          - - LocalAssignment:
+                                                local_token:
+                                                  leading_trivia:
+                                                    - start_position:
+                                                        bytes: 273
+                                                        line: 7
+                                                        character: 1
+                                                      end_position:
+                                                        bytes: 277
+                                                        line: 7
+                                                        character: 5
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: "\t\t\t\t"
+                                                  token:
+                                                    start_position:
+                                                      bytes: 277
+                                                      line: 7
+                                                      character: 5
+                                                    end_position:
+                                                      bytes: 282
+                                                      line: 7
+                                                      character: 10
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: local
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 282
+                                                        line: 7
+                                                        character: 10
+                                                      end_position:
+                                                        bytes: 283
+                                                        line: 7
+                                                        character: 11
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: " "
+                                                name_list:
+                                                  pairs:
+                                                    - End:
+                                                        leading_trivia: []
+                                                        token:
+                                                          start_position:
+                                                            bytes: 283
+                                                            line: 7
+                                                            character: 11
+                                                          end_position:
+                                                            bytes: 288
+                                                            line: 7
+                                                            character: 16
+                                                          token_type:
+                                                            type: Identifier
+                                                            identifier: ratio
+                                                        trailing_trivia:
+                                                          - start_position:
+                                                              bytes: 288
+                                                              line: 7
+                                                              character: 16
+                                                            end_position:
+                                                              bytes: 289
+                                                              line: 7
+                                                              character: 17
+                                                            token_type:
+                                                              type: Whitespace
+                                                              characters: " "
+                                                equal_token:
+                                                  leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 289
+                                                      line: 7
+                                                      character: 17
+                                                    end_position:
+                                                      bytes: 290
+                                                      line: 7
+                                                      character: 18
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: "="
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 290
+                                                        line: 7
+                                                        character: 18
+                                                      end_position:
+                                                        bytes: 291
+                                                        line: 7
+                                                        character: 19
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: " "
+                                                expr_list:
+                                                  pairs:
+                                                    - End:
+                                                        BinaryOperator:
+                                                          lhs:
+                                                            BinaryOperator:
+                                                              lhs:
+                                                                BinaryOperator:
+                                                                  lhs:
+                                                                    Parentheses:
+                                                                      contained:
+                                                                        tokens:
+                                                                          - leading_trivia: []
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 291
+                                                                                line: 7
+                                                                                character: 19
+                                                                              end_position:
+                                                                                bytes: 292
+                                                                                line: 7
+                                                                                character: 20
+                                                                              token_type:
+                                                                                type: Symbol
+                                                                                symbol: (
+                                                                            trailing_trivia: []
+                                                                          - leading_trivia: []
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 313
+                                                                                line: 7
+                                                                                character: 41
+                                                                              end_position:
+                                                                                bytes: 314
+                                                                                line: 7
+                                                                                character: 42
+                                                                              token_type:
+                                                                                type: Symbol
+                                                                                symbol: )
+                                                                            trailing_trivia:
+                                                                              - start_position:
+                                                                                  bytes: 314
+                                                                                  line: 7
+                                                                                  character: 42
+                                                                                end_position:
+                                                                                  bytes: 315
+                                                                                  line: 7
+                                                                                  character: 43
+                                                                                token_type:
+                                                                                  type: Whitespace
+                                                                                  characters: " "
+                                                                      expression:
+                                                                        BinaryOperator:
+                                                                          lhs:
+                                                                            Var:
+                                                                              Name:
+                                                                                leading_trivia: []
+                                                                                token:
+                                                                                  start_position:
+                                                                                    bytes: 292
+                                                                                    line: 7
+                                                                                    character: 20
+                                                                                  end_position:
+                                                                                    bytes: 299
+                                                                                    line: 7
+                                                                                    character: 27
+                                                                                  token_type:
+                                                                                    type: Identifier
+                                                                                    identifier: minAxis
+                                                                                trailing_trivia:
+                                                                                  - start_position:
+                                                                                      bytes: 299
+                                                                                      line: 7
+                                                                                      character: 27
+                                                                                    end_position:
+                                                                                      bytes: 300
+                                                                                      line: 7
+                                                                                      character: 28
+                                                                                    token_type:
+                                                                                      type: Whitespace
+                                                                                      characters: " "
+                                                                          binop:
+                                                                            Minus:
+                                                                              leading_trivia: []
+                                                                              token:
+                                                                                start_position:
+                                                                                  bytes: 300
+                                                                                  line: 7
+                                                                                  character: 28
+                                                                                end_position:
+                                                                                  bytes: 301
+                                                                                  line: 7
+                                                                                  character: 29
+                                                                                token_type:
+                                                                                  type: Symbol
+                                                                                  symbol: "-"
+                                                                              trailing_trivia:
+                                                                                - start_position:
+                                                                                    bytes: 301
+                                                                                    line: 7
+                                                                                    character: 29
+                                                                                  end_position:
+                                                                                    bytes: 302
+                                                                                    line: 7
+                                                                                    character: 30
+                                                                                  token_type:
+                                                                                    type: Whitespace
+                                                                                    characters: " "
+                                                                          rhs:
+                                                                            Var:
+                                                                              Name:
+                                                                                leading_trivia: []
+                                                                                token:
+                                                                                  start_position:
+                                                                                    bytes: 302
+                                                                                    line: 7
+                                                                                    character: 30
+                                                                                  end_position:
+                                                                                    bytes: 313
+                                                                                    line: 7
+                                                                                    character: 41
+                                                                                  token_type:
+                                                                                    type: Identifier
+                                                                                    identifier: minAxisSize
+                                                                                trailing_trivia: []
+                                                                  binop:
+                                                                    Slash:
+                                                                      leading_trivia: []
+                                                                      token:
+                                                                        start_position:
+                                                                          bytes: 315
+                                                                          line: 7
+                                                                          character: 43
+                                                                        end_position:
+                                                                          bytes: 316
+                                                                          line: 7
+                                                                          character: 44
+                                                                        token_type:
+                                                                          type: Symbol
+                                                                          symbol: /
+                                                                      trailing_trivia:
+                                                                        - start_position:
+                                                                            bytes: 316
+                                                                            line: 7
+                                                                            character: 44
+                                                                          end_position:
+                                                                            bytes: 317
+                                                                            line: 7
+                                                                            character: 45
+                                                                          token_type:
+                                                                            type: Whitespace
+                                                                            characters: " "
+                                                                  rhs:
+                                                                    Var:
+                                                                      Name:
+                                                                        leading_trivia: []
+                                                                        token:
+                                                                          start_position:
+                                                                            bytes: 317
+                                                                            line: 7
+                                                                            character: 45
+                                                                          end_position:
+                                                                            bytes: 322
+                                                                            line: 7
+                                                                            character: 50
+                                                                          token_type:
+                                                                            type: Identifier
+                                                                            identifier: delta
+                                                                        trailing_trivia:
+                                                                          - start_position:
+                                                                              bytes: 322
+                                                                              line: 7
+                                                                              character: 50
+                                                                            end_position:
+                                                                              bytes: 323
+                                                                              line: 7
+                                                                              character: 51
+                                                                            token_type:
+                                                                              type: Whitespace
+                                                                              characters: " "
+                                                              binop:
+                                                                Star:
+                                                                  leading_trivia: []
+                                                                  token:
+                                                                    start_position:
+                                                                      bytes: 323
+                                                                      line: 7
+                                                                      character: 51
+                                                                    end_position:
+                                                                      bytes: 324
+                                                                      line: 7
+                                                                      character: 52
+                                                                    token_type:
+                                                                      type: Symbol
+                                                                      symbol: "*"
+                                                                  trailing_trivia:
+                                                                    - start_position:
+                                                                        bytes: 324
+                                                                        line: 7
+                                                                        character: 52
+                                                                      end_position:
+                                                                        bytes: 325
+                                                                        line: 7
+                                                                        character: 53
+                                                                      token_type:
+                                                                        type: Whitespace
+                                                                        characters: " "
+                                                              rhs:
+                                                                Parentheses:
+                                                                  contained:
+                                                                    tokens:
+                                                                      - leading_trivia: []
+                                                                        token:
+                                                                          start_position:
+                                                                            bytes: 325
+                                                                            line: 7
+                                                                            character: 53
+                                                                          end_position:
+                                                                            bytes: 326
+                                                                            line: 7
+                                                                            character: 54
+                                                                          token_type:
+                                                                            type: Symbol
+                                                                            symbol: (
+                                                                        trailing_trivia: []
+                                                                      - leading_trivia: []
+                                                                        token:
+                                                                          start_position:
+                                                                            bytes: 377
+                                                                            line: 7
+                                                                            character: 105
+                                                                          end_position:
+                                                                            bytes: 378
+                                                                            line: 7
+                                                                            character: 106
+                                                                          token_type:
+                                                                            type: Symbol
+                                                                            symbol: )
+                                                                        trailing_trivia:
+                                                                          - start_position:
+                                                                              bytes: 378
+                                                                              line: 7
+                                                                              character: 106
+                                                                            end_position:
+                                                                              bytes: 379
+                                                                              line: 7
+                                                                              character: 107
+                                                                            token_type:
+                                                                              type: Whitespace
+                                                                              characters: " "
+                                                                  expression:
+                                                                    BinaryOperator:
+                                                                      lhs:
+                                                                        Var:
+                                                                          Expression:
+                                                                            prefix:
+                                                                              Name:
+                                                                                leading_trivia: []
+                                                                                token:
+                                                                                  start_position:
+                                                                                    bytes: 326
+                                                                                    line: 7
+                                                                                    character: 54
+                                                                                  end_position:
+                                                                                    bytes: 330
+                                                                                    line: 7
+                                                                                    character: 58
+                                                                                  token_type:
+                                                                                    type: Identifier
+                                                                                    identifier: self
+                                                                                trailing_trivia: []
+                                                                            suffixes:
+                                                                              - Index:
+                                                                                  Dot:
+                                                                                    dot:
+                                                                                      leading_trivia: []
+                                                                                      token:
+                                                                                        start_position:
+                                                                                          bytes: 330
+                                                                                          line: 7
+                                                                                          character: 58
+                                                                                        end_position:
+                                                                                          bytes: 331
+                                                                                          line: 7
+                                                                                          character: 59
+                                                                                        token_type:
+                                                                                          type: Symbol
+                                                                                          symbol: "."
+                                                                                      trailing_trivia: []
+                                                                                    name:
+                                                                                      leading_trivia: []
+                                                                                      token:
+                                                                                        start_position:
+                                                                                          bytes: 331
+                                                                                          line: 7
+                                                                                          character: 59
+                                                                                        end_position:
+                                                                                          bytes: 336
+                                                                                          line: 7
+                                                                                          character: 64
+                                                                                        token_type:
+                                                                                          type: Identifier
+                                                                                          identifier: props
+                                                                                      trailing_trivia: []
+                                                                              - Index:
+                                                                                  Dot:
+                                                                                    dot:
+                                                                                      leading_trivia: []
+                                                                                      token:
+                                                                                        start_position:
+                                                                                          bytes: 336
+                                                                                          line: 7
+                                                                                          character: 64
+                                                                                        end_position:
+                                                                                          bytes: 337
+                                                                                          line: 7
+                                                                                          character: 65
+                                                                                        token_type:
+                                                                                          type: Symbol
+                                                                                          symbol: "."
+                                                                                      trailing_trivia: []
+                                                                                    name:
+                                                                                      leading_trivia: []
+                                                                                      token:
+                                                                                        start_position:
+                                                                                          bytes: 337
+                                                                                          line: 7
+                                                                                          character: 65
+                                                                                        end_position:
+                                                                                          bytes: 350
+                                                                                          line: 7
+                                                                                          character: 78
+                                                                                        token_type:
+                                                                                          type: Identifier
+                                                                                          identifier: maxScaleRatio
+                                                                                      trailing_trivia:
+                                                                                        - start_position:
+                                                                                            bytes: 350
+                                                                                            line: 7
+                                                                                            character: 78
+                                                                                          end_position:
+                                                                                            bytes: 351
+                                                                                            line: 7
+                                                                                            character: 79
+                                                                                          token_type:
+                                                                                            type: Whitespace
+                                                                                            characters: " "
+                                                                      binop:
+                                                                        Minus:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 351
+                                                                              line: 7
+                                                                              character: 79
+                                                                            end_position:
+                                                                              bytes: 352
+                                                                              line: 7
+                                                                              character: 80
+                                                                            token_type:
+                                                                              type: Symbol
+                                                                              symbol: "-"
+                                                                          trailing_trivia:
+                                                                            - start_position:
+                                                                                bytes: 352
+                                                                                line: 7
+                                                                                character: 80
+                                                                              end_position:
+                                                                                bytes: 353
+                                                                                line: 7
+                                                                                character: 81
+                                                                              token_type:
+                                                                                type: Whitespace
+                                                                                characters: " "
+                                                                      rhs:
+                                                                        Var:
+                                                                          Expression:
+                                                                            prefix:
+                                                                              Name:
+                                                                                leading_trivia: []
+                                                                                token:
+                                                                                  start_position:
+                                                                                    bytes: 353
+                                                                                    line: 7
+                                                                                    character: 81
+                                                                                  end_position:
+                                                                                    bytes: 357
+                                                                                    line: 7
+                                                                                    character: 85
+                                                                                  token_type:
+                                                                                    type: Identifier
+                                                                                    identifier: self
+                                                                                trailing_trivia: []
+                                                                            suffixes:
+                                                                              - Index:
+                                                                                  Dot:
+                                                                                    dot:
+                                                                                      leading_trivia: []
+                                                                                      token:
+                                                                                        start_position:
+                                                                                          bytes: 357
+                                                                                          line: 7
+                                                                                          character: 85
+                                                                                        end_position:
+                                                                                          bytes: 358
+                                                                                          line: 7
+                                                                                          character: 86
+                                                                                        token_type:
+                                                                                          type: Symbol
+                                                                                          symbol: "."
+                                                                                      trailing_trivia: []
+                                                                                    name:
+                                                                                      leading_trivia: []
+                                                                                      token:
+                                                                                        start_position:
+                                                                                          bytes: 358
+                                                                                          line: 7
+                                                                                          character: 86
+                                                                                        end_position:
+                                                                                          bytes: 363
+                                                                                          line: 7
+                                                                                          character: 91
+                                                                                        token_type:
+                                                                                          type: Identifier
+                                                                                          identifier: props
+                                                                                      trailing_trivia: []
+                                                                              - Index:
+                                                                                  Dot:
+                                                                                    dot:
+                                                                                      leading_trivia: []
+                                                                                      token:
+                                                                                        start_position:
+                                                                                          bytes: 363
+                                                                                          line: 7
+                                                                                          character: 91
+                                                                                        end_position:
+                                                                                          bytes: 364
+                                                                                          line: 7
+                                                                                          character: 92
+                                                                                        token_type:
+                                                                                          type: Symbol
+                                                                                          symbol: "."
+                                                                                      trailing_trivia: []
+                                                                                    name:
+                                                                                      leading_trivia: []
+                                                                                      token:
+                                                                                        start_position:
+                                                                                          bytes: 364
+                                                                                          line: 7
+                                                                                          character: 92
+                                                                                        end_position:
+                                                                                          bytes: 377
+                                                                                          line: 7
+                                                                                          character: 105
+                                                                                        token_type:
+                                                                                          type: Identifier
+                                                                                          identifier: minScaleRatio
+                                                                                      trailing_trivia: []
+                                                          binop:
+                                                            Plus:
+                                                              leading_trivia: []
+                                                              token:
+                                                                start_position:
+                                                                  bytes: 379
+                                                                  line: 7
+                                                                  character: 107
+                                                                end_position:
+                                                                  bytes: 380
+                                                                  line: 7
+                                                                  character: 108
+                                                                token_type:
+                                                                  type: Symbol
+                                                                  symbol: +
+                                                              trailing_trivia:
+                                                                - start_position:
+                                                                    bytes: 380
+                                                                    line: 7
+                                                                    character: 108
+                                                                  end_position:
+                                                                    bytes: 381
+                                                                    line: 7
+                                                                    character: 109
+                                                                  token_type:
+                                                                    type: Whitespace
+                                                                    characters: " "
+                                                          rhs:
+                                                            Var:
+                                                              Expression:
+                                                                prefix:
+                                                                  Name:
+                                                                    leading_trivia: []
+                                                                    token:
+                                                                      start_position:
+                                                                        bytes: 381
+                                                                        line: 7
+                                                                        character: 109
+                                                                      end_position:
+                                                                        bytes: 385
+                                                                        line: 7
+                                                                        character: 113
+                                                                      token_type:
+                                                                        type: Identifier
+                                                                        identifier: self
+                                                                    trailing_trivia: []
+                                                                suffixes:
+                                                                  - Index:
+                                                                      Dot:
+                                                                        dot:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 385
+                                                                              line: 7
+                                                                              character: 113
+                                                                            end_position:
+                                                                              bytes: 386
+                                                                              line: 7
+                                                                              character: 114
+                                                                            token_type:
+                                                                              type: Symbol
+                                                                              symbol: "."
+                                                                          trailing_trivia: []
+                                                                        name:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 386
+                                                                              line: 7
+                                                                              character: 114
+                                                                            end_position:
+                                                                              bytes: 391
+                                                                              line: 7
+                                                                              character: 119
+                                                                            token_type:
+                                                                              type: Identifier
+                                                                              identifier: props
+                                                                          trailing_trivia: []
+                                                                  - Index:
+                                                                      Dot:
+                                                                        dot:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 391
+                                                                              line: 7
+                                                                              character: 119
+                                                                            end_position:
+                                                                              bytes: 392
+                                                                              line: 7
+                                                                              character: 120
+                                                                            token_type:
+                                                                              type: Symbol
+                                                                              symbol: "."
+                                                                          trailing_trivia: []
+                                                                        name:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 392
+                                                                              line: 7
+                                                                              character: 120
+                                                                            end_position:
+                                                                              bytes: 405
+                                                                              line: 7
+                                                                              character: 133
+                                                                            token_type:
+                                                                              type: Identifier
+                                                                              identifier: minScaleRatio
+                                                                          trailing_trivia:
+                                                                            - start_position:
+                                                                                bytes: 405
+                                                                                line: 7
+                                                                                character: 133
+                                                                              end_position:
+                                                                                bytes: 406
+                                                                                line: 7
+                                                                                character: 133
+                                                                              token_type:
+                                                                                type: Whitespace
+                                                                                characters: "\n"
+                                            - ~
+                                          - - LocalAssignment:
+                                                local_token:
+                                                  leading_trivia:
+                                                    - start_position:
+                                                        bytes: 406
+                                                        line: 8
+                                                        character: 1
+                                                      end_position:
+                                                        bytes: 410
+                                                        line: 8
+                                                        character: 5
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: "\t\t\t\t"
+                                                  token:
+                                                    start_position:
+                                                      bytes: 410
+                                                      line: 8
+                                                      character: 5
+                                                    end_position:
+                                                      bytes: 415
+                                                      line: 8
+                                                      character: 10
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: local
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 415
+                                                        line: 8
+                                                        character: 10
+                                                      end_position:
+                                                        bytes: 416
+                                                        line: 8
+                                                        character: 11
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: " "
+                                                name_list:
+                                                  pairs:
+                                                    - End:
+                                                        leading_trivia: []
+                                                        token:
+                                                          start_position:
+                                                            bytes: 416
+                                                            line: 8
+                                                            character: 11
+                                                          end_position:
+                                                            bytes: 422
+                                                            line: 8
+                                                            character: 17
+                                                          token_type:
+                                                            type: Identifier
+                                                            identifier: ratio2
+                                                        trailing_trivia:
+                                                          - start_position:
+                                                              bytes: 422
+                                                              line: 8
+                                                              character: 17
+                                                            end_position:
+                                                              bytes: 423
+                                                              line: 8
+                                                              character: 18
+                                                            token_type:
+                                                              type: Whitespace
+                                                              characters: " "
+                                                equal_token:
+                                                  leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 423
+                                                      line: 8
+                                                      character: 18
+                                                    end_position:
+                                                      bytes: 424
+                                                      line: 8
+                                                      character: 19
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: "="
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 424
+                                                        line: 8
+                                                        character: 19
+                                                      end_position:
+                                                        bytes: 425
+                                                        line: 8
+                                                        character: 20
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: " "
+                                                expr_list:
+                                                  pairs:
+                                                    - End:
+                                                        BinaryOperator:
+                                                          lhs:
+                                                            BinaryOperator:
+                                                              lhs:
+                                                                BinaryOperator:
+                                                                  lhs:
+                                                                    BinaryOperator:
+                                                                      lhs:
+                                                                        Parentheses:
+                                                                          contained:
+                                                                            tokens:
+                                                                              - leading_trivia: []
+                                                                                token:
+                                                                                  start_position:
+                                                                                    bytes: 425
+                                                                                    line: 8
+                                                                                    character: 20
+                                                                                  end_position:
+                                                                                    bytes: 426
+                                                                                    line: 8
+                                                                                    character: 21
+                                                                                  token_type:
+                                                                                    type: Symbol
+                                                                                    symbol: (
+                                                                                trailing_trivia: []
+                                                                              - leading_trivia: []
+                                                                                token:
+                                                                                  start_position:
+                                                                                    bytes: 447
+                                                                                    line: 8
+                                                                                    character: 42
+                                                                                  end_position:
+                                                                                    bytes: 448
+                                                                                    line: 8
+                                                                                    character: 43
+                                                                                  token_type:
+                                                                                    type: Symbol
+                                                                                    symbol: )
+                                                                                trailing_trivia:
+                                                                                  - start_position:
+                                                                                      bytes: 448
+                                                                                      line: 8
+                                                                                      character: 43
+                                                                                    end_position:
+                                                                                      bytes: 449
+                                                                                      line: 8
+                                                                                      character: 44
+                                                                                    token_type:
+                                                                                      type: Whitespace
+                                                                                      characters: " "
+                                                                          expression:
+                                                                            BinaryOperator:
+                                                                              lhs:
+                                                                                Var:
+                                                                                  Name:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 426
+                                                                                        line: 8
+                                                                                        character: 21
+                                                                                      end_position:
+                                                                                        bytes: 433
+                                                                                        line: 8
+                                                                                        character: 28
+                                                                                      token_type:
+                                                                                        type: Identifier
+                                                                                        identifier: minAxis
+                                                                                    trailing_trivia:
+                                                                                      - start_position:
+                                                                                          bytes: 433
+                                                                                          line: 8
+                                                                                          character: 28
+                                                                                        end_position:
+                                                                                          bytes: 434
+                                                                                          line: 8
+                                                                                          character: 29
+                                                                                        token_type:
+                                                                                          type: Whitespace
+                                                                                          characters: " "
+                                                                              binop:
+                                                                                Minus:
+                                                                                  leading_trivia: []
+                                                                                  token:
+                                                                                    start_position:
+                                                                                      bytes: 434
+                                                                                      line: 8
+                                                                                      character: 29
+                                                                                    end_position:
+                                                                                      bytes: 435
+                                                                                      line: 8
+                                                                                      character: 30
+                                                                                    token_type:
+                                                                                      type: Symbol
+                                                                                      symbol: "-"
+                                                                                  trailing_trivia:
+                                                                                    - start_position:
+                                                                                        bytes: 435
+                                                                                        line: 8
+                                                                                        character: 30
+                                                                                      end_position:
+                                                                                        bytes: 436
+                                                                                        line: 8
+                                                                                        character: 31
+                                                                                      token_type:
+                                                                                        type: Whitespace
+                                                                                        characters: " "
+                                                                              rhs:
+                                                                                Var:
+                                                                                  Name:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 436
+                                                                                        line: 8
+                                                                                        character: 31
+                                                                                      end_position:
+                                                                                        bytes: 447
+                                                                                        line: 8
+                                                                                        character: 42
+                                                                                      token_type:
+                                                                                        type: Identifier
+                                                                                        identifier: minAxisSize
+                                                                                    trailing_trivia: []
+                                                                      binop:
+                                                                        Slash:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 449
+                                                                              line: 8
+                                                                              character: 44
+                                                                            end_position:
+                                                                              bytes: 450
+                                                                              line: 8
+                                                                              character: 45
+                                                                            token_type:
+                                                                              type: Symbol
+                                                                              symbol: /
+                                                                          trailing_trivia:
+                                                                            - start_position:
+                                                                                bytes: 450
+                                                                                line: 8
+                                                                                character: 45
+                                                                              end_position:
+                                                                                bytes: 451
+                                                                                line: 8
+                                                                                character: 46
+                                                                              token_type:
+                                                                                type: Whitespace
+                                                                                characters: " "
+                                                                      rhs:
+                                                                        Var:
+                                                                          Name:
+                                                                            leading_trivia: []
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 451
+                                                                                line: 8
+                                                                                character: 46
+                                                                              end_position:
+                                                                                bytes: 456
+                                                                                line: 8
+                                                                                character: 51
+                                                                              token_type:
+                                                                                type: Identifier
+                                                                                identifier: delta
+                                                                            trailing_trivia:
+                                                                              - start_position:
+                                                                                  bytes: 456
+                                                                                  line: 8
+                                                                                  character: 51
+                                                                                end_position:
+                                                                                  bytes: 457
+                                                                                  line: 8
+                                                                                  character: 52
+                                                                                token_type:
+                                                                                  type: Whitespace
+                                                                                  characters: " "
+                                                                  binop:
+                                                                    Star:
+                                                                      leading_trivia: []
+                                                                      token:
+                                                                        start_position:
+                                                                          bytes: 457
+                                                                          line: 8
+                                                                          character: 52
+                                                                        end_position:
+                                                                          bytes: 458
+                                                                          line: 8
+                                                                          character: 53
+                                                                        token_type:
+                                                                          type: Symbol
+                                                                          symbol: "*"
+                                                                      trailing_trivia:
+                                                                        - start_position:
+                                                                            bytes: 458
+                                                                            line: 8
+                                                                            character: 53
+                                                                          end_position:
+                                                                            bytes: 459
+                                                                            line: 8
+                                                                            character: 54
+                                                                          token_type:
+                                                                            type: Whitespace
+                                                                            characters: " "
+                                                                  rhs:
+                                                                    Parentheses:
+                                                                      contained:
+                                                                        tokens:
+                                                                          - leading_trivia: []
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 459
+                                                                                line: 8
+                                                                                character: 54
+                                                                              end_position:
+                                                                                bytes: 460
+                                                                                line: 8
+                                                                                character: 55
+                                                                              token_type:
+                                                                                type: Symbol
+                                                                                symbol: (
+                                                                            trailing_trivia: []
+                                                                          - leading_trivia: []
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 511
+                                                                                line: 8
+                                                                                character: 106
+                                                                              end_position:
+                                                                                bytes: 512
+                                                                                line: 8
+                                                                                character: 107
+                                                                              token_type:
+                                                                                type: Symbol
+                                                                                symbol: )
+                                                                            trailing_trivia:
+                                                                              - start_position:
+                                                                                  bytes: 512
+                                                                                  line: 8
+                                                                                  character: 107
+                                                                                end_position:
+                                                                                  bytes: 513
+                                                                                  line: 8
+                                                                                  character: 108
+                                                                                token_type:
+                                                                                  type: Whitespace
+                                                                                  characters: " "
+                                                                      expression:
+                                                                        BinaryOperator:
+                                                                          lhs:
+                                                                            Var:
+                                                                              Expression:
+                                                                                prefix:
+                                                                                  Name:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 460
+                                                                                        line: 8
+                                                                                        character: 55
+                                                                                      end_position:
+                                                                                        bytes: 464
+                                                                                        line: 8
+                                                                                        character: 59
+                                                                                      token_type:
+                                                                                        type: Identifier
+                                                                                        identifier: self
+                                                                                    trailing_trivia: []
+                                                                                suffixes:
+                                                                                  - Index:
+                                                                                      Dot:
+                                                                                        dot:
+                                                                                          leading_trivia: []
+                                                                                          token:
+                                                                                            start_position:
+                                                                                              bytes: 464
+                                                                                              line: 8
+                                                                                              character: 59
+                                                                                            end_position:
+                                                                                              bytes: 465
+                                                                                              line: 8
+                                                                                              character: 60
+                                                                                            token_type:
+                                                                                              type: Symbol
+                                                                                              symbol: "."
+                                                                                          trailing_trivia: []
+                                                                                        name:
+                                                                                          leading_trivia: []
+                                                                                          token:
+                                                                                            start_position:
+                                                                                              bytes: 465
+                                                                                              line: 8
+                                                                                              character: 60
+                                                                                            end_position:
+                                                                                              bytes: 470
+                                                                                              line: 8
+                                                                                              character: 65
+                                                                                            token_type:
+                                                                                              type: Identifier
+                                                                                              identifier: props
+                                                                                          trailing_trivia: []
+                                                                                  - Index:
+                                                                                      Dot:
+                                                                                        dot:
+                                                                                          leading_trivia: []
+                                                                                          token:
+                                                                                            start_position:
+                                                                                              bytes: 470
+                                                                                              line: 8
+                                                                                              character: 65
+                                                                                            end_position:
+                                                                                              bytes: 471
+                                                                                              line: 8
+                                                                                              character: 66
+                                                                                            token_type:
+                                                                                              type: Symbol
+                                                                                              symbol: "."
+                                                                                          trailing_trivia: []
+                                                                                        name:
+                                                                                          leading_trivia: []
+                                                                                          token:
+                                                                                            start_position:
+                                                                                              bytes: 471
+                                                                                              line: 8
+                                                                                              character: 66
+                                                                                            end_position:
+                                                                                              bytes: 484
+                                                                                              line: 8
+                                                                                              character: 79
+                                                                                            token_type:
+                                                                                              type: Identifier
+                                                                                              identifier: maxScaleRatio
+                                                                                          trailing_trivia:
+                                                                                            - start_position:
+                                                                                                bytes: 484
+                                                                                                line: 8
+                                                                                                character: 79
+                                                                                              end_position:
+                                                                                                bytes: 485
+                                                                                                line: 8
+                                                                                                character: 80
+                                                                                              token_type:
+                                                                                                type: Whitespace
+                                                                                                characters: " "
+                                                                          binop:
+                                                                            Minus:
+                                                                              leading_trivia: []
+                                                                              token:
+                                                                                start_position:
+                                                                                  bytes: 485
+                                                                                  line: 8
+                                                                                  character: 80
+                                                                                end_position:
+                                                                                  bytes: 486
+                                                                                  line: 8
+                                                                                  character: 81
+                                                                                token_type:
+                                                                                  type: Symbol
+                                                                                  symbol: "-"
+                                                                              trailing_trivia:
+                                                                                - start_position:
+                                                                                    bytes: 486
+                                                                                    line: 8
+                                                                                    character: 81
+                                                                                  end_position:
+                                                                                    bytes: 487
+                                                                                    line: 8
+                                                                                    character: 82
+                                                                                  token_type:
+                                                                                    type: Whitespace
+                                                                                    characters: " "
+                                                                          rhs:
+                                                                            Var:
+                                                                              Expression:
+                                                                                prefix:
+                                                                                  Name:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 487
+                                                                                        line: 8
+                                                                                        character: 82
+                                                                                      end_position:
+                                                                                        bytes: 491
+                                                                                        line: 8
+                                                                                        character: 86
+                                                                                      token_type:
+                                                                                        type: Identifier
+                                                                                        identifier: self
+                                                                                    trailing_trivia: []
+                                                                                suffixes:
+                                                                                  - Index:
+                                                                                      Dot:
+                                                                                        dot:
+                                                                                          leading_trivia: []
+                                                                                          token:
+                                                                                            start_position:
+                                                                                              bytes: 491
+                                                                                              line: 8
+                                                                                              character: 86
+                                                                                            end_position:
+                                                                                              bytes: 492
+                                                                                              line: 8
+                                                                                              character: 87
+                                                                                            token_type:
+                                                                                              type: Symbol
+                                                                                              symbol: "."
+                                                                                          trailing_trivia: []
+                                                                                        name:
+                                                                                          leading_trivia: []
+                                                                                          token:
+                                                                                            start_position:
+                                                                                              bytes: 492
+                                                                                              line: 8
+                                                                                              character: 87
+                                                                                            end_position:
+                                                                                              bytes: 497
+                                                                                              line: 8
+                                                                                              character: 92
+                                                                                            token_type:
+                                                                                              type: Identifier
+                                                                                              identifier: props
+                                                                                          trailing_trivia: []
+                                                                                  - Index:
+                                                                                      Dot:
+                                                                                        dot:
+                                                                                          leading_trivia: []
+                                                                                          token:
+                                                                                            start_position:
+                                                                                              bytes: 497
+                                                                                              line: 8
+                                                                                              character: 92
+                                                                                            end_position:
+                                                                                              bytes: 498
+                                                                                              line: 8
+                                                                                              character: 93
+                                                                                            token_type:
+                                                                                              type: Symbol
+                                                                                              symbol: "."
+                                                                                          trailing_trivia: []
+                                                                                        name:
+                                                                                          leading_trivia: []
+                                                                                          token:
+                                                                                            start_position:
+                                                                                              bytes: 498
+                                                                                              line: 8
+                                                                                              character: 93
+                                                                                            end_position:
+                                                                                              bytes: 511
+                                                                                              line: 8
+                                                                                              character: 106
+                                                                                            token_type:
+                                                                                              type: Identifier
+                                                                                              identifier: minScaleRatio
+                                                                                          trailing_trivia: []
+                                                              binop:
+                                                                Star:
+                                                                  leading_trivia: []
+                                                                  token:
+                                                                    start_position:
+                                                                      bytes: 513
+                                                                      line: 8
+                                                                      character: 108
+                                                                    end_position:
+                                                                      bytes: 514
+                                                                      line: 8
+                                                                      character: 109
+                                                                    token_type:
+                                                                      type: Symbol
+                                                                      symbol: "*"
+                                                                  trailing_trivia:
+                                                                    - start_position:
+                                                                        bytes: 514
+                                                                        line: 8
+                                                                        character: 109
+                                                                      end_position:
+                                                                        bytes: 515
+                                                                        line: 8
+                                                                        character: 110
+                                                                      token_type:
+                                                                        type: Whitespace
+                                                                        characters: " "
+                                                              rhs:
+                                                                Var:
+                                                                  Expression:
+                                                                    prefix:
+                                                                      Name:
+                                                                        leading_trivia: []
+                                                                        token:
+                                                                          start_position:
+                                                                            bytes: 515
+                                                                            line: 8
+                                                                            character: 110
+                                                                          end_position:
+                                                                            bytes: 519
+                                                                            line: 8
+                                                                            character: 114
+                                                                          token_type:
+                                                                            type: Identifier
+                                                                            identifier: self
+                                                                        trailing_trivia: []
+                                                                    suffixes:
+                                                                      - Index:
+                                                                          Dot:
+                                                                            dot:
+                                                                              leading_trivia: []
+                                                                              token:
+                                                                                start_position:
+                                                                                  bytes: 519
+                                                                                  line: 8
+                                                                                  character: 114
+                                                                                end_position:
+                                                                                  bytes: 520
+                                                                                  line: 8
+                                                                                  character: 115
+                                                                                token_type:
+                                                                                  type: Symbol
+                                                                                  symbol: "."
+                                                                              trailing_trivia: []
+                                                                            name:
+                                                                              leading_trivia: []
+                                                                              token:
+                                                                                start_position:
+                                                                                  bytes: 520
+                                                                                  line: 8
+                                                                                  character: 115
+                                                                                end_position:
+                                                                                  bytes: 525
+                                                                                  line: 8
+                                                                                  character: 120
+                                                                                token_type:
+                                                                                  type: Identifier
+                                                                                  identifier: props
+                                                                              trailing_trivia: []
+                                                                      - Index:
+                                                                          Dot:
+                                                                            dot:
+                                                                              leading_trivia: []
+                                                                              token:
+                                                                                start_position:
+                                                                                  bytes: 525
+                                                                                  line: 8
+                                                                                  character: 120
+                                                                                end_position:
+                                                                                  bytes: 526
+                                                                                  line: 8
+                                                                                  character: 121
+                                                                                token_type:
+                                                                                  type: Symbol
+                                                                                  symbol: "."
+                                                                              trailing_trivia: []
+                                                                            name:
+                                                                              leading_trivia: []
+                                                                              token:
+                                                                                start_position:
+                                                                                  bytes: 526
+                                                                                  line: 8
+                                                                                  character: 121
+                                                                                end_position:
+                                                                                  bytes: 556
+                                                                                  line: 8
+                                                                                  character: 151
+                                                                                token_type:
+                                                                                  type: Identifier
+                                                                                  identifier: aRandomVariableWhichIsVeryLong
+                                                                              trailing_trivia:
+                                                                                - start_position:
+                                                                                    bytes: 556
+                                                                                    line: 8
+                                                                                    character: 151
+                                                                                  end_position:
+                                                                                    bytes: 557
+                                                                                    line: 8
+                                                                                    character: 152
+                                                                                  token_type:
+                                                                                    type: Whitespace
+                                                                                    characters: " "
+                                                          binop:
+                                                            Plus:
+                                                              leading_trivia: []
+                                                              token:
+                                                                start_position:
+                                                                  bytes: 557
+                                                                  line: 8
+                                                                  character: 152
+                                                                end_position:
+                                                                  bytes: 558
+                                                                  line: 8
+                                                                  character: 153
+                                                                token_type:
+                                                                  type: Symbol
+                                                                  symbol: +
+                                                              trailing_trivia:
+                                                                - start_position:
+                                                                    bytes: 558
+                                                                    line: 8
+                                                                    character: 153
+                                                                  end_position:
+                                                                    bytes: 559
+                                                                    line: 8
+                                                                    character: 154
+                                                                  token_type:
+                                                                    type: Whitespace
+                                                                    characters: " "
+                                                          rhs:
+                                                            Var:
+                                                              Expression:
+                                                                prefix:
+                                                                  Name:
+                                                                    leading_trivia: []
+                                                                    token:
+                                                                      start_position:
+                                                                        bytes: 559
+                                                                        line: 8
+                                                                        character: 154
+                                                                      end_position:
+                                                                        bytes: 563
+                                                                        line: 8
+                                                                        character: 158
+                                                                      token_type:
+                                                                        type: Identifier
+                                                                        identifier: self
+                                                                    trailing_trivia: []
+                                                                suffixes:
+                                                                  - Index:
+                                                                      Dot:
+                                                                        dot:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 563
+                                                                              line: 8
+                                                                              character: 158
+                                                                            end_position:
+                                                                              bytes: 564
+                                                                              line: 8
+                                                                              character: 159
+                                                                            token_type:
+                                                                              type: Symbol
+                                                                              symbol: "."
+                                                                          trailing_trivia: []
+                                                                        name:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 564
+                                                                              line: 8
+                                                                              character: 159
+                                                                            end_position:
+                                                                              bytes: 569
+                                                                              line: 8
+                                                                              character: 164
+                                                                            token_type:
+                                                                              type: Identifier
+                                                                              identifier: props
+                                                                          trailing_trivia: []
+                                                                  - Index:
+                                                                      Dot:
+                                                                        dot:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 569
+                                                                              line: 8
+                                                                              character: 164
+                                                                            end_position:
+                                                                              bytes: 570
+                                                                              line: 8
+                                                                              character: 165
+                                                                            token_type:
+                                                                              type: Symbol
+                                                                              symbol: "."
+                                                                          trailing_trivia: []
+                                                                        name:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 570
+                                                                              line: 8
+                                                                              character: 165
+                                                                            end_position:
+                                                                              bytes: 583
+                                                                              line: 8
+                                                                              character: 178
+                                                                            token_type:
+                                                                              type: Identifier
+                                                                              identifier: minScaleRatio
+                                                                          trailing_trivia:
+                                                                            - start_position:
+                                                                                bytes: 583
+                                                                                line: 8
+                                                                                character: 178
+                                                                              end_position:
+                                                                                bytes: 584
+                                                                                line: 8
+                                                                                character: 178
+                                                                              token_type:
+                                                                                type: Whitespace
+                                                                                characters: "\n"
+                                            - ~
+                                      end_token:
+                                        leading_trivia:
+                                          - start_position:
+                                              bytes: 584
+                                              line: 9
+                                              character: 1
+                                            end_position:
+                                              bytes: 587
+                                              line: 9
+                                              character: 4
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\t\t\t"
+                                        token:
+                                          start_position:
+                                            bytes: 587
+                                            line: 9
+                                            character: 4
+                                          end_position:
+                                            bytes: 590
+                                            line: 9
+                                            character: 7
+                                          token_type:
+                                            type: Symbol
+                                            symbol: end
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 590
+                                              line: 9
+                                              character: 7
+                                            end_position:
+                                              bytes: 591
+                                              line: 9
+                                              character: 7
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\n"
+                                  - ~
+                            end_token:
+                              leading_trivia:
+                                - start_position:
+                                    bytes: 591
+                                    line: 10
+                                    character: 1
+                                  end_position:
+                                    bytes: 593
+                                    line: 10
+                                    character: 3
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\t\t"
+                              token:
+                                start_position:
+                                  bytes: 593
+                                  line: 10
+                                  character: 3
+                                end_position:
+                                  bytes: 596
+                                  line: 10
+                                  character: 6
+                                token_type:
+                                  type: Symbol
+                                  symbol: end
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 596
+                                    line: 10
+                                    character: 6
+                                  end_position:
+                                    bytes: 597
+                                    line: 10
+                                    character: 6
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\n"
+                        - ~
+                  end_token:
+                    leading_trivia:
+                      - start_position:
+                          bytes: 597
+                          line: 11
+                          character: 1
+                        end_position:
+                          bytes: 598
+                          line: 11
+                          character: 2
+                        token_type:
+                          type: Whitespace
+                          characters: "\t"
+                    token:
+                      start_position:
+                        bytes: 598
+                        line: 11
+                        character: 2
+                      end_position:
+                        bytes: 601
+                        line: 11
+                        character: 5
+                      token_type:
+                        type: Symbol
+                        symbol: end
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 601
+                          line: 11
+                          character: 5
+                        end_position:
+                          bytes: 602
+                          line: 11
+                          character: 5
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+              - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 602
+              line: 12
+              character: 1
+            end_position:
+              bytes: 605
+              line: 12
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 605
+                line: 12
+                character: 4
+              end_position:
+                bytes: 606
+                line: 12
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/multiline_expressions/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/multiline_expressions/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..c899cbb58d25ddd1007382e42c5c344556bca1cd
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/multiline_expressions/source.lua
@@ -0,0 +1,12 @@
+-- Taken from https://github.com/JohnnyMorganz/StyLua/blob/main/tests/inputs/multiline-expressions-3.lua
+do
+	do
+		do
+			do
+				local text = "Players: " .. #Server_Container.ARandomVariableWhichIsVeryLongSoThatThisGetsOverTheColumnLimit.Players_F:GetChildren() - 1 .. "/20"
+				local ratio = (minAxis - minAxisSize) / delta * (self.props.maxScaleRatio - self.props.minScaleRatio) + self.props.minScaleRatio
+				local ratio2 = (minAxis - minAxisSize) / delta * (self.props.maxScaleRatio - self.props.minScaleRatio) * self.props.aRandomVariableWhichIsVeryLong + self.props.minScaleRatio
+			end
+		end
+	end
+end
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/multiline_expressions/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/multiline_expressions/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5d2629e29b383643da70392ec16fd50113e7304e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/multiline_expressions/tokens.snap
@@ -0,0 +1,1689 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/roblox_cases/pass/multiline_expressions
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 104
+    line: 1
+    character: 105
+  token_type:
+    type: SingleLineComment
+    comment: " Taken from https://github.com/JohnnyMorganz/StyLua/blob/main/tests/inputs/multiline-expressions-3.lua"
+- start_position:
+    bytes: 104
+    line: 1
+    character: 105
+  end_position:
+    bytes: 105
+    line: 1
+    character: 105
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 105
+    line: 2
+    character: 1
+  end_position:
+    bytes: 107
+    line: 2
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 107
+    line: 2
+    character: 3
+  end_position:
+    bytes: 108
+    line: 2
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 108
+    line: 3
+    character: 1
+  end_position:
+    bytes: 109
+    line: 3
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 109
+    line: 3
+    character: 2
+  end_position:
+    bytes: 111
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 111
+    line: 3
+    character: 4
+  end_position:
+    bytes: 112
+    line: 3
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 112
+    line: 4
+    character: 1
+  end_position:
+    bytes: 114
+    line: 4
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\t\t"
+- start_position:
+    bytes: 114
+    line: 4
+    character: 3
+  end_position:
+    bytes: 116
+    line: 4
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 116
+    line: 4
+    character: 5
+  end_position:
+    bytes: 117
+    line: 4
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 117
+    line: 5
+    character: 1
+  end_position:
+    bytes: 120
+    line: 5
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t"
+- start_position:
+    bytes: 120
+    line: 5
+    character: 4
+  end_position:
+    bytes: 122
+    line: 5
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 122
+    line: 5
+    character: 6
+  end_position:
+    bytes: 123
+    line: 5
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 123
+    line: 6
+    character: 1
+  end_position:
+    bytes: 127
+    line: 6
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t\t"
+- start_position:
+    bytes: 127
+    line: 6
+    character: 5
+  end_position:
+    bytes: 132
+    line: 6
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 132
+    line: 6
+    character: 10
+  end_position:
+    bytes: 133
+    line: 6
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 133
+    line: 6
+    character: 11
+  end_position:
+    bytes: 137
+    line: 6
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: text
+- start_position:
+    bytes: 137
+    line: 6
+    character: 15
+  end_position:
+    bytes: 138
+    line: 6
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 138
+    line: 6
+    character: 16
+  end_position:
+    bytes: 139
+    line: 6
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 139
+    line: 6
+    character: 17
+  end_position:
+    bytes: 140
+    line: 6
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 140
+    line: 6
+    character: 18
+  end_position:
+    bytes: 151
+    line: 6
+    character: 29
+  token_type:
+    type: StringLiteral
+    literal: "Players: "
+    quote_type: Double
+- start_position:
+    bytes: 151
+    line: 6
+    character: 29
+  end_position:
+    bytes: 152
+    line: 6
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 152
+    line: 6
+    character: 30
+  end_position:
+    bytes: 154
+    line: 6
+    character: 32
+  token_type:
+    type: Symbol
+    symbol: ".."
+- start_position:
+    bytes: 154
+    line: 6
+    character: 32
+  end_position:
+    bytes: 155
+    line: 6
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 155
+    line: 6
+    character: 33
+  end_position:
+    bytes: 156
+    line: 6
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: "#"
+- start_position:
+    bytes: 156
+    line: 6
+    character: 34
+  end_position:
+    bytes: 172
+    line: 6
+    character: 50
+  token_type:
+    type: Identifier
+    identifier: Server_Container
+- start_position:
+    bytes: 172
+    line: 6
+    character: 50
+  end_position:
+    bytes: 173
+    line: 6
+    character: 51
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 173
+    line: 6
+    character: 51
+  end_position:
+    bytes: 235
+    line: 6
+    character: 113
+  token_type:
+    type: Identifier
+    identifier: ARandomVariableWhichIsVeryLongSoThatThisGetsOverTheColumnLimit
+- start_position:
+    bytes: 235
+    line: 6
+    character: 113
+  end_position:
+    bytes: 236
+    line: 6
+    character: 114
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 236
+    line: 6
+    character: 114
+  end_position:
+    bytes: 245
+    line: 6
+    character: 123
+  token_type:
+    type: Identifier
+    identifier: Players_F
+- start_position:
+    bytes: 245
+    line: 6
+    character: 123
+  end_position:
+    bytes: 246
+    line: 6
+    character: 124
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 246
+    line: 6
+    character: 124
+  end_position:
+    bytes: 257
+    line: 6
+    character: 135
+  token_type:
+    type: Identifier
+    identifier: GetChildren
+- start_position:
+    bytes: 257
+    line: 6
+    character: 135
+  end_position:
+    bytes: 258
+    line: 6
+    character: 136
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 258
+    line: 6
+    character: 136
+  end_position:
+    bytes: 259
+    line: 6
+    character: 137
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 259
+    line: 6
+    character: 137
+  end_position:
+    bytes: 260
+    line: 6
+    character: 138
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 260
+    line: 6
+    character: 138
+  end_position:
+    bytes: 261
+    line: 6
+    character: 139
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 261
+    line: 6
+    character: 139
+  end_position:
+    bytes: 262
+    line: 6
+    character: 140
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 262
+    line: 6
+    character: 140
+  end_position:
+    bytes: 263
+    line: 6
+    character: 141
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 263
+    line: 6
+    character: 141
+  end_position:
+    bytes: 264
+    line: 6
+    character: 142
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 264
+    line: 6
+    character: 142
+  end_position:
+    bytes: 266
+    line: 6
+    character: 144
+  token_type:
+    type: Symbol
+    symbol: ".."
+- start_position:
+    bytes: 266
+    line: 6
+    character: 144
+  end_position:
+    bytes: 267
+    line: 6
+    character: 145
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 267
+    line: 6
+    character: 145
+  end_position:
+    bytes: 272
+    line: 6
+    character: 150
+  token_type:
+    type: StringLiteral
+    literal: /20
+    quote_type: Double
+- start_position:
+    bytes: 272
+    line: 6
+    character: 150
+  end_position:
+    bytes: 273
+    line: 6
+    character: 150
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 273
+    line: 7
+    character: 1
+  end_position:
+    bytes: 277
+    line: 7
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t\t"
+- start_position:
+    bytes: 277
+    line: 7
+    character: 5
+  end_position:
+    bytes: 282
+    line: 7
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 282
+    line: 7
+    character: 10
+  end_position:
+    bytes: 283
+    line: 7
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 283
+    line: 7
+    character: 11
+  end_position:
+    bytes: 288
+    line: 7
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: ratio
+- start_position:
+    bytes: 288
+    line: 7
+    character: 16
+  end_position:
+    bytes: 289
+    line: 7
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 289
+    line: 7
+    character: 17
+  end_position:
+    bytes: 290
+    line: 7
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 290
+    line: 7
+    character: 18
+  end_position:
+    bytes: 291
+    line: 7
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 291
+    line: 7
+    character: 19
+  end_position:
+    bytes: 292
+    line: 7
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 292
+    line: 7
+    character: 20
+  end_position:
+    bytes: 299
+    line: 7
+    character: 27
+  token_type:
+    type: Identifier
+    identifier: minAxis
+- start_position:
+    bytes: 299
+    line: 7
+    character: 27
+  end_position:
+    bytes: 300
+    line: 7
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 300
+    line: 7
+    character: 28
+  end_position:
+    bytes: 301
+    line: 7
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 301
+    line: 7
+    character: 29
+  end_position:
+    bytes: 302
+    line: 7
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 302
+    line: 7
+    character: 30
+  end_position:
+    bytes: 313
+    line: 7
+    character: 41
+  token_type:
+    type: Identifier
+    identifier: minAxisSize
+- start_position:
+    bytes: 313
+    line: 7
+    character: 41
+  end_position:
+    bytes: 314
+    line: 7
+    character: 42
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 314
+    line: 7
+    character: 42
+  end_position:
+    bytes: 315
+    line: 7
+    character: 43
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 315
+    line: 7
+    character: 43
+  end_position:
+    bytes: 316
+    line: 7
+    character: 44
+  token_type:
+    type: Symbol
+    symbol: /
+- start_position:
+    bytes: 316
+    line: 7
+    character: 44
+  end_position:
+    bytes: 317
+    line: 7
+    character: 45
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 317
+    line: 7
+    character: 45
+  end_position:
+    bytes: 322
+    line: 7
+    character: 50
+  token_type:
+    type: Identifier
+    identifier: delta
+- start_position:
+    bytes: 322
+    line: 7
+    character: 50
+  end_position:
+    bytes: 323
+    line: 7
+    character: 51
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 323
+    line: 7
+    character: 51
+  end_position:
+    bytes: 324
+    line: 7
+    character: 52
+  token_type:
+    type: Symbol
+    symbol: "*"
+- start_position:
+    bytes: 324
+    line: 7
+    character: 52
+  end_position:
+    bytes: 325
+    line: 7
+    character: 53
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 325
+    line: 7
+    character: 53
+  end_position:
+    bytes: 326
+    line: 7
+    character: 54
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 326
+    line: 7
+    character: 54
+  end_position:
+    bytes: 330
+    line: 7
+    character: 58
+  token_type:
+    type: Identifier
+    identifier: self
+- start_position:
+    bytes: 330
+    line: 7
+    character: 58
+  end_position:
+    bytes: 331
+    line: 7
+    character: 59
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 331
+    line: 7
+    character: 59
+  end_position:
+    bytes: 336
+    line: 7
+    character: 64
+  token_type:
+    type: Identifier
+    identifier: props
+- start_position:
+    bytes: 336
+    line: 7
+    character: 64
+  end_position:
+    bytes: 337
+    line: 7
+    character: 65
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 337
+    line: 7
+    character: 65
+  end_position:
+    bytes: 350
+    line: 7
+    character: 78
+  token_type:
+    type: Identifier
+    identifier: maxScaleRatio
+- start_position:
+    bytes: 350
+    line: 7
+    character: 78
+  end_position:
+    bytes: 351
+    line: 7
+    character: 79
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 351
+    line: 7
+    character: 79
+  end_position:
+    bytes: 352
+    line: 7
+    character: 80
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 352
+    line: 7
+    character: 80
+  end_position:
+    bytes: 353
+    line: 7
+    character: 81
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 353
+    line: 7
+    character: 81
+  end_position:
+    bytes: 357
+    line: 7
+    character: 85
+  token_type:
+    type: Identifier
+    identifier: self
+- start_position:
+    bytes: 357
+    line: 7
+    character: 85
+  end_position:
+    bytes: 358
+    line: 7
+    character: 86
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 358
+    line: 7
+    character: 86
+  end_position:
+    bytes: 363
+    line: 7
+    character: 91
+  token_type:
+    type: Identifier
+    identifier: props
+- start_position:
+    bytes: 363
+    line: 7
+    character: 91
+  end_position:
+    bytes: 364
+    line: 7
+    character: 92
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 364
+    line: 7
+    character: 92
+  end_position:
+    bytes: 377
+    line: 7
+    character: 105
+  token_type:
+    type: Identifier
+    identifier: minScaleRatio
+- start_position:
+    bytes: 377
+    line: 7
+    character: 105
+  end_position:
+    bytes: 378
+    line: 7
+    character: 106
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 378
+    line: 7
+    character: 106
+  end_position:
+    bytes: 379
+    line: 7
+    character: 107
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 379
+    line: 7
+    character: 107
+  end_position:
+    bytes: 380
+    line: 7
+    character: 108
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 380
+    line: 7
+    character: 108
+  end_position:
+    bytes: 381
+    line: 7
+    character: 109
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 381
+    line: 7
+    character: 109
+  end_position:
+    bytes: 385
+    line: 7
+    character: 113
+  token_type:
+    type: Identifier
+    identifier: self
+- start_position:
+    bytes: 385
+    line: 7
+    character: 113
+  end_position:
+    bytes: 386
+    line: 7
+    character: 114
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 386
+    line: 7
+    character: 114
+  end_position:
+    bytes: 391
+    line: 7
+    character: 119
+  token_type:
+    type: Identifier
+    identifier: props
+- start_position:
+    bytes: 391
+    line: 7
+    character: 119
+  end_position:
+    bytes: 392
+    line: 7
+    character: 120
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 392
+    line: 7
+    character: 120
+  end_position:
+    bytes: 405
+    line: 7
+    character: 133
+  token_type:
+    type: Identifier
+    identifier: minScaleRatio
+- start_position:
+    bytes: 405
+    line: 7
+    character: 133
+  end_position:
+    bytes: 406
+    line: 7
+    character: 133
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 406
+    line: 8
+    character: 1
+  end_position:
+    bytes: 410
+    line: 8
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t\t"
+- start_position:
+    bytes: 410
+    line: 8
+    character: 5
+  end_position:
+    bytes: 415
+    line: 8
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 415
+    line: 8
+    character: 10
+  end_position:
+    bytes: 416
+    line: 8
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 416
+    line: 8
+    character: 11
+  end_position:
+    bytes: 422
+    line: 8
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: ratio2
+- start_position:
+    bytes: 422
+    line: 8
+    character: 17
+  end_position:
+    bytes: 423
+    line: 8
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 423
+    line: 8
+    character: 18
+  end_position:
+    bytes: 424
+    line: 8
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 424
+    line: 8
+    character: 19
+  end_position:
+    bytes: 425
+    line: 8
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 425
+    line: 8
+    character: 20
+  end_position:
+    bytes: 426
+    line: 8
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 426
+    line: 8
+    character: 21
+  end_position:
+    bytes: 433
+    line: 8
+    character: 28
+  token_type:
+    type: Identifier
+    identifier: minAxis
+- start_position:
+    bytes: 433
+    line: 8
+    character: 28
+  end_position:
+    bytes: 434
+    line: 8
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 434
+    line: 8
+    character: 29
+  end_position:
+    bytes: 435
+    line: 8
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 435
+    line: 8
+    character: 30
+  end_position:
+    bytes: 436
+    line: 8
+    character: 31
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 436
+    line: 8
+    character: 31
+  end_position:
+    bytes: 447
+    line: 8
+    character: 42
+  token_type:
+    type: Identifier
+    identifier: minAxisSize
+- start_position:
+    bytes: 447
+    line: 8
+    character: 42
+  end_position:
+    bytes: 448
+    line: 8
+    character: 43
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 448
+    line: 8
+    character: 43
+  end_position:
+    bytes: 449
+    line: 8
+    character: 44
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 449
+    line: 8
+    character: 44
+  end_position:
+    bytes: 450
+    line: 8
+    character: 45
+  token_type:
+    type: Symbol
+    symbol: /
+- start_position:
+    bytes: 450
+    line: 8
+    character: 45
+  end_position:
+    bytes: 451
+    line: 8
+    character: 46
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 451
+    line: 8
+    character: 46
+  end_position:
+    bytes: 456
+    line: 8
+    character: 51
+  token_type:
+    type: Identifier
+    identifier: delta
+- start_position:
+    bytes: 456
+    line: 8
+    character: 51
+  end_position:
+    bytes: 457
+    line: 8
+    character: 52
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 457
+    line: 8
+    character: 52
+  end_position:
+    bytes: 458
+    line: 8
+    character: 53
+  token_type:
+    type: Symbol
+    symbol: "*"
+- start_position:
+    bytes: 458
+    line: 8
+    character: 53
+  end_position:
+    bytes: 459
+    line: 8
+    character: 54
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 459
+    line: 8
+    character: 54
+  end_position:
+    bytes: 460
+    line: 8
+    character: 55
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 460
+    line: 8
+    character: 55
+  end_position:
+    bytes: 464
+    line: 8
+    character: 59
+  token_type:
+    type: Identifier
+    identifier: self
+- start_position:
+    bytes: 464
+    line: 8
+    character: 59
+  end_position:
+    bytes: 465
+    line: 8
+    character: 60
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 465
+    line: 8
+    character: 60
+  end_position:
+    bytes: 470
+    line: 8
+    character: 65
+  token_type:
+    type: Identifier
+    identifier: props
+- start_position:
+    bytes: 470
+    line: 8
+    character: 65
+  end_position:
+    bytes: 471
+    line: 8
+    character: 66
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 471
+    line: 8
+    character: 66
+  end_position:
+    bytes: 484
+    line: 8
+    character: 79
+  token_type:
+    type: Identifier
+    identifier: maxScaleRatio
+- start_position:
+    bytes: 484
+    line: 8
+    character: 79
+  end_position:
+    bytes: 485
+    line: 8
+    character: 80
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 485
+    line: 8
+    character: 80
+  end_position:
+    bytes: 486
+    line: 8
+    character: 81
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 486
+    line: 8
+    character: 81
+  end_position:
+    bytes: 487
+    line: 8
+    character: 82
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 487
+    line: 8
+    character: 82
+  end_position:
+    bytes: 491
+    line: 8
+    character: 86
+  token_type:
+    type: Identifier
+    identifier: self
+- start_position:
+    bytes: 491
+    line: 8
+    character: 86
+  end_position:
+    bytes: 492
+    line: 8
+    character: 87
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 492
+    line: 8
+    character: 87
+  end_position:
+    bytes: 497
+    line: 8
+    character: 92
+  token_type:
+    type: Identifier
+    identifier: props
+- start_position:
+    bytes: 497
+    line: 8
+    character: 92
+  end_position:
+    bytes: 498
+    line: 8
+    character: 93
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 498
+    line: 8
+    character: 93
+  end_position:
+    bytes: 511
+    line: 8
+    character: 106
+  token_type:
+    type: Identifier
+    identifier: minScaleRatio
+- start_position:
+    bytes: 511
+    line: 8
+    character: 106
+  end_position:
+    bytes: 512
+    line: 8
+    character: 107
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 512
+    line: 8
+    character: 107
+  end_position:
+    bytes: 513
+    line: 8
+    character: 108
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 513
+    line: 8
+    character: 108
+  end_position:
+    bytes: 514
+    line: 8
+    character: 109
+  token_type:
+    type: Symbol
+    symbol: "*"
+- start_position:
+    bytes: 514
+    line: 8
+    character: 109
+  end_position:
+    bytes: 515
+    line: 8
+    character: 110
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 515
+    line: 8
+    character: 110
+  end_position:
+    bytes: 519
+    line: 8
+    character: 114
+  token_type:
+    type: Identifier
+    identifier: self
+- start_position:
+    bytes: 519
+    line: 8
+    character: 114
+  end_position:
+    bytes: 520
+    line: 8
+    character: 115
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 520
+    line: 8
+    character: 115
+  end_position:
+    bytes: 525
+    line: 8
+    character: 120
+  token_type:
+    type: Identifier
+    identifier: props
+- start_position:
+    bytes: 525
+    line: 8
+    character: 120
+  end_position:
+    bytes: 526
+    line: 8
+    character: 121
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 526
+    line: 8
+    character: 121
+  end_position:
+    bytes: 556
+    line: 8
+    character: 151
+  token_type:
+    type: Identifier
+    identifier: aRandomVariableWhichIsVeryLong
+- start_position:
+    bytes: 556
+    line: 8
+    character: 151
+  end_position:
+    bytes: 557
+    line: 8
+    character: 152
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 557
+    line: 8
+    character: 152
+  end_position:
+    bytes: 558
+    line: 8
+    character: 153
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 558
+    line: 8
+    character: 153
+  end_position:
+    bytes: 559
+    line: 8
+    character: 154
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 559
+    line: 8
+    character: 154
+  end_position:
+    bytes: 563
+    line: 8
+    character: 158
+  token_type:
+    type: Identifier
+    identifier: self
+- start_position:
+    bytes: 563
+    line: 8
+    character: 158
+  end_position:
+    bytes: 564
+    line: 8
+    character: 159
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 564
+    line: 8
+    character: 159
+  end_position:
+    bytes: 569
+    line: 8
+    character: 164
+  token_type:
+    type: Identifier
+    identifier: props
+- start_position:
+    bytes: 569
+    line: 8
+    character: 164
+  end_position:
+    bytes: 570
+    line: 8
+    character: 165
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 570
+    line: 8
+    character: 165
+  end_position:
+    bytes: 583
+    line: 8
+    character: 178
+  token_type:
+    type: Identifier
+    identifier: minScaleRatio
+- start_position:
+    bytes: 583
+    line: 8
+    character: 178
+  end_position:
+    bytes: 584
+    line: 8
+    character: 178
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 584
+    line: 9
+    character: 1
+  end_position:
+    bytes: 587
+    line: 9
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t"
+- start_position:
+    bytes: 587
+    line: 9
+    character: 4
+  end_position:
+    bytes: 590
+    line: 9
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 590
+    line: 9
+    character: 7
+  end_position:
+    bytes: 591
+    line: 9
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 591
+    line: 10
+    character: 1
+  end_position:
+    bytes: 593
+    line: 10
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\t\t"
+- start_position:
+    bytes: 593
+    line: 10
+    character: 3
+  end_position:
+    bytes: 596
+    line: 10
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 596
+    line: 10
+    character: 6
+  end_position:
+    bytes: 597
+    line: 10
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 597
+    line: 11
+    character: 1
+  end_position:
+    bytes: 598
+    line: 11
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 598
+    line: 11
+    character: 2
+  end_position:
+    bytes: 601
+    line: 11
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 601
+    line: 11
+    character: 5
+  end_position:
+    bytes: 602
+    line: 11
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 602
+    line: 12
+    character: 1
+  end_position:
+    bytes: 605
+    line: 12
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 605
+    line: 12
+    character: 4
+  end_position:
+    bytes: 606
+    line: 12
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 606
+    line: 13
+    character: 1
+  end_position:
+    bytes: 606
+    line: 13
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/named_function_arg_types/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/named_function_arg_types/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5113175fb9c61c226bfed43dd631614fc6e4c9da
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/named_function_arg_types/ast.snap
@@ -0,0 +1,1983 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/roblox_cases/pass/named_function_arg_types
+---
+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: 19
+              line: 1
+              character: 20
+            token_type:
+              type: Identifier
+              identifier: MyCallbackType
+          trailing_trivia:
+            - start_position:
+                bytes: 19
+                line: 1
+                character: 20
+              end_position:
+                bytes: 20
+                line: 1
+                character: 21
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          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: " "
+        declare_as:
+          Callback:
+            parentheses:
+              tokens:
+                - 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: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 49
+                      line: 1
+                      character: 50
+                    end_position:
+                      bytes: 50
+                      line: 1
+                      character: 51
+                    token_type:
+                      type: Symbol
+                      symbol: )
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 50
+                        line: 1
+                        character: 51
+                      end_position:
+                        bytes: 51
+                        line: 1
+                        character: 52
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            arguments:
+              pairs:
+                - Punctuated:
+                    - name:
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 23
+                              line: 1
+                              character: 24
+                            end_position:
+                              bytes: 27
+                              line: 1
+                              character: 28
+                            token_type:
+                              type: Identifier
+                              identifier: cost
+                          trailing_trivia: []
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 27
+                              line: 1
+                              character: 28
+                            end_position:
+                              bytes: 28
+                              line: 1
+                              character: 29
+                            token_type:
+                              type: Symbol
+                              symbol: ":"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 28
+                                line: 1
+                                character: 29
+                              end_position:
+                                bytes: 29
+                                line: 1
+                                character: 30
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                      type_info:
+                        Basic:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 29
+                              line: 1
+                              character: 30
+                            end_position:
+                              bytes: 35
+                              line: 1
+                              character: 36
+                            token_type:
+                              type: Identifier
+                              identifier: number
+                          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: 38
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                - End:
+                    name:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 37
+                            line: 1
+                            character: 38
+                          end_position:
+                            bytes: 41
+                            line: 1
+                            character: 42
+                          token_type:
+                            type: Identifier
+                            identifier: name
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 41
+                            line: 1
+                            character: 42
+                          end_position:
+                            bytes: 42
+                            line: 1
+                            character: 43
+                          token_type:
+                            type: Symbol
+                            symbol: ":"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 42
+                              line: 1
+                              character: 43
+                            end_position:
+                              bytes: 43
+                              line: 1
+                              character: 44
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                    type_info:
+                      Basic:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 43
+                            line: 1
+                            character: 44
+                          end_position:
+                            bytes: 49
+                            line: 1
+                            character: 50
+                          token_type:
+                            type: Identifier
+                            identifier: string
+                        trailing_trivia: []
+            arrow:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 51
+                  line: 1
+                  character: 52
+                end_position:
+                  bytes: 53
+                  line: 1
+                  character: 54
+                token_type:
+                  type: Symbol
+                  symbol: "->"
+              trailing_trivia:
+                - start_position:
+                    bytes: 53
+                    line: 1
+                    character: 54
+                  end_position:
+                    bytes: 54
+                    line: 1
+                    character: 55
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            return_type:
+              Basic:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 54
+                    line: 1
+                    character: 55
+                  end_position:
+                    bytes: 60
+                    line: 1
+                    character: 61
+                  token_type:
+                    type: Identifier
+                    identifier: string
+                trailing_trivia:
+                  - start_position:
+                      bytes: 60
+                      line: 1
+                      character: 61
+                    end_position:
+                      bytes: 61
+                      line: 1
+                      character: 61
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 61
+                line: 2
+                character: 1
+              end_position:
+                bytes: 62
+                line: 2
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 62
+              line: 3
+              character: 1
+            end_position:
+              bytes: 67
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 67
+                line: 3
+                character: 6
+              end_position:
+                bytes: 68
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        type_specifiers:
+          - punctuation:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 70
+                  line: 3
+                  character: 9
+                end_position:
+                  bytes: 71
+                  line: 3
+                  character: 10
+                token_type:
+                  type: Symbol
+                  symbol: ":"
+              trailing_trivia:
+                - start_position:
+                    bytes: 71
+                    line: 3
+                    character: 10
+                  end_position:
+                    bytes: 72
+                    line: 3
+                    character: 11
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            type_info:
+              Callback:
+                parentheses:
+                  tokens:
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 72
+                          line: 3
+                          character: 11
+                        end_position:
+                          bytes: 73
+                          line: 3
+                          character: 12
+                        token_type:
+                          type: Symbol
+                          symbol: (
+                      trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 87
+                          line: 3
+                          character: 26
+                        end_position:
+                          bytes: 88
+                          line: 3
+                          character: 27
+                        token_type:
+                          type: Symbol
+                          symbol: )
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 88
+                            line: 3
+                            character: 27
+                          end_position:
+                            bytes: 89
+                            line: 3
+                            character: 28
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                arguments:
+                  pairs:
+                    - End:
+                        name:
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 73
+                                line: 3
+                                character: 12
+                              end_position:
+                                bytes: 79
+                                line: 3
+                                character: 18
+                              token_type:
+                                type: Identifier
+                                identifier: amount
+                            trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 79
+                                line: 3
+                                character: 18
+                              end_position:
+                                bytes: 80
+                                line: 3
+                                character: 19
+                              token_type:
+                                type: Symbol
+                                symbol: ":"
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 80
+                                  line: 3
+                                  character: 19
+                                end_position:
+                                  bytes: 81
+                                  line: 3
+                                  character: 20
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                        type_info:
+                          Basic:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 81
+                                line: 3
+                                character: 20
+                              end_position:
+                                bytes: 87
+                                line: 3
+                                character: 26
+                              token_type:
+                                type: Identifier
+                                identifier: number
+                            trailing_trivia: []
+                arrow:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 89
+                      line: 3
+                      character: 28
+                    end_position:
+                      bytes: 91
+                      line: 3
+                      character: 30
+                    token_type:
+                      type: Symbol
+                      symbol: "->"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 91
+                        line: 3
+                        character: 30
+                      end_position:
+                        bytes: 92
+                        line: 3
+                        character: 31
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+                return_type:
+                  Basic:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 92
+                        line: 3
+                        character: 31
+                      end_position:
+                        bytes: 98
+                        line: 3
+                        character: 37
+                      token_type:
+                        type: Identifier
+                        identifier: number
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 98
+                          line: 3
+                          character: 37
+                        end_position:
+                          bytes: 99
+                          line: 3
+                          character: 37
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 68
+                    line: 3
+                    character: 7
+                  end_position:
+                    bytes: 70
+                    line: 3
+                    character: 9
+                  token_type:
+                    type: Identifier
+                    identifier: cb
+                trailing_trivia: []
+        equal_token: ~
+        expr_list:
+          pairs: []
+    - ~
+  - - LocalFunction:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 99
+              line: 4
+              character: 1
+            end_position:
+              bytes: 104
+              line: 4
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 104
+                line: 4
+                character: 6
+              end_position:
+                bytes: 105
+                line: 4
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        function_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 105
+              line: 4
+              character: 7
+            end_position:
+              bytes: 113
+              line: 4
+              character: 15
+            token_type:
+              type: Symbol
+              symbol: function
+          trailing_trivia:
+            - start_position:
+                bytes: 113
+                line: 4
+                character: 15
+              end_position:
+                bytes: 114
+                line: 4
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        name:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 114
+              line: 4
+              character: 16
+            end_position:
+              bytes: 117
+              line: 4
+              character: 19
+            token_type:
+              type: Identifier
+              identifier: foo
+          trailing_trivia: []
+        body:
+          parameters_parentheses:
+            tokens:
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 117
+                    line: 4
+                    character: 19
+                  end_position:
+                    bytes: 118
+                    line: 4
+                    character: 20
+                  token_type:
+                    type: Symbol
+                    symbol: (
+                trailing_trivia: []
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 144
+                    line: 4
+                    character: 46
+                  end_position:
+                    bytes: 145
+                    line: 4
+                    character: 47
+                  token_type:
+                    type: Symbol
+                    symbol: )
+                trailing_trivia:
+                  - start_position:
+                      bytes: 145
+                      line: 4
+                      character: 47
+                    end_position:
+                      bytes: 146
+                      line: 4
+                      character: 47
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+          parameters:
+            pairs:
+              - End:
+                  name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 118
+                        line: 4
+                        character: 20
+                      end_position:
+                        bytes: 120
+                        line: 4
+                        character: 22
+                      token_type:
+                        type: Identifier
+                        identifier: cb
+                    trailing_trivia: []
+          type_specifiers:
+            - punctuation:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 120
+                    line: 4
+                    character: 22
+                  end_position:
+                    bytes: 121
+                    line: 4
+                    character: 23
+                  token_type:
+                    type: Symbol
+                    symbol: ":"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 121
+                      line: 4
+                      character: 23
+                    end_position:
+                      bytes: 122
+                      line: 4
+                      character: 24
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              type_info:
+                Callback:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 122
+                            line: 4
+                            character: 24
+                          end_position:
+                            bytes: 123
+                            line: 4
+                            character: 25
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 135
+                            line: 4
+                            character: 37
+                          end_position:
+                            bytes: 136
+                            line: 4
+                            character: 38
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 136
+                              line: 4
+                              character: 38
+                            end_position:
+                              bytes: 137
+                              line: 4
+                              character: 39
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  arguments:
+                    pairs:
+                      - End:
+                          name:
+                            - leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 123
+                                  line: 4
+                                  character: 25
+                                end_position:
+                                  bytes: 127
+                                  line: 4
+                                  character: 29
+                                token_type:
+                                  type: Identifier
+                                  identifier: name
+                              trailing_trivia: []
+                            - leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 127
+                                  line: 4
+                                  character: 29
+                                end_position:
+                                  bytes: 128
+                                  line: 4
+                                  character: 30
+                                token_type:
+                                  type: Symbol
+                                  symbol: ":"
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 128
+                                    line: 4
+                                    character: 30
+                                  end_position:
+                                    bytes: 129
+                                    line: 4
+                                    character: 31
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                          type_info:
+                            Basic:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 129
+                                  line: 4
+                                  character: 31
+                                end_position:
+                                  bytes: 135
+                                  line: 4
+                                  character: 37
+                                token_type:
+                                  type: Identifier
+                                  identifier: string
+                              trailing_trivia: []
+                  arrow:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 137
+                        line: 4
+                        character: 39
+                      end_position:
+                        bytes: 139
+                        line: 4
+                        character: 41
+                      token_type:
+                        type: Symbol
+                        symbol: "->"
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 139
+                          line: 4
+                          character: 41
+                        end_position:
+                          bytes: 140
+                          line: 4
+                          character: 42
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  return_type:
+                    Basic:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 140
+                          line: 4
+                          character: 42
+                        end_position:
+                          bytes: 144
+                          line: 4
+                          character: 46
+                        token_type:
+                          type: Identifier
+                          identifier: unit
+                      trailing_trivia: []
+          block:
+            stmts: []
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 146
+                line: 5
+                character: 1
+              end_position:
+                bytes: 149
+                line: 5
+                character: 4
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia:
+              - start_position:
+                  bytes: 149
+                  line: 5
+                  character: 4
+                end_position:
+                  bytes: 150
+                  line: 5
+                  character: 4
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - LocalFunction:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 150
+                line: 6
+                character: 1
+              end_position:
+                bytes: 151
+                line: 6
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 151
+              line: 7
+              character: 1
+            end_position:
+              bytes: 156
+              line: 7
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 156
+                line: 7
+                character: 6
+              end_position:
+                bytes: 157
+                line: 7
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        function_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 157
+              line: 7
+              character: 7
+            end_position:
+              bytes: 165
+              line: 7
+              character: 15
+            token_type:
+              type: Symbol
+              symbol: function
+          trailing_trivia:
+            - start_position:
+                bytes: 165
+                line: 7
+                character: 15
+              end_position:
+                bytes: 166
+                line: 7
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        name:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 166
+              line: 7
+              character: 16
+            end_position:
+              bytes: 169
+              line: 7
+              character: 19
+            token_type:
+              type: Identifier
+              identifier: bar
+          trailing_trivia: []
+        body:
+          parameters_parentheses:
+            tokens:
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 169
+                    line: 7
+                    character: 19
+                  end_position:
+                    bytes: 170
+                    line: 7
+                    character: 20
+                  token_type:
+                    type: Symbol
+                    symbol: (
+                trailing_trivia: []
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 180
+                    line: 7
+                    character: 30
+                  end_position:
+                    bytes: 181
+                    line: 7
+                    character: 31
+                  token_type:
+                    type: Symbol
+                    symbol: )
+                trailing_trivia: []
+          parameters:
+            pairs:
+              - End:
+                  name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 170
+                        line: 7
+                        character: 20
+                      end_position:
+                        bytes: 171
+                        line: 7
+                        character: 21
+                      token_type:
+                        type: Identifier
+                        identifier: x
+                    trailing_trivia: []
+          type_specifiers:
+            - punctuation:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 171
+                    line: 7
+                    character: 21
+                  end_position:
+                    bytes: 172
+                    line: 7
+                    character: 22
+                  token_type:
+                    type: Symbol
+                    symbol: ":"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 172
+                      line: 7
+                      character: 22
+                    end_position:
+                      bytes: 173
+                      line: 7
+                      character: 23
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              type_info:
+                Optional:
+                  base:
+                    Basic:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 173
+                          line: 7
+                          character: 23
+                        end_position:
+                          bytes: 179
+                          line: 7
+                          character: 29
+                        token_type:
+                          type: Identifier
+                          identifier: number
+                      trailing_trivia: []
+                  question_mark:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 179
+                        line: 7
+                        character: 29
+                      end_position:
+                        bytes: 180
+                        line: 7
+                        character: 30
+                      token_type:
+                        type: Symbol
+                        symbol: "?"
+                    trailing_trivia: []
+          return_type:
+            punctuation:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 181
+                  line: 7
+                  character: 31
+                end_position:
+                  bytes: 182
+                  line: 7
+                  character: 32
+                token_type:
+                  type: Symbol
+                  symbol: ":"
+              trailing_trivia:
+                - start_position:
+                    bytes: 182
+                    line: 7
+                    character: 32
+                  end_position:
+                    bytes: 183
+                    line: 7
+                    character: 33
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            type_info:
+              Callback:
+                parentheses:
+                  tokens:
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 183
+                          line: 7
+                          character: 33
+                        end_position:
+                          bytes: 184
+                          line: 7
+                          character: 34
+                        token_type:
+                          type: Symbol
+                          symbol: (
+                      trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 195
+                          line: 7
+                          character: 45
+                        end_position:
+                          bytes: 196
+                          line: 7
+                          character: 46
+                        token_type:
+                          type: Symbol
+                          symbol: )
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 196
+                            line: 7
+                            character: 46
+                          end_position:
+                            bytes: 197
+                            line: 7
+                            character: 47
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                arguments:
+                  pairs:
+                    - End:
+                        name:
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 184
+                                line: 7
+                                character: 34
+                              end_position:
+                                bytes: 187
+                                line: 7
+                                character: 37
+                              token_type:
+                                type: Identifier
+                                identifier: baz
+                            trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 187
+                                line: 7
+                                character: 37
+                              end_position:
+                                bytes: 188
+                                line: 7
+                                character: 38
+                              token_type:
+                                type: Symbol
+                                symbol: ":"
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 188
+                                  line: 7
+                                  character: 38
+                                end_position:
+                                  bytes: 189
+                                  line: 7
+                                  character: 39
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                        type_info:
+                          Basic:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 189
+                                line: 7
+                                character: 39
+                              end_position:
+                                bytes: 195
+                                line: 7
+                                character: 45
+                              token_type:
+                                type: Identifier
+                                identifier: string
+                            trailing_trivia: []
+                arrow:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 197
+                      line: 7
+                      character: 47
+                    end_position:
+                      bytes: 199
+                      line: 7
+                      character: 49
+                    token_type:
+                      type: Symbol
+                      symbol: "->"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 199
+                        line: 7
+                        character: 49
+                      end_position:
+                        bytes: 200
+                        line: 7
+                        character: 50
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+                return_type:
+                  Basic:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 200
+                        line: 7
+                        character: 50
+                      end_position:
+                        bytes: 206
+                        line: 7
+                        character: 56
+                      token_type:
+                        type: Identifier
+                        identifier: string
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 206
+                          line: 7
+                          character: 56
+                        end_position:
+                          bytes: 207
+                          line: 7
+                          character: 56
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+          block:
+            stmts: []
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 207
+                line: 8
+                character: 1
+              end_position:
+                bytes: 210
+                line: 8
+                character: 4
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia:
+              - start_position:
+                  bytes: 210
+                  line: 8
+                  character: 4
+                end_position:
+                  bytes: 211
+                  line: 8
+                  character: 4
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - LocalFunction:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 211
+                line: 9
+                character: 1
+              end_position:
+                bytes: 212
+                line: 9
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 212
+              line: 10
+              character: 1
+            end_position:
+              bytes: 217
+              line: 10
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 217
+                line: 10
+                character: 6
+              end_position:
+                bytes: 218
+                line: 10
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        function_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 218
+              line: 10
+              character: 7
+            end_position:
+              bytes: 226
+              line: 10
+              character: 15
+            token_type:
+              type: Symbol
+              symbol: function
+          trailing_trivia:
+            - start_position:
+                bytes: 226
+                line: 10
+                character: 15
+              end_position:
+                bytes: 227
+                line: 10
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        name:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 227
+              line: 10
+              character: 16
+            end_position:
+              bytes: 230
+              line: 10
+              character: 19
+            token_type:
+              type: Identifier
+              identifier: bar
+          trailing_trivia: []
+        body:
+          parameters_parentheses:
+            tokens:
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 230
+                    line: 10
+                    character: 19
+                  end_position:
+                    bytes: 231
+                    line: 10
+                    character: 20
+                  token_type:
+                    type: Symbol
+                    symbol: (
+                trailing_trivia: []
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 241
+                    line: 10
+                    character: 30
+                  end_position:
+                    bytes: 242
+                    line: 10
+                    character: 31
+                  token_type:
+                    type: Symbol
+                    symbol: )
+                trailing_trivia: []
+          parameters:
+            pairs:
+              - End:
+                  name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 231
+                        line: 10
+                        character: 20
+                      end_position:
+                        bytes: 232
+                        line: 10
+                        character: 21
+                      token_type:
+                        type: Identifier
+                        identifier: x
+                    trailing_trivia: []
+          type_specifiers:
+            - punctuation:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 232
+                    line: 10
+                    character: 21
+                  end_position:
+                    bytes: 233
+                    line: 10
+                    character: 22
+                  token_type:
+                    type: Symbol
+                    symbol: ":"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 233
+                      line: 10
+                      character: 22
+                    end_position:
+                      bytes: 234
+                      line: 10
+                      character: 23
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              type_info:
+                Optional:
+                  base:
+                    Basic:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 234
+                          line: 10
+                          character: 23
+                        end_position:
+                          bytes: 240
+                          line: 10
+                          character: 29
+                        token_type:
+                          type: Identifier
+                          identifier: number
+                      trailing_trivia: []
+                  question_mark:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 240
+                        line: 10
+                        character: 29
+                      end_position:
+                        bytes: 241
+                        line: 10
+                        character: 30
+                      token_type:
+                        type: Symbol
+                        symbol: "?"
+                    trailing_trivia: []
+          return_type:
+            punctuation:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 242
+                  line: 10
+                  character: 31
+                end_position:
+                  bytes: 243
+                  line: 10
+                  character: 32
+                token_type:
+                  type: Symbol
+                  symbol: ":"
+              trailing_trivia:
+                - start_position:
+                    bytes: 243
+                    line: 10
+                    character: 32
+                  end_position:
+                    bytes: 244
+                    line: 10
+                    character: 33
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            type_info:
+              Callback:
+                parentheses:
+                  tokens:
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 244
+                          line: 10
+                          character: 33
+                        end_position:
+                          bytes: 245
+                          line: 10
+                          character: 34
+                        token_type:
+                          type: Symbol
+                          symbol: (
+                      trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 256
+                          line: 10
+                          character: 45
+                        end_position:
+                          bytes: 257
+                          line: 10
+                          character: 46
+                        token_type:
+                          type: Symbol
+                          symbol: )
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 257
+                            line: 10
+                            character: 46
+                          end_position:
+                            bytes: 258
+                            line: 10
+                            character: 47
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                arguments:
+                  pairs:
+                    - End:
+                        name:
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 245
+                                line: 10
+                                character: 34
+                              end_position:
+                                bytes: 248
+                                line: 10
+                                character: 37
+                              token_type:
+                                type: Identifier
+                                identifier: baz
+                            trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 248
+                                line: 10
+                                character: 37
+                              end_position:
+                                bytes: 249
+                                line: 10
+                                character: 38
+                              token_type:
+                                type: Symbol
+                                symbol: ":"
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 249
+                                  line: 10
+                                  character: 38
+                                end_position:
+                                  bytes: 250
+                                  line: 10
+                                  character: 39
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                        type_info:
+                          Basic:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 250
+                                line: 10
+                                character: 39
+                              end_position:
+                                bytes: 256
+                                line: 10
+                                character: 45
+                              token_type:
+                                type: Identifier
+                                identifier: string
+                            trailing_trivia: []
+                arrow:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 258
+                      line: 10
+                      character: 47
+                    end_position:
+                      bytes: 260
+                      line: 10
+                      character: 49
+                    token_type:
+                      type: Symbol
+                      symbol: "->"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 260
+                        line: 10
+                        character: 49
+                      end_position:
+                        bytes: 261
+                        line: 10
+                        character: 50
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+                return_type:
+                  Tuple:
+                    parentheses:
+                      tokens:
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 261
+                              line: 10
+                              character: 50
+                            end_position:
+                              bytes: 262
+                              line: 10
+                              character: 51
+                            token_type:
+                              type: Symbol
+                              symbol: (
+                          trailing_trivia: []
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 298
+                              line: 10
+                              character: 87
+                            end_position:
+                              bytes: 299
+                              line: 10
+                              character: 88
+                            token_type:
+                              type: Symbol
+                              symbol: )
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 299
+                                line: 10
+                                character: 88
+                              end_position:
+                                bytes: 300
+                                line: 10
+                                character: 88
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+                    types:
+                      pairs:
+                        - End:
+                            Callback:
+                              parentheses:
+                                tokens:
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 262
+                                        line: 10
+                                        character: 51
+                                      end_position:
+                                        bytes: 263
+                                        line: 10
+                                        character: 52
+                                      token_type:
+                                        type: Symbol
+                                        symbol: (
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 290
+                                        line: 10
+                                        character: 79
+                                      end_position:
+                                        bytes: 291
+                                        line: 10
+                                        character: 80
+                                      token_type:
+                                        type: Symbol
+                                        symbol: )
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 291
+                                          line: 10
+                                          character: 80
+                                        end_position:
+                                          bytes: 292
+                                          line: 10
+                                          character: 81
+                                        token_type:
+                                          type: Whitespace
+                                          characters: " "
+                              arguments:
+                                pairs:
+                                  - End:
+                                      name:
+                                        - leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 263
+                                              line: 10
+                                              character: 52
+                                            end_position:
+                                              bytes: 268
+                                              line: 10
+                                              character: 57
+                                            token_type:
+                                              type: Identifier
+                                              identifier: names
+                                          trailing_trivia: []
+                                        - leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 268
+                                              line: 10
+                                              character: 57
+                                            end_position:
+                                              bytes: 269
+                                              line: 10
+                                              character: 58
+                                            token_type:
+                                              type: Symbol
+                                              symbol: ":"
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 269
+                                                line: 10
+                                                character: 58
+                                              end_position:
+                                                bytes: 270
+                                                line: 10
+                                                character: 59
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+                                      type_info:
+                                        Table:
+                                          braces:
+                                            tokens:
+                                              - leading_trivia: []
+                                                token:
+                                                  start_position:
+                                                    bytes: 270
+                                                    line: 10
+                                                    character: 59
+                                                  end_position:
+                                                    bytes: 271
+                                                    line: 10
+                                                    character: 60
+                                                  token_type:
+                                                    type: Symbol
+                                                    symbol: "{"
+                                                trailing_trivia:
+                                                  - start_position:
+                                                      bytes: 271
+                                                      line: 10
+                                                      character: 60
+                                                    end_position:
+                                                      bytes: 272
+                                                      line: 10
+                                                      character: 61
+                                                    token_type:
+                                                      type: Whitespace
+                                                      characters: " "
+                                              - leading_trivia: []
+                                                token:
+                                                  start_position:
+                                                    bytes: 289
+                                                    line: 10
+                                                    character: 78
+                                                  end_position:
+                                                    bytes: 290
+                                                    line: 10
+                                                    character: 79
+                                                  token_type:
+                                                    type: Symbol
+                                                    symbol: "}"
+                                                trailing_trivia: []
+                                          fields:
+                                            pairs:
+                                              - End:
+                                                  key:
+                                                    IndexSignature:
+                                                      brackets:
+                                                        tokens:
+                                                          - leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 272
+                                                                line: 10
+                                                                character: 61
+                                                              end_position:
+                                                                bytes: 273
+                                                                line: 10
+                                                                character: 62
+                                                              token_type:
+                                                                type: Symbol
+                                                                symbol: "["
+                                                            trailing_trivia: []
+                                                          - leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 279
+                                                                line: 10
+                                                                character: 68
+                                                              end_position:
+                                                                bytes: 280
+                                                                line: 10
+                                                                character: 69
+                                                              token_type:
+                                                                type: Symbol
+                                                                symbol: "]"
+                                                            trailing_trivia: []
+                                                      inner:
+                                                        Basic:
+                                                          leading_trivia: []
+                                                          token:
+                                                            start_position:
+                                                              bytes: 273
+                                                              line: 10
+                                                              character: 62
+                                                            end_position:
+                                                              bytes: 279
+                                                              line: 10
+                                                              character: 68
+                                                            token_type:
+                                                              type: Identifier
+                                                              identifier: number
+                                                          trailing_trivia: []
+                                                  colon:
+                                                    leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 280
+                                                        line: 10
+                                                        character: 69
+                                                      end_position:
+                                                        bytes: 281
+                                                        line: 10
+                                                        character: 70
+                                                      token_type:
+                                                        type: Symbol
+                                                        symbol: ":"
+                                                    trailing_trivia:
+                                                      - start_position:
+                                                          bytes: 281
+                                                          line: 10
+                                                          character: 70
+                                                        end_position:
+                                                          bytes: 282
+                                                          line: 10
+                                                          character: 71
+                                                        token_type:
+                                                          type: Whitespace
+                                                          characters: " "
+                                                  value:
+                                                    Basic:
+                                                      leading_trivia: []
+                                                      token:
+                                                        start_position:
+                                                          bytes: 282
+                                                          line: 10
+                                                          character: 71
+                                                        end_position:
+                                                          bytes: 288
+                                                          line: 10
+                                                          character: 77
+                                                        token_type:
+                                                          type: Identifier
+                                                          identifier: string
+                                                      trailing_trivia:
+                                                        - start_position:
+                                                            bytes: 288
+                                                            line: 10
+                                                            character: 77
+                                                          end_position:
+                                                            bytes: 289
+                                                            line: 10
+                                                            character: 78
+                                                          token_type:
+                                                            type: Whitespace
+                                                            characters: " "
+                              arrow:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 292
+                                    line: 10
+                                    character: 81
+                                  end_position:
+                                    bytes: 294
+                                    line: 10
+                                    character: 83
+                                  token_type:
+                                    type: Symbol
+                                    symbol: "->"
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 294
+                                      line: 10
+                                      character: 83
+                                    end_position:
+                                      bytes: 295
+                                      line: 10
+                                      character: 84
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              return_type:
+                                Basic:
+                                  leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 295
+                                      line: 10
+                                      character: 84
+                                    end_position:
+                                      bytes: 298
+                                      line: 10
+                                      character: 87
+                                    token_type:
+                                      type: Identifier
+                                      identifier: any
+                                  trailing_trivia: []
+          block:
+            stmts: []
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 300
+                line: 11
+                character: 1
+              end_position:
+                bytes: 303
+                line: 11
+                character: 4
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia:
+              - start_position:
+                  bytes: 303
+                  line: 11
+                  character: 4
+                end_position:
+                  bytes: 304
+                  line: 11
+                  character: 4
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/named_function_arg_types/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/named_function_arg_types/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8b18eb9fee05aa1057f226f0d772e25d77575833
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/named_function_arg_types/source.lua
@@ -0,0 +1,11 @@
+type MyCallbackType = (cost: number, name: string) -> string
+
+local cb: (amount: number) -> number
+local function foo(cb: (name: string) -> unit)
+end
+
+local function bar(x: number?): (baz: string) -> string
+end
+
+local function bar(x: number?): (baz: string) -> ((names: { [number]: string }) -> any)
+end
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/named_function_arg_types/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/named_function_arg_types/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..be7270ec714eb7f745eec7b53b9d22fe8c9cb969
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/named_function_arg_types/tokens.snap
@@ -0,0 +1,1544 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/roblox_cases/pass/named_function_arg_types
+---
+- 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: 19
+    line: 1
+    character: 20
+  token_type:
+    type: Identifier
+    identifier: MyCallbackType
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- 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: Symbol
+    symbol: (
+- start_position:
+    bytes: 23
+    line: 1
+    character: 24
+  end_position:
+    bytes: 27
+    line: 1
+    character: 28
+  token_type:
+    type: Identifier
+    identifier: cost
+- start_position:
+    bytes: 27
+    line: 1
+    character: 28
+  end_position:
+    bytes: 28
+    line: 1
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 28
+    line: 1
+    character: 29
+  end_position:
+    bytes: 29
+    line: 1
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 29
+    line: 1
+    character: 30
+  end_position:
+    bytes: 35
+    line: 1
+    character: 36
+  token_type:
+    type: Identifier
+    identifier: number
+- 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: 37
+    line: 1
+    character: 38
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 37
+    line: 1
+    character: 38
+  end_position:
+    bytes: 41
+    line: 1
+    character: 42
+  token_type:
+    type: Identifier
+    identifier: name
+- start_position:
+    bytes: 41
+    line: 1
+    character: 42
+  end_position:
+    bytes: 42
+    line: 1
+    character: 43
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 42
+    line: 1
+    character: 43
+  end_position:
+    bytes: 43
+    line: 1
+    character: 44
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 43
+    line: 1
+    character: 44
+  end_position:
+    bytes: 49
+    line: 1
+    character: 50
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 49
+    line: 1
+    character: 50
+  end_position:
+    bytes: 50
+    line: 1
+    character: 51
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 50
+    line: 1
+    character: 51
+  end_position:
+    bytes: 51
+    line: 1
+    character: 52
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 51
+    line: 1
+    character: 52
+  end_position:
+    bytes: 53
+    line: 1
+    character: 54
+  token_type:
+    type: Symbol
+    symbol: "->"
+- start_position:
+    bytes: 53
+    line: 1
+    character: 54
+  end_position:
+    bytes: 54
+    line: 1
+    character: 55
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 54
+    line: 1
+    character: 55
+  end_position:
+    bytes: 60
+    line: 1
+    character: 61
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 60
+    line: 1
+    character: 61
+  end_position:
+    bytes: 61
+    line: 1
+    character: 61
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 61
+    line: 2
+    character: 1
+  end_position:
+    bytes: 62
+    line: 2
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 62
+    line: 3
+    character: 1
+  end_position:
+    bytes: 67
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 67
+    line: 3
+    character: 6
+  end_position:
+    bytes: 68
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 68
+    line: 3
+    character: 7
+  end_position:
+    bytes: 70
+    line: 3
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: cb
+- start_position:
+    bytes: 70
+    line: 3
+    character: 9
+  end_position:
+    bytes: 71
+    line: 3
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 71
+    line: 3
+    character: 10
+  end_position:
+    bytes: 72
+    line: 3
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 72
+    line: 3
+    character: 11
+  end_position:
+    bytes: 73
+    line: 3
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 73
+    line: 3
+    character: 12
+  end_position:
+    bytes: 79
+    line: 3
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: amount
+- start_position:
+    bytes: 79
+    line: 3
+    character: 18
+  end_position:
+    bytes: 80
+    line: 3
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 80
+    line: 3
+    character: 19
+  end_position:
+    bytes: 81
+    line: 3
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 81
+    line: 3
+    character: 20
+  end_position:
+    bytes: 87
+    line: 3
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 87
+    line: 3
+    character: 26
+  end_position:
+    bytes: 88
+    line: 3
+    character: 27
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 88
+    line: 3
+    character: 27
+  end_position:
+    bytes: 89
+    line: 3
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 89
+    line: 3
+    character: 28
+  end_position:
+    bytes: 91
+    line: 3
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: "->"
+- start_position:
+    bytes: 91
+    line: 3
+    character: 30
+  end_position:
+    bytes: 92
+    line: 3
+    character: 31
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 92
+    line: 3
+    character: 31
+  end_position:
+    bytes: 98
+    line: 3
+    character: 37
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 98
+    line: 3
+    character: 37
+  end_position:
+    bytes: 99
+    line: 3
+    character: 37
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 99
+    line: 4
+    character: 1
+  end_position:
+    bytes: 104
+    line: 4
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 104
+    line: 4
+    character: 6
+  end_position:
+    bytes: 105
+    line: 4
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 105
+    line: 4
+    character: 7
+  end_position:
+    bytes: 113
+    line: 4
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: function
+- start_position:
+    bytes: 113
+    line: 4
+    character: 15
+  end_position:
+    bytes: 114
+    line: 4
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 114
+    line: 4
+    character: 16
+  end_position:
+    bytes: 117
+    line: 4
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: foo
+- start_position:
+    bytes: 117
+    line: 4
+    character: 19
+  end_position:
+    bytes: 118
+    line: 4
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 118
+    line: 4
+    character: 20
+  end_position:
+    bytes: 120
+    line: 4
+    character: 22
+  token_type:
+    type: Identifier
+    identifier: cb
+- start_position:
+    bytes: 120
+    line: 4
+    character: 22
+  end_position:
+    bytes: 121
+    line: 4
+    character: 23
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 121
+    line: 4
+    character: 23
+  end_position:
+    bytes: 122
+    line: 4
+    character: 24
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 122
+    line: 4
+    character: 24
+  end_position:
+    bytes: 123
+    line: 4
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 123
+    line: 4
+    character: 25
+  end_position:
+    bytes: 127
+    line: 4
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: name
+- start_position:
+    bytes: 127
+    line: 4
+    character: 29
+  end_position:
+    bytes: 128
+    line: 4
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 128
+    line: 4
+    character: 30
+  end_position:
+    bytes: 129
+    line: 4
+    character: 31
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 129
+    line: 4
+    character: 31
+  end_position:
+    bytes: 135
+    line: 4
+    character: 37
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 135
+    line: 4
+    character: 37
+  end_position:
+    bytes: 136
+    line: 4
+    character: 38
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 136
+    line: 4
+    character: 38
+  end_position:
+    bytes: 137
+    line: 4
+    character: 39
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 137
+    line: 4
+    character: 39
+  end_position:
+    bytes: 139
+    line: 4
+    character: 41
+  token_type:
+    type: Symbol
+    symbol: "->"
+- start_position:
+    bytes: 139
+    line: 4
+    character: 41
+  end_position:
+    bytes: 140
+    line: 4
+    character: 42
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 140
+    line: 4
+    character: 42
+  end_position:
+    bytes: 144
+    line: 4
+    character: 46
+  token_type:
+    type: Identifier
+    identifier: unit
+- start_position:
+    bytes: 144
+    line: 4
+    character: 46
+  end_position:
+    bytes: 145
+    line: 4
+    character: 47
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 145
+    line: 4
+    character: 47
+  end_position:
+    bytes: 146
+    line: 4
+    character: 47
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 146
+    line: 5
+    character: 1
+  end_position:
+    bytes: 149
+    line: 5
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 149
+    line: 5
+    character: 4
+  end_position:
+    bytes: 150
+    line: 5
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 150
+    line: 6
+    character: 1
+  end_position:
+    bytes: 151
+    line: 6
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 151
+    line: 7
+    character: 1
+  end_position:
+    bytes: 156
+    line: 7
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 156
+    line: 7
+    character: 6
+  end_position:
+    bytes: 157
+    line: 7
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 157
+    line: 7
+    character: 7
+  end_position:
+    bytes: 165
+    line: 7
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: function
+- start_position:
+    bytes: 165
+    line: 7
+    character: 15
+  end_position:
+    bytes: 166
+    line: 7
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 166
+    line: 7
+    character: 16
+  end_position:
+    bytes: 169
+    line: 7
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 169
+    line: 7
+    character: 19
+  end_position:
+    bytes: 170
+    line: 7
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 170
+    line: 7
+    character: 20
+  end_position:
+    bytes: 171
+    line: 7
+    character: 21
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 171
+    line: 7
+    character: 21
+  end_position:
+    bytes: 172
+    line: 7
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 172
+    line: 7
+    character: 22
+  end_position:
+    bytes: 173
+    line: 7
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 173
+    line: 7
+    character: 23
+  end_position:
+    bytes: 179
+    line: 7
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 179
+    line: 7
+    character: 29
+  end_position:
+    bytes: 180
+    line: 7
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: "?"
+- start_position:
+    bytes: 180
+    line: 7
+    character: 30
+  end_position:
+    bytes: 181
+    line: 7
+    character: 31
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 181
+    line: 7
+    character: 31
+  end_position:
+    bytes: 182
+    line: 7
+    character: 32
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 182
+    line: 7
+    character: 32
+  end_position:
+    bytes: 183
+    line: 7
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 183
+    line: 7
+    character: 33
+  end_position:
+    bytes: 184
+    line: 7
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 184
+    line: 7
+    character: 34
+  end_position:
+    bytes: 187
+    line: 7
+    character: 37
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 187
+    line: 7
+    character: 37
+  end_position:
+    bytes: 188
+    line: 7
+    character: 38
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 188
+    line: 7
+    character: 38
+  end_position:
+    bytes: 189
+    line: 7
+    character: 39
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 189
+    line: 7
+    character: 39
+  end_position:
+    bytes: 195
+    line: 7
+    character: 45
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 195
+    line: 7
+    character: 45
+  end_position:
+    bytes: 196
+    line: 7
+    character: 46
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 196
+    line: 7
+    character: 46
+  end_position:
+    bytes: 197
+    line: 7
+    character: 47
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 197
+    line: 7
+    character: 47
+  end_position:
+    bytes: 199
+    line: 7
+    character: 49
+  token_type:
+    type: Symbol
+    symbol: "->"
+- start_position:
+    bytes: 199
+    line: 7
+    character: 49
+  end_position:
+    bytes: 200
+    line: 7
+    character: 50
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 200
+    line: 7
+    character: 50
+  end_position:
+    bytes: 206
+    line: 7
+    character: 56
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 206
+    line: 7
+    character: 56
+  end_position:
+    bytes: 207
+    line: 7
+    character: 56
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 207
+    line: 8
+    character: 1
+  end_position:
+    bytes: 210
+    line: 8
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 210
+    line: 8
+    character: 4
+  end_position:
+    bytes: 211
+    line: 8
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 211
+    line: 9
+    character: 1
+  end_position:
+    bytes: 212
+    line: 9
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 212
+    line: 10
+    character: 1
+  end_position:
+    bytes: 217
+    line: 10
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 217
+    line: 10
+    character: 6
+  end_position:
+    bytes: 218
+    line: 10
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 218
+    line: 10
+    character: 7
+  end_position:
+    bytes: 226
+    line: 10
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: function
+- start_position:
+    bytes: 226
+    line: 10
+    character: 15
+  end_position:
+    bytes: 227
+    line: 10
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 227
+    line: 10
+    character: 16
+  end_position:
+    bytes: 230
+    line: 10
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 230
+    line: 10
+    character: 19
+  end_position:
+    bytes: 231
+    line: 10
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 231
+    line: 10
+    character: 20
+  end_position:
+    bytes: 232
+    line: 10
+    character: 21
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 232
+    line: 10
+    character: 21
+  end_position:
+    bytes: 233
+    line: 10
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 233
+    line: 10
+    character: 22
+  end_position:
+    bytes: 234
+    line: 10
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 234
+    line: 10
+    character: 23
+  end_position:
+    bytes: 240
+    line: 10
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 240
+    line: 10
+    character: 29
+  end_position:
+    bytes: 241
+    line: 10
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: "?"
+- start_position:
+    bytes: 241
+    line: 10
+    character: 30
+  end_position:
+    bytes: 242
+    line: 10
+    character: 31
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 242
+    line: 10
+    character: 31
+  end_position:
+    bytes: 243
+    line: 10
+    character: 32
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 243
+    line: 10
+    character: 32
+  end_position:
+    bytes: 244
+    line: 10
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 244
+    line: 10
+    character: 33
+  end_position:
+    bytes: 245
+    line: 10
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 245
+    line: 10
+    character: 34
+  end_position:
+    bytes: 248
+    line: 10
+    character: 37
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 248
+    line: 10
+    character: 37
+  end_position:
+    bytes: 249
+    line: 10
+    character: 38
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 249
+    line: 10
+    character: 38
+  end_position:
+    bytes: 250
+    line: 10
+    character: 39
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 250
+    line: 10
+    character: 39
+  end_position:
+    bytes: 256
+    line: 10
+    character: 45
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 256
+    line: 10
+    character: 45
+  end_position:
+    bytes: 257
+    line: 10
+    character: 46
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 257
+    line: 10
+    character: 46
+  end_position:
+    bytes: 258
+    line: 10
+    character: 47
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 258
+    line: 10
+    character: 47
+  end_position:
+    bytes: 260
+    line: 10
+    character: 49
+  token_type:
+    type: Symbol
+    symbol: "->"
+- start_position:
+    bytes: 260
+    line: 10
+    character: 49
+  end_position:
+    bytes: 261
+    line: 10
+    character: 50
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 261
+    line: 10
+    character: 50
+  end_position:
+    bytes: 262
+    line: 10
+    character: 51
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 262
+    line: 10
+    character: 51
+  end_position:
+    bytes: 263
+    line: 10
+    character: 52
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 263
+    line: 10
+    character: 52
+  end_position:
+    bytes: 268
+    line: 10
+    character: 57
+  token_type:
+    type: Identifier
+    identifier: names
+- start_position:
+    bytes: 268
+    line: 10
+    character: 57
+  end_position:
+    bytes: 269
+    line: 10
+    character: 58
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 269
+    line: 10
+    character: 58
+  end_position:
+    bytes: 270
+    line: 10
+    character: 59
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 270
+    line: 10
+    character: 59
+  end_position:
+    bytes: 271
+    line: 10
+    character: 60
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 271
+    line: 10
+    character: 60
+  end_position:
+    bytes: 272
+    line: 10
+    character: 61
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 272
+    line: 10
+    character: 61
+  end_position:
+    bytes: 273
+    line: 10
+    character: 62
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 273
+    line: 10
+    character: 62
+  end_position:
+    bytes: 279
+    line: 10
+    character: 68
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 279
+    line: 10
+    character: 68
+  end_position:
+    bytes: 280
+    line: 10
+    character: 69
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 280
+    line: 10
+    character: 69
+  end_position:
+    bytes: 281
+    line: 10
+    character: 70
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 281
+    line: 10
+    character: 70
+  end_position:
+    bytes: 282
+    line: 10
+    character: 71
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 282
+    line: 10
+    character: 71
+  end_position:
+    bytes: 288
+    line: 10
+    character: 77
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 288
+    line: 10
+    character: 77
+  end_position:
+    bytes: 289
+    line: 10
+    character: 78
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 289
+    line: 10
+    character: 78
+  end_position:
+    bytes: 290
+    line: 10
+    character: 79
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 290
+    line: 10
+    character: 79
+  end_position:
+    bytes: 291
+    line: 10
+    character: 80
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 291
+    line: 10
+    character: 80
+  end_position:
+    bytes: 292
+    line: 10
+    character: 81
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 292
+    line: 10
+    character: 81
+  end_position:
+    bytes: 294
+    line: 10
+    character: 83
+  token_type:
+    type: Symbol
+    symbol: "->"
+- start_position:
+    bytes: 294
+    line: 10
+    character: 83
+  end_position:
+    bytes: 295
+    line: 10
+    character: 84
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 295
+    line: 10
+    character: 84
+  end_position:
+    bytes: 298
+    line: 10
+    character: 87
+  token_type:
+    type: Identifier
+    identifier: any
+- start_position:
+    bytes: 298
+    line: 10
+    character: 87
+  end_position:
+    bytes: 299
+    line: 10
+    character: 88
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 299
+    line: 10
+    character: 88
+  end_position:
+    bytes: 300
+    line: 10
+    character: 88
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 300
+    line: 11
+    character: 1
+  end_position:
+    bytes: 303
+    line: 11
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 303
+    line: 11
+    character: 4
+  end_position:
+    bytes: 304
+    line: 11
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 304
+    line: 12
+    character: 1
+  end_position:
+    bytes: 304
+    line: 12
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/no_roblox_syntax/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/no_roblox_syntax/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d8d3dfb58b4b5073f1d886a3a657f0d7050a5642
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/no_roblox_syntax/ast.snap
@@ -0,0 +1,5623 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/roblox_cases/pass/no_roblox_syntax
+---
+stmts:
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 0
+                line: 1
+                character: 1
+              end_position:
+                bytes: 97
+                line: 1
+                character: 98
+              token_type:
+                type: SingleLineComment
+                comment: " Taken from https://raw.githubusercontent.com/Kampfkarren/Roblox/master/Modules/LineOfSight.lua"
+            - start_position:
+                bytes: 97
+                line: 1
+                character: 98
+              end_position:
+                bytes: 98
+                line: 1
+                character: 98
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 98
+              line: 2
+              character: 1
+            end_position:
+              bytes: 103
+              line: 2
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 103
+                line: 2
+                character: 6
+              end_position:
+                bytes: 104
+                line: 2
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 104
+                    line: 2
+                    character: 7
+                  end_position:
+                    bytes: 121
+                    line: 2
+                    character: 24
+                  token_type:
+                    type: Identifier
+                    identifier: ReplicatedStorage
+                trailing_trivia:
+                  - start_position:
+                      bytes: 121
+                      line: 2
+                      character: 24
+                    end_position:
+                      bytes: 122
+                      line: 2
+                      character: 25
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 122
+              line: 2
+              character: 25
+            end_position:
+              bytes: 123
+              line: 2
+              character: 26
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 123
+                line: 2
+                character: 26
+              end_position:
+                bytes: 124
+                line: 2
+                character: 27
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                FunctionCall:
+                  prefix:
+                    Name:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 124
+                          line: 2
+                          character: 27
+                        end_position:
+                          bytes: 128
+                          line: 2
+                          character: 31
+                        token_type:
+                          type: Identifier
+                          identifier: game
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        MethodCall:
+                          colon_token:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 128
+                                line: 2
+                                character: 31
+                              end_position:
+                                bytes: 129
+                                line: 2
+                                character: 32
+                              token_type:
+                                type: Symbol
+                                symbol: ":"
+                            trailing_trivia: []
+                          name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 129
+                                line: 2
+                                character: 32
+                              end_position:
+                                bytes: 139
+                                line: 2
+                                character: 42
+                              token_type:
+                                type: Identifier
+                                identifier: GetService
+                            trailing_trivia: []
+                          args:
+                            Parentheses:
+                              parentheses:
+                                tokens:
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 139
+                                        line: 2
+                                        character: 42
+                                      end_position:
+                                        bytes: 140
+                                        line: 2
+                                        character: 43
+                                      token_type:
+                                        type: Symbol
+                                        symbol: (
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 159
+                                        line: 2
+                                        character: 62
+                                      end_position:
+                                        bytes: 160
+                                        line: 2
+                                        character: 63
+                                      token_type:
+                                        type: Symbol
+                                        symbol: )
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 160
+                                          line: 2
+                                          character: 63
+                                        end_position:
+                                          bytes: 161
+                                          line: 2
+                                          character: 63
+                                        token_type:
+                                          type: Whitespace
+                                          characters: "\n"
+                              arguments:
+                                pairs:
+                                  - End:
+                                      String:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 140
+                                            line: 2
+                                            character: 43
+                                          end_position:
+                                            bytes: 159
+                                            line: 2
+                                            character: 62
+                                          token_type:
+                                            type: StringLiteral
+                                            literal: ReplicatedStorage
+                                            quote_type: Double
+                                        trailing_trivia: []
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 161
+              line: 3
+              character: 1
+            end_position:
+              bytes: 166
+              line: 3
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 166
+                line: 3
+                character: 6
+              end_position:
+                bytes: 167
+                line: 3
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 167
+                    line: 3
+                    character: 7
+                  end_position:
+                    bytes: 177
+                    line: 3
+                    character: 17
+                  token_type:
+                    type: Identifier
+                    identifier: RunService
+                trailing_trivia:
+                  - start_position:
+                      bytes: 177
+                      line: 3
+                      character: 17
+                    end_position:
+                      bytes: 178
+                      line: 3
+                      character: 18
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 178
+              line: 3
+              character: 18
+            end_position:
+              bytes: 179
+              line: 3
+              character: 19
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 179
+                line: 3
+                character: 19
+              end_position:
+                bytes: 180
+                line: 3
+                character: 20
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                FunctionCall:
+                  prefix:
+                    Name:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 180
+                          line: 3
+                          character: 20
+                        end_position:
+                          bytes: 184
+                          line: 3
+                          character: 24
+                        token_type:
+                          type: Identifier
+                          identifier: game
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        MethodCall:
+                          colon_token:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 184
+                                line: 3
+                                character: 24
+                              end_position:
+                                bytes: 185
+                                line: 3
+                                character: 25
+                              token_type:
+                                type: Symbol
+                                symbol: ":"
+                            trailing_trivia: []
+                          name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 185
+                                line: 3
+                                character: 25
+                              end_position:
+                                bytes: 195
+                                line: 3
+                                character: 35
+                              token_type:
+                                type: Identifier
+                                identifier: GetService
+                            trailing_trivia: []
+                          args:
+                            Parentheses:
+                              parentheses:
+                                tokens:
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 195
+                                        line: 3
+                                        character: 35
+                                      end_position:
+                                        bytes: 196
+                                        line: 3
+                                        character: 36
+                                      token_type:
+                                        type: Symbol
+                                        symbol: (
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 208
+                                        line: 3
+                                        character: 48
+                                      end_position:
+                                        bytes: 209
+                                        line: 3
+                                        character: 49
+                                      token_type:
+                                        type: Symbol
+                                        symbol: )
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 209
+                                          line: 3
+                                          character: 49
+                                        end_position:
+                                          bytes: 210
+                                          line: 3
+                                          character: 49
+                                        token_type:
+                                          type: Whitespace
+                                          characters: "\n"
+                              arguments:
+                                pairs:
+                                  - End:
+                                      String:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 196
+                                            line: 3
+                                            character: 36
+                                          end_position:
+                                            bytes: 208
+                                            line: 3
+                                            character: 48
+                                          token_type:
+                                            type: StringLiteral
+                                            literal: RunService
+                                            quote_type: Double
+                                        trailing_trivia: []
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 210
+                line: 4
+                character: 1
+              end_position:
+                bytes: 211
+                line: 4
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 211
+              line: 5
+              character: 1
+            end_position:
+              bytes: 216
+              line: 5
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 216
+                line: 5
+                character: 6
+              end_position:
+                bytes: 217
+                line: 5
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 217
+                    line: 5
+                    character: 7
+                  end_position:
+                    bytes: 224
+                    line: 5
+                    character: 14
+                  token_type:
+                    type: Identifier
+                    identifier: Raycast
+                trailing_trivia:
+                  - start_position:
+                      bytes: 224
+                      line: 5
+                      character: 14
+                    end_position:
+                      bytes: 225
+                      line: 5
+                      character: 15
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 225
+              line: 5
+              character: 15
+            end_position:
+              bytes: 226
+              line: 5
+              character: 16
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 226
+                line: 5
+                character: 16
+              end_position:
+                bytes: 227
+                line: 5
+                character: 17
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                FunctionCall:
+                  prefix:
+                    Name:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 227
+                          line: 5
+                          character: 17
+                        end_position:
+                          bytes: 234
+                          line: 5
+                          character: 24
+                        token_type:
+                          type: Identifier
+                          identifier: require
+                      trailing_trivia: []
+                  suffixes:
+                    - Call:
+                        AnonymousCall:
+                          Parentheses:
+                            parentheses:
+                              tokens:
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 234
+                                      line: 5
+                                      character: 24
+                                    end_position:
+                                      bytes: 235
+                                      line: 5
+                                      character: 25
+                                    token_type:
+                                      type: Symbol
+                                      symbol: (
+                                  trailing_trivia: []
+                                - leading_trivia: []
+                                  token:
+                                    start_position:
+                                      bytes: 268
+                                      line: 5
+                                      character: 58
+                                    end_position:
+                                      bytes: 269
+                                      line: 5
+                                      character: 59
+                                    token_type:
+                                      type: Symbol
+                                      symbol: )
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 269
+                                        line: 5
+                                        character: 59
+                                      end_position:
+                                        bytes: 270
+                                        line: 5
+                                        character: 59
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\n"
+                            arguments:
+                              pairs:
+                                - End:
+                                    Var:
+                                      Expression:
+                                        prefix:
+                                          Name:
+                                            leading_trivia: []
+                                            token:
+                                              start_position:
+                                                bytes: 235
+                                                line: 5
+                                                character: 25
+                                              end_position:
+                                                bytes: 252
+                                                line: 5
+                                                character: 42
+                                              token_type:
+                                                type: Identifier
+                                                identifier: ReplicatedStorage
+                                            trailing_trivia: []
+                                        suffixes:
+                                          - Index:
+                                              Dot:
+                                                dot:
+                                                  leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 252
+                                                      line: 5
+                                                      character: 42
+                                                    end_position:
+                                                      bytes: 253
+                                                      line: 5
+                                                      character: 43
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: "."
+                                                  trailing_trivia: []
+                                                name:
+                                                  leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 253
+                                                      line: 5
+                                                      character: 43
+                                                    end_position:
+                                                      bytes: 260
+                                                      line: 5
+                                                      character: 50
+                                                    token_type:
+                                                      type: Identifier
+                                                      identifier: Modules
+                                                  trailing_trivia: []
+                                          - Index:
+                                              Dot:
+                                                dot:
+                                                  leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 260
+                                                      line: 5
+                                                      character: 50
+                                                    end_position:
+                                                      bytes: 261
+                                                      line: 5
+                                                      character: 51
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: "."
+                                                  trailing_trivia: []
+                                                name:
+                                                  leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 261
+                                                      line: 5
+                                                      character: 51
+                                                    end_position:
+                                                      bytes: 268
+                                                      line: 5
+                                                      character: 58
+                                                    token_type:
+                                                      type: Identifier
+                                                      identifier: Raycast
+                                                  trailing_trivia: []
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 270
+                line: 6
+                character: 1
+              end_position:
+                bytes: 271
+                line: 6
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 271
+              line: 7
+              character: 1
+            end_position:
+              bytes: 276
+              line: 7
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 276
+                line: 7
+                character: 6
+              end_position:
+                bytes: 277
+                line: 7
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 277
+                    line: 7
+                    character: 7
+                  end_position:
+                    bytes: 282
+                    line: 7
+                    character: 12
+                  token_type:
+                    type: Identifier
+                    identifier: DEBUG
+                trailing_trivia:
+                  - start_position:
+                      bytes: 282
+                      line: 7
+                      character: 12
+                    end_position:
+                      bytes: 283
+                      line: 7
+                      character: 13
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 283
+              line: 7
+              character: 13
+            end_position:
+              bytes: 284
+              line: 7
+              character: 14
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 284
+                line: 7
+                character: 14
+              end_position:
+                bytes: 285
+                line: 7
+                character: 15
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Symbol:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 285
+                      line: 7
+                      character: 15
+                    end_position:
+                      bytes: 289
+                      line: 7
+                      character: 19
+                    token_type:
+                      type: Symbol
+                      symbol: "true"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 289
+                        line: 7
+                        character: 19
+                      end_position:
+                        bytes: 290
+                        line: 7
+                        character: 19
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - Assignment:
+        var_list:
+          pairs:
+            - End:
+                Name:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 290
+                      line: 8
+                      character: 1
+                    end_position:
+                      bytes: 295
+                      line: 8
+                      character: 6
+                    token_type:
+                      type: Identifier
+                      identifier: DEBUG
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 295
+                        line: 8
+                        character: 6
+                      end_position:
+                        bytes: 296
+                        line: 8
+                        character: 7
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 296
+              line: 8
+              character: 7
+            end_position:
+              bytes: 297
+              line: 8
+              character: 8
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 297
+                line: 8
+                character: 8
+              end_position:
+                bytes: 298
+                line: 8
+                character: 9
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                BinaryOperator:
+                  lhs:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 298
+                            line: 8
+                            character: 9
+                          end_position:
+                            bytes: 303
+                            line: 8
+                            character: 14
+                          token_type:
+                            type: Identifier
+                            identifier: DEBUG
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 303
+                              line: 8
+                              character: 14
+                            end_position:
+                              bytes: 304
+                              line: 8
+                              character: 15
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  binop:
+                    And:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 304
+                          line: 8
+                          character: 15
+                        end_position:
+                          bytes: 307
+                          line: 8
+                          character: 18
+                        token_type:
+                          type: Symbol
+                          symbol: and
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 307
+                            line: 8
+                            character: 18
+                          end_position:
+                            bytes: 308
+                            line: 8
+                            character: 19
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                  rhs:
+                    FunctionCall:
+                      prefix:
+                        Name:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 308
+                              line: 8
+                              character: 19
+                            end_position:
+                              bytes: 318
+                              line: 8
+                              character: 29
+                            token_type:
+                              type: Identifier
+                              identifier: RunService
+                          trailing_trivia: []
+                      suffixes:
+                        - Call:
+                            MethodCall:
+                              colon_token:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 318
+                                    line: 8
+                                    character: 29
+                                  end_position:
+                                    bytes: 319
+                                    line: 8
+                                    character: 30
+                                  token_type:
+                                    type: Symbol
+                                    symbol: ":"
+                                trailing_trivia: []
+                              name:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 319
+                                    line: 8
+                                    character: 30
+                                  end_position:
+                                    bytes: 327
+                                    line: 8
+                                    character: 38
+                                  token_type:
+                                    type: Identifier
+                                    identifier: IsStudio
+                                trailing_trivia: []
+                              args:
+                                Parentheses:
+                                  parentheses:
+                                    tokens:
+                                      - leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 327
+                                            line: 8
+                                            character: 38
+                                          end_position:
+                                            bytes: 328
+                                            line: 8
+                                            character: 39
+                                          token_type:
+                                            type: Symbol
+                                            symbol: (
+                                        trailing_trivia: []
+                                      - leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 328
+                                            line: 8
+                                            character: 39
+                                          end_position:
+                                            bytes: 329
+                                            line: 8
+                                            character: 40
+                                          token_type:
+                                            type: Symbol
+                                            symbol: )
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 329
+                                              line: 8
+                                              character: 40
+                                            end_position:
+                                              bytes: 330
+                                              line: 8
+                                              character: 40
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\n"
+                                  arguments:
+                                    pairs: []
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 330
+                line: 9
+                character: 1
+              end_position:
+                bytes: 331
+                line: 9
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 331
+              line: 10
+              character: 1
+            end_position:
+              bytes: 336
+              line: 10
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 336
+                line: 10
+                character: 6
+              end_position:
+                bytes: 337
+                line: 10
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 337
+                    line: 10
+                    character: 7
+                  end_position:
+                    bytes: 342
+                    line: 10
+                    character: 12
+                  token_type:
+                    type: Identifier
+                    identifier: debug
+                trailing_trivia:
+                  - start_position:
+                      bytes: 342
+                      line: 10
+                      character: 12
+                    end_position:
+                      bytes: 343
+                      line: 10
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+        equal_token: ~
+        expr_list:
+          pairs: []
+    - ~
+  - - If:
+        if_token:
+          leading_trivia:
+            - start_position:
+                bytes: 343
+                line: 11
+                character: 1
+              end_position:
+                bytes: 344
+                line: 11
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 344
+              line: 12
+              character: 1
+            end_position:
+              bytes: 346
+              line: 12
+              character: 3
+            token_type:
+              type: Symbol
+              symbol: if
+          trailing_trivia:
+            - start_position:
+                bytes: 346
+                line: 12
+                character: 3
+              end_position:
+                bytes: 347
+                line: 12
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: " "
+        condition:
+          Var:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 347
+                  line: 12
+                  character: 4
+                end_position:
+                  bytes: 352
+                  line: 12
+                  character: 9
+                token_type:
+                  type: Identifier
+                  identifier: DEBUG
+              trailing_trivia:
+                - start_position:
+                    bytes: 352
+                    line: 12
+                    character: 9
+                  end_position:
+                    bytes: 353
+                    line: 12
+                    character: 10
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+        then_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 353
+              line: 12
+              character: 10
+            end_position:
+              bytes: 357
+              line: 12
+              character: 14
+            token_type:
+              type: Symbol
+              symbol: then
+          trailing_trivia:
+            - start_position:
+                bytes: 357
+                line: 12
+                character: 14
+              end_position:
+                bytes: 358
+                line: 12
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        block:
+          stmts:
+            - - FunctionDeclaration:
+                  function_token:
+                    leading_trivia:
+                      - start_position:
+                          bytes: 358
+                          line: 13
+                          character: 1
+                        end_position:
+                          bytes: 359
+                          line: 13
+                          character: 2
+                        token_type:
+                          type: Whitespace
+                          characters: "\t"
+                    token:
+                      start_position:
+                        bytes: 359
+                        line: 13
+                        character: 2
+                      end_position:
+                        bytes: 367
+                        line: 13
+                        character: 10
+                      token_type:
+                        type: Symbol
+                        symbol: function
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 367
+                          line: 13
+                          character: 10
+                        end_position:
+                          bytes: 368
+                          line: 13
+                          character: 11
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  name:
+                    names:
+                      pairs:
+                        - End:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 368
+                                line: 13
+                                character: 11
+                              end_position:
+                                bytes: 373
+                                line: 13
+                                character: 16
+                              token_type:
+                                type: Identifier
+                                identifier: debug
+                            trailing_trivia: []
+                    colon_name: ~
+                  body:
+                    parameters_parentheses:
+                      tokens:
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 373
+                              line: 13
+                              character: 16
+                            end_position:
+                              bytes: 374
+                              line: 13
+                              character: 17
+                            token_type:
+                              type: Symbol
+                              symbol: (
+                          trailing_trivia: []
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 379
+                              line: 13
+                              character: 22
+                            end_position:
+                              bytes: 380
+                              line: 13
+                              character: 23
+                            token_type:
+                              type: Symbol
+                              symbol: )
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 380
+                                line: 13
+                                character: 23
+                              end_position:
+                                bytes: 381
+                                line: 13
+                                character: 23
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+                    parameters:
+                      pairs:
+                        - End:
+                            name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 374
+                                  line: 13
+                                  character: 17
+                                end_position:
+                                  bytes: 379
+                                  line: 13
+                                  character: 22
+                                token_type:
+                                  type: Identifier
+                                  identifier: table
+                              trailing_trivia: []
+                    type_specifiers:
+                      - ~
+                    block:
+                      stmts:
+                        - - FunctionCall:
+                              prefix:
+                                Name:
+                                  leading_trivia:
+                                    - start_position:
+                                        bytes: 381
+                                        line: 14
+                                        character: 1
+                                      end_position:
+                                        bytes: 383
+                                        line: 14
+                                        character: 3
+                                      token_type:
+                                        type: Whitespace
+                                        characters: "\t\t"
+                                  token:
+                                    start_position:
+                                      bytes: 383
+                                      line: 14
+                                      character: 3
+                                    end_position:
+                                      bytes: 388
+                                      line: 14
+                                      character: 8
+                                    token_type:
+                                      type: Identifier
+                                      identifier: print
+                                  trailing_trivia: []
+                              suffixes:
+                                - Call:
+                                    AnonymousCall:
+                                      Parentheses:
+                                        parentheses:
+                                          tokens:
+                                            - leading_trivia: []
+                                              token:
+                                                start_position:
+                                                  bytes: 388
+                                                  line: 14
+                                                  character: 8
+                                                end_position:
+                                                  bytes: 389
+                                                  line: 14
+                                                  character: 9
+                                                token_type:
+                                                  type: Symbol
+                                                  symbol: (
+                                              trailing_trivia: []
+                                            - leading_trivia: []
+                                              token:
+                                                start_position:
+                                                  bytes: 411
+                                                  line: 14
+                                                  character: 31
+                                                end_position:
+                                                  bytes: 412
+                                                  line: 14
+                                                  character: 32
+                                                token_type:
+                                                  type: Symbol
+                                                  symbol: )
+                                              trailing_trivia:
+                                                - start_position:
+                                                    bytes: 412
+                                                    line: 14
+                                                    character: 32
+                                                  end_position:
+                                                    bytes: 413
+                                                    line: 14
+                                                    character: 32
+                                                  token_type:
+                                                    type: Whitespace
+                                                    characters: "\n"
+                                        arguments:
+                                          pairs:
+                                            - Punctuated:
+                                                - String:
+                                                    leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 389
+                                                        line: 14
+                                                        character: 9
+                                                      end_position:
+                                                        bytes: 404
+                                                        line: 14
+                                                        character: 24
+                                                      token_type:
+                                                        type: StringLiteral
+                                                        literal: "[LineOfSight]"
+                                                        quote_type: Double
+                                                    trailing_trivia: []
+                                                - leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 404
+                                                      line: 14
+                                                      character: 24
+                                                    end_position:
+                                                      bytes: 405
+                                                      line: 14
+                                                      character: 25
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: ","
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 405
+                                                        line: 14
+                                                        character: 25
+                                                      end_position:
+                                                        bytes: 406
+                                                        line: 14
+                                                        character: 26
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: " "
+                                            - End:
+                                                Var:
+                                                  Name:
+                                                    leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 406
+                                                        line: 14
+                                                        character: 26
+                                                      end_position:
+                                                        bytes: 411
+                                                        line: 14
+                                                        character: 31
+                                                      token_type:
+                                                        type: Identifier
+                                                        identifier: table
+                                                    trailing_trivia: []
+                          - ~
+                    end_token:
+                      leading_trivia:
+                        - start_position:
+                            bytes: 413
+                            line: 15
+                            character: 1
+                          end_position:
+                            bytes: 414
+                            line: 15
+                            character: 2
+                          token_type:
+                            type: Whitespace
+                            characters: "\t"
+                      token:
+                        start_position:
+                          bytes: 414
+                          line: 15
+                          character: 2
+                        end_position:
+                          bytes: 417
+                          line: 15
+                          character: 5
+                        token_type:
+                          type: Symbol
+                          symbol: end
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 417
+                            line: 15
+                            character: 5
+                          end_position:
+                            bytes: 418
+                            line: 15
+                            character: 5
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+              - ~
+        else_if: ~
+        else_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 418
+              line: 16
+              character: 1
+            end_position:
+              bytes: 422
+              line: 16
+              character: 5
+            token_type:
+              type: Symbol
+              symbol: else
+          trailing_trivia:
+            - start_position:
+                bytes: 422
+                line: 16
+                character: 5
+              end_position:
+                bytes: 423
+                line: 16
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        else:
+          stmts:
+            - - FunctionDeclaration:
+                  function_token:
+                    leading_trivia:
+                      - start_position:
+                          bytes: 423
+                          line: 17
+                          character: 1
+                        end_position:
+                          bytes: 424
+                          line: 17
+                          character: 2
+                        token_type:
+                          type: Whitespace
+                          characters: "\t"
+                    token:
+                      start_position:
+                        bytes: 424
+                        line: 17
+                        character: 2
+                      end_position:
+                        bytes: 432
+                        line: 17
+                        character: 10
+                      token_type:
+                        type: Symbol
+                        symbol: function
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 432
+                          line: 17
+                          character: 10
+                        end_position:
+                          bytes: 433
+                          line: 17
+                          character: 11
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  name:
+                    names:
+                      pairs:
+                        - End:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 433
+                                line: 17
+                                character: 11
+                              end_position:
+                                bytes: 438
+                                line: 17
+                                character: 16
+                              token_type:
+                                type: Identifier
+                                identifier: debug
+                            trailing_trivia: []
+                    colon_name: ~
+                  body:
+                    parameters_parentheses:
+                      tokens:
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 438
+                              line: 17
+                              character: 16
+                            end_position:
+                              bytes: 439
+                              line: 17
+                              character: 17
+                            token_type:
+                              type: Symbol
+                              symbol: (
+                          trailing_trivia: []
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 439
+                              line: 17
+                              character: 17
+                            end_position:
+                              bytes: 440
+                              line: 17
+                              character: 18
+                            token_type:
+                              type: Symbol
+                              symbol: )
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 440
+                                line: 17
+                                character: 18
+                              end_position:
+                                bytes: 441
+                                line: 17
+                                character: 18
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+                    parameters:
+                      pairs: []
+                    type_specifiers: []
+                    block:
+                      stmts: []
+                    end_token:
+                      leading_trivia:
+                        - start_position:
+                            bytes: 441
+                            line: 18
+                            character: 1
+                          end_position:
+                            bytes: 442
+                            line: 18
+                            character: 2
+                          token_type:
+                            type: Whitespace
+                            characters: "\t"
+                      token:
+                        start_position:
+                          bytes: 442
+                          line: 18
+                          character: 2
+                        end_position:
+                          bytes: 445
+                          line: 18
+                          character: 5
+                        token_type:
+                          type: Symbol
+                          symbol: end
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 445
+                            line: 18
+                            character: 5
+                          end_position:
+                            bytes: 446
+                            line: 18
+                            character: 5
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+              - ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 446
+              line: 19
+              character: 1
+            end_position:
+              bytes: 449
+              line: 19
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 449
+                line: 19
+                character: 4
+              end_position:
+                bytes: 450
+                line: 19
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
+last_stmt:
+  - Return:
+      token:
+        leading_trivia:
+          - start_position:
+              bytes: 450
+              line: 20
+              character: 1
+            end_position:
+              bytes: 451
+              line: 20
+              character: 1
+            token_type:
+              type: Whitespace
+              characters: "\n"
+        token:
+          start_position:
+            bytes: 451
+            line: 21
+            character: 1
+          end_position:
+            bytes: 457
+            line: 21
+            character: 7
+          token_type:
+            type: Symbol
+            symbol: return
+        trailing_trivia:
+          - start_position:
+              bytes: 457
+              line: 21
+              character: 7
+            end_position:
+              bytes: 458
+              line: 21
+              character: 8
+            token_type:
+              type: Whitespace
+              characters: " "
+      returns:
+        pairs:
+          - End:
+              Function:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 458
+                      line: 21
+                      character: 8
+                    end_position:
+                      bytes: 466
+                      line: 21
+                      character: 16
+                    token_type:
+                      type: Symbol
+                      symbol: function
+                  trailing_trivia: []
+                - parameters_parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 466
+                            line: 21
+                            character: 16
+                          end_position:
+                            bytes: 467
+                            line: 21
+                            character: 17
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 512
+                            line: 21
+                            character: 62
+                          end_position:
+                            bytes: 513
+                            line: 21
+                            character: 63
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 513
+                              line: 21
+                              character: 63
+                            end_position:
+                              bytes: 514
+                              line: 21
+                              character: 63
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+                  parameters:
+                    pairs:
+                      - Punctuated:
+                          - name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 467
+                                  line: 21
+                                  character: 17
+                                end_position:
+                                  bytes: 473
+                                  line: 21
+                                  character: 23
+                                token_type:
+                                  type: Identifier
+                                  identifier: origin
+                              trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 473
+                                line: 21
+                                character: 23
+                              end_position:
+                                bytes: 474
+                                line: 21
+                                character: 24
+                              token_type:
+                                type: Symbol
+                                symbol: ","
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 474
+                                  line: 21
+                                  character: 24
+                                end_position:
+                                  bytes: 475
+                                  line: 21
+                                  character: 25
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      - Punctuated:
+                          - name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 475
+                                  line: 21
+                                  character: 25
+                                end_position:
+                                  bytes: 484
+                                  line: 21
+                                  character: 34
+                                token_type:
+                                  type: Identifier
+                                  identifier: character
+                              trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 484
+                                line: 21
+                                character: 34
+                              end_position:
+                                bytes: 485
+                                line: 21
+                                character: 35
+                              token_type:
+                                type: Symbol
+                                symbol: ","
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 485
+                                  line: 21
+                                  character: 35
+                                end_position:
+                                  bytes: 486
+                                  line: 21
+                                  character: 36
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      - Punctuated:
+                          - name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 486
+                                  line: 21
+                                  character: 36
+                                end_position:
+                                  bytes: 491
+                                  line: 21
+                                  character: 41
+                                token_type:
+                                  type: Identifier
+                                  identifier: range
+                              trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 491
+                                line: 21
+                                character: 41
+                              end_position:
+                                bytes: 492
+                                line: 21
+                                character: 42
+                              token_type:
+                                type: Symbol
+                                symbol: ","
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 492
+                                  line: 21
+                                  character: 42
+                                end_position:
+                                  bytes: 493
+                                  line: 21
+                                  character: 43
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      - Punctuated:
+                          - name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 493
+                                  line: 21
+                                  character: 43
+                                end_position:
+                                  bytes: 501
+                                  line: 21
+                                  character: 51
+                                token_type:
+                                  type: Identifier
+                                  identifier: ignoreIf
+                              trailing_trivia: []
+                          - leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 501
+                                line: 21
+                                character: 51
+                              end_position:
+                                bytes: 502
+                                line: 21
+                                character: 52
+                              token_type:
+                                type: Symbol
+                                symbol: ","
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 502
+                                  line: 21
+                                  character: 52
+                                end_position:
+                                  bytes: 503
+                                  line: 21
+                                  character: 53
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                      - End:
+                          name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 503
+                                line: 21
+                                character: 53
+                              end_position:
+                                bytes: 512
+                                line: 21
+                                character: 62
+                              token_type:
+                                type: Identifier
+                                identifier: blacklist
+                            trailing_trivia: []
+                  type_specifiers:
+                    - ~
+                    - ~
+                    - ~
+                    - ~
+                    - ~
+                  block:
+                    stmts:
+                      - - If:
+                            if_token:
+                              leading_trivia:
+                                - start_position:
+                                    bytes: 514
+                                    line: 22
+                                    character: 1
+                                  end_position:
+                                    bytes: 515
+                                    line: 22
+                                    character: 2
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\t"
+                              token:
+                                start_position:
+                                  bytes: 515
+                                  line: 22
+                                  character: 2
+                                end_position:
+                                  bytes: 517
+                                  line: 22
+                                  character: 4
+                                token_type:
+                                  type: Symbol
+                                  symbol: if
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 517
+                                    line: 22
+                                    character: 4
+                                  end_position:
+                                    bytes: 518
+                                    line: 22
+                                    character: 5
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            condition:
+                              BinaryOperator:
+                                lhs:
+                                  FunctionCall:
+                                    prefix:
+                                      Name:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 518
+                                            line: 22
+                                            character: 5
+                                          end_position:
+                                            bytes: 524
+                                            line: 22
+                                            character: 11
+                                          token_type:
+                                            type: Identifier
+                                            identifier: typeof
+                                        trailing_trivia: []
+                                    suffixes:
+                                      - Call:
+                                          AnonymousCall:
+                                            Parentheses:
+                                              parentheses:
+                                                tokens:
+                                                  - leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 524
+                                                        line: 22
+                                                        character: 11
+                                                      end_position:
+                                                        bytes: 525
+                                                        line: 22
+                                                        character: 12
+                                                      token_type:
+                                                        type: Symbol
+                                                        symbol: (
+                                                    trailing_trivia: []
+                                                  - leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 531
+                                                        line: 22
+                                                        character: 18
+                                                      end_position:
+                                                        bytes: 532
+                                                        line: 22
+                                                        character: 19
+                                                      token_type:
+                                                        type: Symbol
+                                                        symbol: )
+                                                    trailing_trivia:
+                                                      - start_position:
+                                                          bytes: 532
+                                                          line: 22
+                                                          character: 19
+                                                        end_position:
+                                                          bytes: 533
+                                                          line: 22
+                                                          character: 20
+                                                        token_type:
+                                                          type: Whitespace
+                                                          characters: " "
+                                              arguments:
+                                                pairs:
+                                                  - End:
+                                                      Var:
+                                                        Name:
+                                                          leading_trivia: []
+                                                          token:
+                                                            start_position:
+                                                              bytes: 525
+                                                              line: 22
+                                                              character: 12
+                                                            end_position:
+                                                              bytes: 531
+                                                              line: 22
+                                                              character: 18
+                                                            token_type:
+                                                              type: Identifier
+                                                              identifier: origin
+                                                          trailing_trivia: []
+                                binop:
+                                  TwoEqual:
+                                    leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 533
+                                        line: 22
+                                        character: 20
+                                      end_position:
+                                        bytes: 535
+                                        line: 22
+                                        character: 22
+                                      token_type:
+                                        type: Symbol
+                                        symbol: "=="
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 535
+                                          line: 22
+                                          character: 22
+                                        end_position:
+                                          bytes: 536
+                                          line: 22
+                                          character: 23
+                                        token_type:
+                                          type: Whitespace
+                                          characters: " "
+                                rhs:
+                                  String:
+                                    leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 536
+                                        line: 22
+                                        character: 23
+                                      end_position:
+                                        bytes: 546
+                                        line: 22
+                                        character: 33
+                                      token_type:
+                                        type: StringLiteral
+                                        literal: Instance
+                                        quote_type: Double
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 546
+                                          line: 22
+                                          character: 33
+                                        end_position:
+                                          bytes: 547
+                                          line: 22
+                                          character: 34
+                                        token_type:
+                                          type: Whitespace
+                                          characters: " "
+                            then_token:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 547
+                                  line: 22
+                                  character: 34
+                                end_position:
+                                  bytes: 551
+                                  line: 22
+                                  character: 38
+                                token_type:
+                                  type: Symbol
+                                  symbol: then
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 551
+                                    line: 22
+                                    character: 38
+                                  end_position:
+                                    bytes: 552
+                                    line: 22
+                                    character: 38
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\n"
+                            block:
+                              stmts:
+                                - - If:
+                                      if_token:
+                                        leading_trivia:
+                                          - start_position:
+                                              bytes: 552
+                                              line: 23
+                                              character: 1
+                                            end_position:
+                                              bytes: 554
+                                              line: 23
+                                              character: 3
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\t\t"
+                                        token:
+                                          start_position:
+                                            bytes: 554
+                                            line: 23
+                                            character: 3
+                                          end_position:
+                                            bytes: 556
+                                            line: 23
+                                            character: 5
+                                          token_type:
+                                            type: Symbol
+                                            symbol: if
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 556
+                                              line: 23
+                                              character: 5
+                                            end_position:
+                                              bytes: 557
+                                              line: 23
+                                              character: 6
+                                            token_type:
+                                              type: Whitespace
+                                              characters: " "
+                                      condition:
+                                        FunctionCall:
+                                          prefix:
+                                            Name:
+                                              leading_trivia: []
+                                              token:
+                                                start_position:
+                                                  bytes: 557
+                                                  line: 23
+                                                  character: 6
+                                                end_position:
+                                                  bytes: 563
+                                                  line: 23
+                                                  character: 12
+                                                token_type:
+                                                  type: Identifier
+                                                  identifier: origin
+                                              trailing_trivia: []
+                                          suffixes:
+                                            - Index:
+                                                Dot:
+                                                  dot:
+                                                    leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 563
+                                                        line: 23
+                                                        character: 12
+                                                      end_position:
+                                                        bytes: 564
+                                                        line: 23
+                                                        character: 13
+                                                      token_type:
+                                                        type: Symbol
+                                                        symbol: "."
+                                                    trailing_trivia: []
+                                                  name:
+                                                    leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 564
+                                                        line: 23
+                                                        character: 13
+                                                      end_position:
+                                                        bytes: 572
+                                                        line: 23
+                                                        character: 21
+                                                      token_type:
+                                                        type: Identifier
+                                                        identifier: Position
+                                                    trailing_trivia: []
+                                            - Call:
+                                                MethodCall:
+                                                  colon_token:
+                                                    leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 572
+                                                        line: 23
+                                                        character: 21
+                                                      end_position:
+                                                        bytes: 573
+                                                        line: 23
+                                                        character: 22
+                                                      token_type:
+                                                        type: Symbol
+                                                        symbol: ":"
+                                                    trailing_trivia: []
+                                                  name:
+                                                    leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 573
+                                                        line: 23
+                                                        character: 22
+                                                      end_position:
+                                                        bytes: 580
+                                                        line: 23
+                                                        character: 29
+                                                      token_type:
+                                                        type: Identifier
+                                                        identifier: FuzzyEq
+                                                    trailing_trivia: []
+                                                  args:
+                                                    Parentheses:
+                                                      parentheses:
+                                                        tokens:
+                                                          - leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 580
+                                                                line: 23
+                                                                character: 29
+                                                              end_position:
+                                                                bytes: 581
+                                                                line: 23
+                                                                character: 30
+                                                              token_type:
+                                                                type: Symbol
+                                                                symbol: (
+                                                            trailing_trivia: []
+                                                          - leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 611
+                                                                line: 23
+                                                                character: 60
+                                                              end_position:
+                                                                bytes: 612
+                                                                line: 23
+                                                                character: 61
+                                                              token_type:
+                                                                type: Symbol
+                                                                symbol: )
+                                                            trailing_trivia:
+                                                              - start_position:
+                                                                  bytes: 612
+                                                                  line: 23
+                                                                  character: 61
+                                                                end_position:
+                                                                  bytes: 613
+                                                                  line: 23
+                                                                  character: 62
+                                                                token_type:
+                                                                  type: Whitespace
+                                                                  characters: " "
+                                                      arguments:
+                                                        pairs:
+                                                          - End:
+                                                              Var:
+                                                                Expression:
+                                                                  prefix:
+                                                                    Name:
+                                                                      leading_trivia: []
+                                                                      token:
+                                                                        start_position:
+                                                                          bytes: 581
+                                                                          line: 23
+                                                                          character: 30
+                                                                        end_position:
+                                                                          bytes: 590
+                                                                          line: 23
+                                                                          character: 39
+                                                                        token_type:
+                                                                          type: Identifier
+                                                                          identifier: character
+                                                                      trailing_trivia: []
+                                                                  suffixes:
+                                                                    - Index:
+                                                                        Dot:
+                                                                          dot:
+                                                                            leading_trivia: []
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 590
+                                                                                line: 23
+                                                                                character: 39
+                                                                              end_position:
+                                                                                bytes: 591
+                                                                                line: 23
+                                                                                character: 40
+                                                                              token_type:
+                                                                                type: Symbol
+                                                                                symbol: "."
+                                                                            trailing_trivia: []
+                                                                          name:
+                                                                            leading_trivia: []
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 591
+                                                                                line: 23
+                                                                                character: 40
+                                                                              end_position:
+                                                                                bytes: 602
+                                                                                line: 23
+                                                                                character: 51
+                                                                              token_type:
+                                                                                type: Identifier
+                                                                                identifier: PrimaryPart
+                                                                            trailing_trivia: []
+                                                                    - Index:
+                                                                        Dot:
+                                                                          dot:
+                                                                            leading_trivia: []
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 602
+                                                                                line: 23
+                                                                                character: 51
+                                                                              end_position:
+                                                                                bytes: 603
+                                                                                line: 23
+                                                                                character: 52
+                                                                              token_type:
+                                                                                type: Symbol
+                                                                                symbol: "."
+                                                                            trailing_trivia: []
+                                                                          name:
+                                                                            leading_trivia: []
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 603
+                                                                                line: 23
+                                                                                character: 52
+                                                                              end_position:
+                                                                                bytes: 611
+                                                                                line: 23
+                                                                                character: 60
+                                                                              token_type:
+                                                                                type: Identifier
+                                                                                identifier: Position
+                                                                            trailing_trivia: []
+                                      then_token:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 613
+                                            line: 23
+                                            character: 62
+                                          end_position:
+                                            bytes: 617
+                                            line: 23
+                                            character: 66
+                                          token_type:
+                                            type: Symbol
+                                            symbol: then
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 617
+                                              line: 23
+                                              character: 66
+                                            end_position:
+                                              bytes: 618
+                                              line: 23
+                                              character: 66
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\n"
+                                      block:
+                                        stmts:
+                                          - - FunctionCall:
+                                                prefix:
+                                                  Name:
+                                                    leading_trivia:
+                                                      - start_position:
+                                                          bytes: 618
+                                                          line: 24
+                                                          character: 1
+                                                        end_position:
+                                                          bytes: 621
+                                                          line: 24
+                                                          character: 4
+                                                        token_type:
+                                                          type: Whitespace
+                                                          characters: "\t\t\t"
+                                                    token:
+                                                      start_position:
+                                                        bytes: 621
+                                                        line: 24
+                                                        character: 4
+                                                      end_position:
+                                                        bytes: 626
+                                                        line: 24
+                                                        character: 9
+                                                      token_type:
+                                                        type: Identifier
+                                                        identifier: debug
+                                                    trailing_trivia: []
+                                                suffixes:
+                                                  - Call:
+                                                      AnonymousCall:
+                                                        Parentheses:
+                                                          parentheses:
+                                                            tokens:
+                                                              - leading_trivia: []
+                                                                token:
+                                                                  start_position:
+                                                                    bytes: 626
+                                                                    line: 24
+                                                                    character: 9
+                                                                  end_position:
+                                                                    bytes: 627
+                                                                    line: 24
+                                                                    character: 10
+                                                                  token_type:
+                                                                    type: Symbol
+                                                                    symbol: (
+                                                                trailing_trivia: []
+                                                              - leading_trivia: []
+                                                                token:
+                                                                  start_position:
+                                                                    bytes: 649
+                                                                    line: 24
+                                                                    character: 32
+                                                                  end_position:
+                                                                    bytes: 650
+                                                                    line: 24
+                                                                    character: 33
+                                                                  token_type:
+                                                                    type: Symbol
+                                                                    symbol: )
+                                                                trailing_trivia:
+                                                                  - start_position:
+                                                                      bytes: 650
+                                                                      line: 24
+                                                                      character: 33
+                                                                    end_position:
+                                                                      bytes: 651
+                                                                      line: 24
+                                                                      character: 33
+                                                                    token_type:
+                                                                      type: Whitespace
+                                                                      characters: "\n"
+                                                          arguments:
+                                                            pairs:
+                                                              - End:
+                                                                  String:
+                                                                    leading_trivia: []
+                                                                    token:
+                                                                      start_position:
+                                                                        bytes: 627
+                                                                        line: 24
+                                                                        character: 10
+                                                                      end_position:
+                                                                        bytes: 649
+                                                                        line: 24
+                                                                        character: 32
+                                                                      token_type:
+                                                                        type: StringLiteral
+                                                                        literal: ORIGIN WAS CHARACTER
+                                                                        quote_type: Double
+                                                                    trailing_trivia: []
+                                            - ~
+                                        last_stmt:
+                                          - Return:
+                                              token:
+                                                leading_trivia:
+                                                  - start_position:
+                                                      bytes: 651
+                                                      line: 25
+                                                      character: 1
+                                                    end_position:
+                                                      bytes: 654
+                                                      line: 25
+                                                      character: 4
+                                                    token_type:
+                                                      type: Whitespace
+                                                      characters: "\t\t\t"
+                                                token:
+                                                  start_position:
+                                                    bytes: 654
+                                                    line: 25
+                                                    character: 4
+                                                  end_position:
+                                                    bytes: 660
+                                                    line: 25
+                                                    character: 10
+                                                  token_type:
+                                                    type: Symbol
+                                                    symbol: return
+                                                trailing_trivia:
+                                                  - start_position:
+                                                      bytes: 660
+                                                      line: 25
+                                                      character: 10
+                                                    end_position:
+                                                      bytes: 661
+                                                      line: 25
+                                                      character: 11
+                                                    token_type:
+                                                      type: Whitespace
+                                                      characters: " "
+                                              returns:
+                                                pairs:
+                                                  - Punctuated:
+                                                      - Var:
+                                                          Name:
+                                                            leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 661
+                                                                line: 25
+                                                                character: 11
+                                                              end_position:
+                                                                bytes: 667
+                                                                line: 25
+                                                                character: 17
+                                                              token_type:
+                                                                type: Identifier
+                                                                identifier: origin
+                                                            trailing_trivia: []
+                                                      - leading_trivia: []
+                                                        token:
+                                                          start_position:
+                                                            bytes: 667
+                                                            line: 25
+                                                            character: 17
+                                                          end_position:
+                                                            bytes: 668
+                                                            line: 25
+                                                            character: 18
+                                                          token_type:
+                                                            type: Symbol
+                                                            symbol: ","
+                                                        trailing_trivia:
+                                                          - start_position:
+                                                              bytes: 668
+                                                              line: 25
+                                                              character: 18
+                                                            end_position:
+                                                              bytes: 669
+                                                              line: 25
+                                                              character: 19
+                                                            token_type:
+                                                              type: Whitespace
+                                                              characters: " "
+                                                  - End:
+                                                      Var:
+                                                        Expression:
+                                                          prefix:
+                                                            Name:
+                                                              leading_trivia: []
+                                                              token:
+                                                                start_position:
+                                                                  bytes: 669
+                                                                  line: 25
+                                                                  character: 19
+                                                                end_position:
+                                                                  bytes: 675
+                                                                  line: 25
+                                                                  character: 25
+                                                                token_type:
+                                                                  type: Identifier
+                                                                  identifier: origin
+                                                              trailing_trivia: []
+                                                          suffixes:
+                                                            - Index:
+                                                                Dot:
+                                                                  dot:
+                                                                    leading_trivia: []
+                                                                    token:
+                                                                      start_position:
+                                                                        bytes: 675
+                                                                        line: 25
+                                                                        character: 25
+                                                                      end_position:
+                                                                        bytes: 676
+                                                                        line: 25
+                                                                        character: 26
+                                                                      token_type:
+                                                                        type: Symbol
+                                                                        symbol: "."
+                                                                    trailing_trivia: []
+                                                                  name:
+                                                                    leading_trivia: []
+                                                                    token:
+                                                                      start_position:
+                                                                        bytes: 676
+                                                                        line: 25
+                                                                        character: 26
+                                                                      end_position:
+                                                                        bytes: 684
+                                                                        line: 25
+                                                                        character: 34
+                                                                      token_type:
+                                                                        type: Identifier
+                                                                        identifier: Position
+                                                                    trailing_trivia:
+                                                                      - start_position:
+                                                                          bytes: 684
+                                                                          line: 25
+                                                                          character: 34
+                                                                        end_position:
+                                                                          bytes: 685
+                                                                          line: 25
+                                                                          character: 34
+                                                                        token_type:
+                                                                          type: Whitespace
+                                                                          characters: "\n"
+                                          - ~
+                                      else_if: ~
+                                      else_token: ~
+                                      else: ~
+                                      end_token:
+                                        leading_trivia:
+                                          - start_position:
+                                              bytes: 685
+                                              line: 26
+                                              character: 1
+                                            end_position:
+                                              bytes: 687
+                                              line: 26
+                                              character: 3
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\t\t"
+                                        token:
+                                          start_position:
+                                            bytes: 687
+                                            line: 26
+                                            character: 3
+                                          end_position:
+                                            bytes: 690
+                                            line: 26
+                                            character: 6
+                                          token_type:
+                                            type: Symbol
+                                            symbol: end
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 690
+                                              line: 26
+                                              character: 6
+                                            end_position:
+                                              bytes: 691
+                                              line: 26
+                                              character: 6
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\n"
+                                  - ~
+                                - - Assignment:
+                                      var_list:
+                                        pairs:
+                                          - End:
+                                              Name:
+                                                leading_trivia:
+                                                  - start_position:
+                                                      bytes: 691
+                                                      line: 27
+                                                      character: 1
+                                                    end_position:
+                                                      bytes: 692
+                                                      line: 27
+                                                      character: 1
+                                                    token_type:
+                                                      type: Whitespace
+                                                      characters: "\n"
+                                                  - start_position:
+                                                      bytes: 692
+                                                      line: 28
+                                                      character: 1
+                                                    end_position:
+                                                      bytes: 694
+                                                      line: 28
+                                                      character: 3
+                                                    token_type:
+                                                      type: Whitespace
+                                                      characters: "\t\t"
+                                                token:
+                                                  start_position:
+                                                    bytes: 694
+                                                    line: 28
+                                                    character: 3
+                                                  end_position:
+                                                    bytes: 700
+                                                    line: 28
+                                                    character: 9
+                                                  token_type:
+                                                    type: Identifier
+                                                    identifier: origin
+                                                trailing_trivia:
+                                                  - start_position:
+                                                      bytes: 700
+                                                      line: 28
+                                                      character: 9
+                                                    end_position:
+                                                      bytes: 701
+                                                      line: 28
+                                                      character: 10
+                                                    token_type:
+                                                      type: Whitespace
+                                                      characters: " "
+                                      equal_token:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 701
+                                            line: 28
+                                            character: 10
+                                          end_position:
+                                            bytes: 702
+                                            line: 28
+                                            character: 11
+                                          token_type:
+                                            type: Symbol
+                                            symbol: "="
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 702
+                                              line: 28
+                                              character: 11
+                                            end_position:
+                                              bytes: 703
+                                              line: 28
+                                              character: 12
+                                            token_type:
+                                              type: Whitespace
+                                              characters: " "
+                                      expr_list:
+                                        pairs:
+                                          - End:
+                                              Var:
+                                                Expression:
+                                                  prefix:
+                                                    Name:
+                                                      leading_trivia: []
+                                                      token:
+                                                        start_position:
+                                                          bytes: 703
+                                                          line: 28
+                                                          character: 12
+                                                        end_position:
+                                                          bytes: 709
+                                                          line: 28
+                                                          character: 18
+                                                        token_type:
+                                                          type: Identifier
+                                                          identifier: origin
+                                                      trailing_trivia: []
+                                                  suffixes:
+                                                    - Index:
+                                                        Dot:
+                                                          dot:
+                                                            leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 709
+                                                                line: 28
+                                                                character: 18
+                                                              end_position:
+                                                                bytes: 710
+                                                                line: 28
+                                                                character: 19
+                                                              token_type:
+                                                                type: Symbol
+                                                                symbol: "."
+                                                            trailing_trivia: []
+                                                          name:
+                                                            leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 710
+                                                                line: 28
+                                                                character: 19
+                                                              end_position:
+                                                                bytes: 718
+                                                                line: 28
+                                                                character: 27
+                                                              token_type:
+                                                                type: Identifier
+                                                                identifier: Position
+                                                            trailing_trivia:
+                                                              - start_position:
+                                                                  bytes: 718
+                                                                  line: 28
+                                                                  character: 27
+                                                                end_position:
+                                                                  bytes: 719
+                                                                  line: 28
+                                                                  character: 27
+                                                                token_type:
+                                                                  type: Whitespace
+                                                                  characters: "\n"
+                                  - ~
+                            else_if: ~
+                            else_token: ~
+                            else: ~
+                            end_token:
+                              leading_trivia:
+                                - start_position:
+                                    bytes: 719
+                                    line: 29
+                                    character: 1
+                                  end_position:
+                                    bytes: 720
+                                    line: 29
+                                    character: 2
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\t"
+                              token:
+                                start_position:
+                                  bytes: 720
+                                  line: 29
+                                  character: 2
+                                end_position:
+                                  bytes: 723
+                                  line: 29
+                                  character: 5
+                                token_type:
+                                  type: Symbol
+                                  symbol: end
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 723
+                                    line: 29
+                                    character: 5
+                                  end_position:
+                                    bytes: 724
+                                    line: 29
+                                    character: 5
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\n"
+                        - ~
+                      - - Assignment:
+                            var_list:
+                              pairs:
+                                - End:
+                                    Name:
+                                      leading_trivia:
+                                        - start_position:
+                                            bytes: 724
+                                            line: 30
+                                            character: 1
+                                          end_position:
+                                            bytes: 725
+                                            line: 30
+                                            character: 1
+                                          token_type:
+                                            type: Whitespace
+                                            characters: "\n"
+                                        - start_position:
+                                            bytes: 725
+                                            line: 31
+                                            character: 1
+                                          end_position:
+                                            bytes: 726
+                                            line: 31
+                                            character: 2
+                                          token_type:
+                                            type: Whitespace
+                                            characters: "\t"
+                                      token:
+                                        start_position:
+                                          bytes: 726
+                                          line: 31
+                                          character: 2
+                                        end_position:
+                                          bytes: 735
+                                          line: 31
+                                          character: 11
+                                        token_type:
+                                          type: Identifier
+                                          identifier: blacklist
+                                      trailing_trivia:
+                                        - start_position:
+                                            bytes: 735
+                                            line: 31
+                                            character: 11
+                                          end_position:
+                                            bytes: 736
+                                            line: 31
+                                            character: 12
+                                          token_type:
+                                            type: Whitespace
+                                            characters: " "
+                            equal_token:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 736
+                                  line: 31
+                                  character: 12
+                                end_position:
+                                  bytes: 737
+                                  line: 31
+                                  character: 13
+                                token_type:
+                                  type: Symbol
+                                  symbol: "="
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 737
+                                    line: 31
+                                    character: 13
+                                  end_position:
+                                    bytes: 738
+                                    line: 31
+                                    character: 14
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            expr_list:
+                              pairs:
+                                - End:
+                                    BinaryOperator:
+                                      lhs:
+                                        Var:
+                                          Name:
+                                            leading_trivia: []
+                                            token:
+                                              start_position:
+                                                bytes: 738
+                                                line: 31
+                                                character: 14
+                                              end_position:
+                                                bytes: 747
+                                                line: 31
+                                                character: 23
+                                              token_type:
+                                                type: Identifier
+                                                identifier: blacklist
+                                            trailing_trivia:
+                                              - start_position:
+                                                  bytes: 747
+                                                  line: 31
+                                                  character: 23
+                                                end_position:
+                                                  bytes: 748
+                                                  line: 31
+                                                  character: 24
+                                                token_type:
+                                                  type: Whitespace
+                                                  characters: " "
+                                      binop:
+                                        Or:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 748
+                                              line: 31
+                                              character: 24
+                                            end_position:
+                                              bytes: 750
+                                              line: 31
+                                              character: 26
+                                            token_type:
+                                              type: Symbol
+                                              symbol: or
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 750
+                                                line: 31
+                                                character: 26
+                                              end_position:
+                                                bytes: 751
+                                                line: 31
+                                                character: 27
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+                                      rhs:
+                                        TableConstructor:
+                                          braces:
+                                            tokens:
+                                              - leading_trivia: []
+                                                token:
+                                                  start_position:
+                                                    bytes: 751
+                                                    line: 31
+                                                    character: 27
+                                                  end_position:
+                                                    bytes: 752
+                                                    line: 31
+                                                    character: 28
+                                                  token_type:
+                                                    type: Symbol
+                                                    symbol: "{"
+                                                trailing_trivia: []
+                                              - leading_trivia: []
+                                                token:
+                                                  start_position:
+                                                    bytes: 752
+                                                    line: 31
+                                                    character: 28
+                                                  end_position:
+                                                    bytes: 753
+                                                    line: 31
+                                                    character: 29
+                                                  token_type:
+                                                    type: Symbol
+                                                    symbol: "}"
+                                                trailing_trivia:
+                                                  - start_position:
+                                                      bytes: 753
+                                                      line: 31
+                                                      character: 29
+                                                    end_position:
+                                                      bytes: 754
+                                                      line: 31
+                                                      character: 29
+                                                    token_type:
+                                                      type: Whitespace
+                                                      characters: "\n"
+                                          fields:
+                                            pairs: []
+                        - ~
+                      - - LocalAssignment:
+                            local_token:
+                              leading_trivia:
+                                - start_position:
+                                    bytes: 754
+                                    line: 32
+                                    character: 1
+                                  end_position:
+                                    bytes: 755
+                                    line: 32
+                                    character: 1
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\n"
+                                - start_position:
+                                    bytes: 755
+                                    line: 33
+                                    character: 1
+                                  end_position:
+                                    bytes: 756
+                                    line: 33
+                                    character: 2
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\t"
+                              token:
+                                start_position:
+                                  bytes: 756
+                                  line: 33
+                                  character: 2
+                                end_position:
+                                  bytes: 761
+                                  line: 33
+                                  character: 7
+                                token_type:
+                                  type: Symbol
+                                  symbol: local
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 761
+                                    line: 33
+                                    character: 7
+                                  end_position:
+                                    bytes: 762
+                                    line: 33
+                                    character: 8
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            name_list:
+                              pairs:
+                                - Punctuated:
+                                    - leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 762
+                                          line: 33
+                                          character: 8
+                                        end_position:
+                                          bytes: 765
+                                          line: 33
+                                          character: 11
+                                        token_type:
+                                          type: Identifier
+                                          identifier: hit
+                                      trailing_trivia: []
+                                    - leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 765
+                                          line: 33
+                                          character: 11
+                                        end_position:
+                                          bytes: 766
+                                          line: 33
+                                          character: 12
+                                        token_type:
+                                          type: Symbol
+                                          symbol: ","
+                                      trailing_trivia:
+                                        - start_position:
+                                            bytes: 766
+                                            line: 33
+                                            character: 12
+                                          end_position:
+                                            bytes: 767
+                                            line: 33
+                                            character: 13
+                                          token_type:
+                                            type: Whitespace
+                                            characters: " "
+                                - End:
+                                    leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 767
+                                        line: 33
+                                        character: 13
+                                      end_position:
+                                        bytes: 772
+                                        line: 33
+                                        character: 18
+                                      token_type:
+                                        type: Identifier
+                                        identifier: point
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 772
+                                          line: 33
+                                          character: 18
+                                        end_position:
+                                          bytes: 773
+                                          line: 33
+                                          character: 19
+                                        token_type:
+                                          type: Whitespace
+                                          characters: " "
+                            equal_token: ~
+                            expr_list:
+                              pairs: []
+                        - ~
+                      - - Do:
+                            do_token:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 773
+                                  line: 33
+                                  character: 19
+                                end_position:
+                                  bytes: 775
+                                  line: 33
+                                  character: 21
+                                token_type:
+                                  type: Symbol
+                                  symbol: do
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 775
+                                    line: 33
+                                    character: 21
+                                  end_position:
+                                    bytes: 776
+                                    line: 33
+                                    character: 21
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\n"
+                            block:
+                              stmts:
+                                - - While:
+                                      while_token:
+                                        leading_trivia:
+                                          - start_position:
+                                              bytes: 776
+                                              line: 34
+                                              character: 1
+                                            end_position:
+                                              bytes: 778
+                                              line: 34
+                                              character: 3
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\t\t"
+                                        token:
+                                          start_position:
+                                            bytes: 778
+                                            line: 34
+                                            character: 3
+                                          end_position:
+                                            bytes: 783
+                                            line: 34
+                                            character: 8
+                                          token_type:
+                                            type: Symbol
+                                            symbol: while
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 783
+                                              line: 34
+                                              character: 8
+                                            end_position:
+                                              bytes: 784
+                                              line: 34
+                                              character: 9
+                                            token_type:
+                                              type: Whitespace
+                                              characters: " "
+                                      condition:
+                                        Symbol:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 784
+                                              line: 34
+                                              character: 9
+                                            end_position:
+                                              bytes: 788
+                                              line: 34
+                                              character: 13
+                                            token_type:
+                                              type: Symbol
+                                              symbol: "true"
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 788
+                                                line: 34
+                                                character: 13
+                                              end_position:
+                                                bytes: 789
+                                                line: 34
+                                                character: 14
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+                                      do_token:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 789
+                                            line: 34
+                                            character: 14
+                                          end_position:
+                                            bytes: 791
+                                            line: 34
+                                            character: 16
+                                          token_type:
+                                            type: Symbol
+                                            symbol: do
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 791
+                                              line: 34
+                                              character: 16
+                                            end_position:
+                                              bytes: 792
+                                              line: 34
+                                              character: 16
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\n"
+                                      block:
+                                        stmts:
+                                          - - Assignment:
+                                                var_list:
+                                                  pairs:
+                                                    - Punctuated:
+                                                        - Name:
+                                                            leading_trivia:
+                                                              - start_position:
+                                                                  bytes: 792
+                                                                  line: 35
+                                                                  character: 1
+                                                                end_position:
+                                                                  bytes: 795
+                                                                  line: 35
+                                                                  character: 4
+                                                                token_type:
+                                                                  type: Whitespace
+                                                                  characters: "\t\t\t"
+                                                            token:
+                                                              start_position:
+                                                                bytes: 795
+                                                                line: 35
+                                                                character: 4
+                                                              end_position:
+                                                                bytes: 798
+                                                                line: 35
+                                                                character: 7
+                                                              token_type:
+                                                                type: Identifier
+                                                                identifier: hit
+                                                            trailing_trivia: []
+                                                        - leading_trivia: []
+                                                          token:
+                                                            start_position:
+                                                              bytes: 798
+                                                              line: 35
+                                                              character: 7
+                                                            end_position:
+                                                              bytes: 799
+                                                              line: 35
+                                                              character: 8
+                                                            token_type:
+                                                              type: Symbol
+                                                              symbol: ","
+                                                          trailing_trivia:
+                                                            - start_position:
+                                                                bytes: 799
+                                                                line: 35
+                                                                character: 8
+                                                              end_position:
+                                                                bytes: 800
+                                                                line: 35
+                                                                character: 9
+                                                              token_type:
+                                                                type: Whitespace
+                                                                characters: " "
+                                                    - End:
+                                                        Name:
+                                                          leading_trivia: []
+                                                          token:
+                                                            start_position:
+                                                              bytes: 800
+                                                              line: 35
+                                                              character: 9
+                                                            end_position:
+                                                              bytes: 805
+                                                              line: 35
+                                                              character: 14
+                                                            token_type:
+                                                              type: Identifier
+                                                              identifier: point
+                                                          trailing_trivia:
+                                                            - start_position:
+                                                                bytes: 805
+                                                                line: 35
+                                                                character: 14
+                                                              end_position:
+                                                                bytes: 806
+                                                                line: 35
+                                                                character: 15
+                                                              token_type:
+                                                                type: Whitespace
+                                                                characters: " "
+                                                equal_token:
+                                                  leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 806
+                                                      line: 35
+                                                      character: 15
+                                                    end_position:
+                                                      bytes: 807
+                                                      line: 35
+                                                      character: 16
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: "="
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 807
+                                                        line: 35
+                                                        character: 16
+                                                      end_position:
+                                                        bytes: 808
+                                                        line: 35
+                                                        character: 17
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: " "
+                                                expr_list:
+                                                  pairs:
+                                                    - End:
+                                                        FunctionCall:
+                                                          prefix:
+                                                            Name:
+                                                              leading_trivia: []
+                                                              token:
+                                                                start_position:
+                                                                  bytes: 808
+                                                                  line: 35
+                                                                  character: 17
+                                                                end_position:
+                                                                  bytes: 815
+                                                                  line: 35
+                                                                  character: 24
+                                                                token_type:
+                                                                  type: Identifier
+                                                                  identifier: Raycast
+                                                              trailing_trivia: []
+                                                          suffixes:
+                                                            - Call:
+                                                                AnonymousCall:
+                                                                  Parentheses:
+                                                                    parentheses:
+                                                                      tokens:
+                                                                        - leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 815
+                                                                              line: 35
+                                                                              character: 24
+                                                                            end_position:
+                                                                              bytes: 816
+                                                                              line: 35
+                                                                              character: 25
+                                                                            token_type:
+                                                                              type: Symbol
+                                                                              symbol: (
+                                                                          trailing_trivia: []
+                                                                        - leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 899
+                                                                              line: 35
+                                                                              character: 108
+                                                                            end_position:
+                                                                              bytes: 900
+                                                                              line: 35
+                                                                              character: 109
+                                                                            token_type:
+                                                                              type: Symbol
+                                                                              symbol: )
+                                                                          trailing_trivia:
+                                                                            - start_position:
+                                                                                bytes: 900
+                                                                                line: 35
+                                                                                character: 109
+                                                                              end_position:
+                                                                                bytes: 901
+                                                                                line: 35
+                                                                                character: 109
+                                                                              token_type:
+                                                                                type: Whitespace
+                                                                                characters: "\n"
+                                                                    arguments:
+                                                                      pairs:
+                                                                        - Punctuated:
+                                                                            - FunctionCall:
+                                                                                prefix:
+                                                                                  Name:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 816
+                                                                                        line: 35
+                                                                                        character: 25
+                                                                                      end_position:
+                                                                                        bytes: 819
+                                                                                        line: 35
+                                                                                        character: 28
+                                                                                      token_type:
+                                                                                        type: Identifier
+                                                                                        identifier: Ray
+                                                                                    trailing_trivia: []
+                                                                                suffixes:
+                                                                                  - Index:
+                                                                                      Dot:
+                                                                                        dot:
+                                                                                          leading_trivia: []
+                                                                                          token:
+                                                                                            start_position:
+                                                                                              bytes: 819
+                                                                                              line: 35
+                                                                                              character: 28
+                                                                                            end_position:
+                                                                                              bytes: 820
+                                                                                              line: 35
+                                                                                              character: 29
+                                                                                            token_type:
+                                                                                              type: Symbol
+                                                                                              symbol: "."
+                                                                                          trailing_trivia: []
+                                                                                        name:
+                                                                                          leading_trivia: []
+                                                                                          token:
+                                                                                            start_position:
+                                                                                              bytes: 820
+                                                                                              line: 35
+                                                                                              character: 29
+                                                                                            end_position:
+                                                                                              bytes: 823
+                                                                                              line: 35
+                                                                                              character: 32
+                                                                                            token_type:
+                                                                                              type: Identifier
+                                                                                              identifier: new
+                                                                                          trailing_trivia: []
+                                                                                  - Call:
+                                                                                      AnonymousCall:
+                                                                                        Parentheses:
+                                                                                          parentheses:
+                                                                                            tokens:
+                                                                                              - leading_trivia: []
+                                                                                                token:
+                                                                                                  start_position:
+                                                                                                    bytes: 823
+                                                                                                    line: 35
+                                                                                                    character: 32
+                                                                                                  end_position:
+                                                                                                    bytes: 824
+                                                                                                    line: 35
+                                                                                                    character: 33
+                                                                                                  token_type:
+                                                                                                    type: Symbol
+                                                                                                    symbol: (
+                                                                                                trailing_trivia: []
+                                                                                              - leading_trivia: []
+                                                                                                token:
+                                                                                                  start_position:
+                                                                                                    bytes: 887
+                                                                                                    line: 35
+                                                                                                    character: 96
+                                                                                                  end_position:
+                                                                                                    bytes: 888
+                                                                                                    line: 35
+                                                                                                    character: 97
+                                                                                                  token_type:
+                                                                                                    type: Symbol
+                                                                                                    symbol: )
+                                                                                                trailing_trivia: []
+                                                                                          arguments:
+                                                                                            pairs:
+                                                                                              - Punctuated:
+                                                                                                  - Var:
+                                                                                                      Name:
+                                                                                                        leading_trivia: []
+                                                                                                        token:
+                                                                                                          start_position:
+                                                                                                            bytes: 824
+                                                                                                            line: 35
+                                                                                                            character: 33
+                                                                                                          end_position:
+                                                                                                            bytes: 830
+                                                                                                            line: 35
+                                                                                                            character: 39
+                                                                                                          token_type:
+                                                                                                            type: Identifier
+                                                                                                            identifier: origin
+                                                                                                        trailing_trivia: []
+                                                                                                  - leading_trivia: []
+                                                                                                    token:
+                                                                                                      start_position:
+                                                                                                        bytes: 830
+                                                                                                        line: 35
+                                                                                                        character: 39
+                                                                                                      end_position:
+                                                                                                        bytes: 831
+                                                                                                        line: 35
+                                                                                                        character: 40
+                                                                                                      token_type:
+                                                                                                        type: Symbol
+                                                                                                        symbol: ","
+                                                                                                    trailing_trivia:
+                                                                                                      - start_position:
+                                                                                                          bytes: 831
+                                                                                                          line: 35
+                                                                                                          character: 40
+                                                                                                        end_position:
+                                                                                                          bytes: 832
+                                                                                                          line: 35
+                                                                                                          character: 41
+                                                                                                        token_type:
+                                                                                                          type: Whitespace
+                                                                                                          characters: " "
+                                                                                              - End:
+                                                                                                  BinaryOperator:
+                                                                                                    lhs:
+                                                                                                      Var:
+                                                                                                        Expression:
+                                                                                                          prefix:
+                                                                                                            Expression:
+                                                                                                              Parentheses:
+                                                                                                                contained:
+                                                                                                                  tokens:
+                                                                                                                    - leading_trivia: []
+                                                                                                                      token:
+                                                                                                                        start_position:
+                                                                                                                          bytes: 832
+                                                                                                                          line: 35
+                                                                                                                          character: 41
+                                                                                                                        end_position:
+                                                                                                                          bytes: 833
+                                                                                                                          line: 35
+                                                                                                                          character: 42
+                                                                                                                        token_type:
+                                                                                                                          type: Symbol
+                                                                                                                          symbol: (
+                                                                                                                      trailing_trivia: []
+                                                                                                                    - leading_trivia: []
+                                                                                                                      token:
+                                                                                                                        start_position:
+                                                                                                                          bytes: 872
+                                                                                                                          line: 35
+                                                                                                                          character: 81
+                                                                                                                        end_position:
+                                                                                                                          bytes: 873
+                                                                                                                          line: 35
+                                                                                                                          character: 82
+                                                                                                                        token_type:
+                                                                                                                          type: Symbol
+                                                                                                                          symbol: )
+                                                                                                                      trailing_trivia: []
+                                                                                                                expression:
+                                                                                                                  BinaryOperator:
+                                                                                                                    lhs:
+                                                                                                                      Var:
+                                                                                                                        Name:
+                                                                                                                          leading_trivia: []
+                                                                                                                          token:
+                                                                                                                            start_position:
+                                                                                                                              bytes: 833
+                                                                                                                              line: 35
+                                                                                                                              character: 42
+                                                                                                                            end_position:
+                                                                                                                              bytes: 839
+                                                                                                                              line: 35
+                                                                                                                              character: 48
+                                                                                                                            token_type:
+                                                                                                                              type: Identifier
+                                                                                                                              identifier: origin
+                                                                                                                          trailing_trivia:
+                                                                                                                            - start_position:
+                                                                                                                                bytes: 839
+                                                                                                                                line: 35
+                                                                                                                                character: 48
+                                                                                                                              end_position:
+                                                                                                                                bytes: 840
+                                                                                                                                line: 35
+                                                                                                                                character: 49
+                                                                                                                              token_type:
+                                                                                                                                type: Whitespace
+                                                                                                                                characters: " "
+                                                                                                                    binop:
+                                                                                                                      Minus:
+                                                                                                                        leading_trivia: []
+                                                                                                                        token:
+                                                                                                                          start_position:
+                                                                                                                            bytes: 840
+                                                                                                                            line: 35
+                                                                                                                            character: 49
+                                                                                                                          end_position:
+                                                                                                                            bytes: 841
+                                                                                                                            line: 35
+                                                                                                                            character: 50
+                                                                                                                          token_type:
+                                                                                                                            type: Symbol
+                                                                                                                            symbol: "-"
+                                                                                                                        trailing_trivia:
+                                                                                                                          - start_position:
+                                                                                                                              bytes: 841
+                                                                                                                              line: 35
+                                                                                                                              character: 50
+                                                                                                                            end_position:
+                                                                                                                              bytes: 842
+                                                                                                                              line: 35
+                                                                                                                              character: 51
+                                                                                                                            token_type:
+                                                                                                                              type: Whitespace
+                                                                                                                              characters: " "
+                                                                                                                    rhs:
+                                                                                                                      Var:
+                                                                                                                        Expression:
+                                                                                                                          prefix:
+                                                                                                                            Name:
+                                                                                                                              leading_trivia: []
+                                                                                                                              token:
+                                                                                                                                start_position:
+                                                                                                                                  bytes: 842
+                                                                                                                                  line: 35
+                                                                                                                                  character: 51
+                                                                                                                                end_position:
+                                                                                                                                  bytes: 851
+                                                                                                                                  line: 35
+                                                                                                                                  character: 60
+                                                                                                                                token_type:
+                                                                                                                                  type: Identifier
+                                                                                                                                  identifier: character
+                                                                                                                              trailing_trivia: []
+                                                                                                                          suffixes:
+                                                                                                                            - Index:
+                                                                                                                                Dot:
+                                                                                                                                  dot:
+                                                                                                                                    leading_trivia: []
+                                                                                                                                    token:
+                                                                                                                                      start_position:
+                                                                                                                                        bytes: 851
+                                                                                                                                        line: 35
+                                                                                                                                        character: 60
+                                                                                                                                      end_position:
+                                                                                                                                        bytes: 852
+                                                                                                                                        line: 35
+                                                                                                                                        character: 61
+                                                                                                                                      token_type:
+                                                                                                                                        type: Symbol
+                                                                                                                                        symbol: "."
+                                                                                                                                    trailing_trivia: []
+                                                                                                                                  name:
+                                                                                                                                    leading_trivia: []
+                                                                                                                                    token:
+                                                                                                                                      start_position:
+                                                                                                                                        bytes: 852
+                                                                                                                                        line: 35
+                                                                                                                                        character: 61
+                                                                                                                                      end_position:
+                                                                                                                                        bytes: 863
+                                                                                                                                        line: 35
+                                                                                                                                        character: 72
+                                                                                                                                      token_type:
+                                                                                                                                        type: Identifier
+                                                                                                                                        identifier: PrimaryPart
+                                                                                                                                    trailing_trivia: []
+                                                                                                                            - Index:
+                                                                                                                                Dot:
+                                                                                                                                  dot:
+                                                                                                                                    leading_trivia: []
+                                                                                                                                    token:
+                                                                                                                                      start_position:
+                                                                                                                                        bytes: 863
+                                                                                                                                        line: 35
+                                                                                                                                        character: 72
+                                                                                                                                      end_position:
+                                                                                                                                        bytes: 864
+                                                                                                                                        line: 35
+                                                                                                                                        character: 73
+                                                                                                                                      token_type:
+                                                                                                                                        type: Symbol
+                                                                                                                                        symbol: "."
+                                                                                                                                    trailing_trivia: []
+                                                                                                                                  name:
+                                                                                                                                    leading_trivia: []
+                                                                                                                                    token:
+                                                                                                                                      start_position:
+                                                                                                                                        bytes: 864
+                                                                                                                                        line: 35
+                                                                                                                                        character: 73
+                                                                                                                                      end_position:
+                                                                                                                                        bytes: 872
+                                                                                                                                        line: 35
+                                                                                                                                        character: 81
+                                                                                                                                      token_type:
+                                                                                                                                        type: Identifier
+                                                                                                                                        identifier: Position
+                                                                                                                                    trailing_trivia: []
+                                                                                                          suffixes:
+                                                                                                            - Index:
+                                                                                                                Dot:
+                                                                                                                  dot:
+                                                                                                                    leading_trivia: []
+                                                                                                                    token:
+                                                                                                                      start_position:
+                                                                                                                        bytes: 873
+                                                                                                                        line: 35
+                                                                                                                        character: 82
+                                                                                                                      end_position:
+                                                                                                                        bytes: 874
+                                                                                                                        line: 35
+                                                                                                                        character: 83
+                                                                                                                      token_type:
+                                                                                                                        type: Symbol
+                                                                                                                        symbol: "."
+                                                                                                                    trailing_trivia: []
+                                                                                                                  name:
+                                                                                                                    leading_trivia: []
+                                                                                                                    token:
+                                                                                                                      start_position:
+                                                                                                                        bytes: 874
+                                                                                                                        line: 35
+                                                                                                                        character: 83
+                                                                                                                      end_position:
+                                                                                                                        bytes: 878
+                                                                                                                        line: 35
+                                                                                                                        character: 87
+                                                                                                                      token_type:
+                                                                                                                        type: Identifier
+                                                                                                                        identifier: Unit
+                                                                                                                    trailing_trivia:
+                                                                                                                      - start_position:
+                                                                                                                          bytes: 878
+                                                                                                                          line: 35
+                                                                                                                          character: 87
+                                                                                                                        end_position:
+                                                                                                                          bytes: 879
+                                                                                                                          line: 35
+                                                                                                                          character: 88
+                                                                                                                        token_type:
+                                                                                                                          type: Whitespace
+                                                                                                                          characters: " "
+                                                                                                    binop:
+                                                                                                      Star:
+                                                                                                        leading_trivia: []
+                                                                                                        token:
+                                                                                                          start_position:
+                                                                                                            bytes: 879
+                                                                                                            line: 35
+                                                                                                            character: 88
+                                                                                                          end_position:
+                                                                                                            bytes: 880
+                                                                                                            line: 35
+                                                                                                            character: 89
+                                                                                                          token_type:
+                                                                                                            type: Symbol
+                                                                                                            symbol: "*"
+                                                                                                        trailing_trivia:
+                                                                                                          - start_position:
+                                                                                                              bytes: 880
+                                                                                                              line: 35
+                                                                                                              character: 89
+                                                                                                            end_position:
+                                                                                                              bytes: 881
+                                                                                                              line: 35
+                                                                                                              character: 90
+                                                                                                            token_type:
+                                                                                                              type: Whitespace
+                                                                                                              characters: " "
+                                                                                                    rhs:
+                                                                                                      UnaryOperator:
+                                                                                                        unop:
+                                                                                                          Minus:
+                                                                                                            leading_trivia: []
+                                                                                                            token:
+                                                                                                              start_position:
+                                                                                                                bytes: 881
+                                                                                                                line: 35
+                                                                                                                character: 90
+                                                                                                              end_position:
+                                                                                                                bytes: 882
+                                                                                                                line: 35
+                                                                                                                character: 91
+                                                                                                              token_type:
+                                                                                                                type: Symbol
+                                                                                                                symbol: "-"
+                                                                                                            trailing_trivia: []
+                                                                                                        expression:
+                                                                                                          Var:
+                                                                                                            Name:
+                                                                                                              leading_trivia: []
+                                                                                                              token:
+                                                                                                                start_position:
+                                                                                                                  bytes: 882
+                                                                                                                  line: 35
+                                                                                                                  character: 91
+                                                                                                                end_position:
+                                                                                                                  bytes: 887
+                                                                                                                  line: 35
+                                                                                                                  character: 96
+                                                                                                                token_type:
+                                                                                                                  type: Identifier
+                                                                                                                  identifier: range
+                                                                                                              trailing_trivia: []
+                                                                            - leading_trivia: []
+                                                                              token:
+                                                                                start_position:
+                                                                                  bytes: 888
+                                                                                  line: 35
+                                                                                  character: 97
+                                                                                end_position:
+                                                                                  bytes: 889
+                                                                                  line: 35
+                                                                                  character: 98
+                                                                                token_type:
+                                                                                  type: Symbol
+                                                                                  symbol: ","
+                                                                              trailing_trivia:
+                                                                                - start_position:
+                                                                                    bytes: 889
+                                                                                    line: 35
+                                                                                    character: 98
+                                                                                  end_position:
+                                                                                    bytes: 890
+                                                                                    line: 35
+                                                                                    character: 99
+                                                                                  token_type:
+                                                                                    type: Whitespace
+                                                                                    characters: " "
+                                                                        - End:
+                                                                            Var:
+                                                                              Name:
+                                                                                leading_trivia: []
+                                                                                token:
+                                                                                  start_position:
+                                                                                    bytes: 890
+                                                                                    line: 35
+                                                                                    character: 99
+                                                                                  end_position:
+                                                                                    bytes: 899
+                                                                                    line: 35
+                                                                                    character: 108
+                                                                                  token_type:
+                                                                                    type: Identifier
+                                                                                    identifier: blacklist
+                                                                                trailing_trivia: []
+                                            - ~
+                                          - - If:
+                                                if_token:
+                                                  leading_trivia:
+                                                    - start_position:
+                                                        bytes: 901
+                                                        line: 36
+                                                        character: 1
+                                                      end_position:
+                                                        bytes: 902
+                                                        line: 36
+                                                        character: 1
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: "\n"
+                                                    - start_position:
+                                                        bytes: 902
+                                                        line: 37
+                                                        character: 1
+                                                      end_position:
+                                                        bytes: 905
+                                                        line: 37
+                                                        character: 4
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: "\t\t\t"
+                                                  token:
+                                                    start_position:
+                                                      bytes: 905
+                                                      line: 37
+                                                      character: 4
+                                                    end_position:
+                                                      bytes: 907
+                                                      line: 37
+                                                      character: 6
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: if
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 907
+                                                        line: 37
+                                                        character: 6
+                                                      end_position:
+                                                        bytes: 908
+                                                        line: 37
+                                                        character: 7
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: " "
+                                                condition:
+                                                  BinaryOperator:
+                                                    lhs:
+                                                      Var:
+                                                        Name:
+                                                          leading_trivia: []
+                                                          token:
+                                                            start_position:
+                                                              bytes: 908
+                                                              line: 37
+                                                              character: 7
+                                                            end_position:
+                                                              bytes: 911
+                                                              line: 37
+                                                              character: 10
+                                                            token_type:
+                                                              type: Identifier
+                                                              identifier: hit
+                                                          trailing_trivia:
+                                                            - start_position:
+                                                                bytes: 911
+                                                                line: 37
+                                                                character: 10
+                                                              end_position:
+                                                                bytes: 912
+                                                                line: 37
+                                                                character: 11
+                                                              token_type:
+                                                                type: Whitespace
+                                                                characters: " "
+                                                    binop:
+                                                      And:
+                                                        leading_trivia: []
+                                                        token:
+                                                          start_position:
+                                                            bytes: 912
+                                                            line: 37
+                                                            character: 11
+                                                          end_position:
+                                                            bytes: 915
+                                                            line: 37
+                                                            character: 14
+                                                          token_type:
+                                                            type: Symbol
+                                                            symbol: and
+                                                        trailing_trivia:
+                                                          - start_position:
+                                                              bytes: 915
+                                                              line: 37
+                                                              character: 14
+                                                            end_position:
+                                                              bytes: 916
+                                                              line: 37
+                                                              character: 15
+                                                            token_type:
+                                                              type: Whitespace
+                                                              characters: " "
+                                                    rhs:
+                                                      FunctionCall:
+                                                        prefix:
+                                                          Name:
+                                                            leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 916
+                                                                line: 37
+                                                                character: 15
+                                                              end_position:
+                                                                bytes: 919
+                                                                line: 37
+                                                                character: 18
+                                                              token_type:
+                                                                type: Identifier
+                                                                identifier: hit
+                                                            trailing_trivia: []
+                                                        suffixes:
+                                                          - Call:
+                                                              MethodCall:
+                                                                colon_token:
+                                                                  leading_trivia: []
+                                                                  token:
+                                                                    start_position:
+                                                                      bytes: 919
+                                                                      line: 37
+                                                                      character: 18
+                                                                    end_position:
+                                                                      bytes: 920
+                                                                      line: 37
+                                                                      character: 19
+                                                                    token_type:
+                                                                      type: Symbol
+                                                                      symbol: ":"
+                                                                  trailing_trivia: []
+                                                                name:
+                                                                  leading_trivia: []
+                                                                  token:
+                                                                    start_position:
+                                                                      bytes: 920
+                                                                      line: 37
+                                                                      character: 19
+                                                                    end_position:
+                                                                      bytes: 934
+                                                                      line: 37
+                                                                      character: 33
+                                                                    token_type:
+                                                                      type: Identifier
+                                                                      identifier: IsDescendantOf
+                                                                  trailing_trivia: []
+                                                                args:
+                                                                  Parentheses:
+                                                                    parentheses:
+                                                                      tokens:
+                                                                        - leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 934
+                                                                              line: 37
+                                                                              character: 33
+                                                                            end_position:
+                                                                              bytes: 935
+                                                                              line: 37
+                                                                              character: 34
+                                                                            token_type:
+                                                                              type: Symbol
+                                                                              symbol: (
+                                                                          trailing_trivia: []
+                                                                        - leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 944
+                                                                              line: 37
+                                                                              character: 43
+                                                                            end_position:
+                                                                              bytes: 945
+                                                                              line: 37
+                                                                              character: 44
+                                                                            token_type:
+                                                                              type: Symbol
+                                                                              symbol: )
+                                                                          trailing_trivia:
+                                                                            - start_position:
+                                                                                bytes: 945
+                                                                                line: 37
+                                                                                character: 44
+                                                                              end_position:
+                                                                                bytes: 946
+                                                                                line: 37
+                                                                                character: 45
+                                                                              token_type:
+                                                                                type: Whitespace
+                                                                                characters: " "
+                                                                    arguments:
+                                                                      pairs:
+                                                                        - End:
+                                                                            Var:
+                                                                              Name:
+                                                                                leading_trivia: []
+                                                                                token:
+                                                                                  start_position:
+                                                                                    bytes: 935
+                                                                                    line: 37
+                                                                                    character: 34
+                                                                                  end_position:
+                                                                                    bytes: 944
+                                                                                    line: 37
+                                                                                    character: 43
+                                                                                  token_type:
+                                                                                    type: Identifier
+                                                                                    identifier: character
+                                                                                trailing_trivia: []
+                                                then_token:
+                                                  leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 946
+                                                      line: 37
+                                                      character: 45
+                                                    end_position:
+                                                      bytes: 950
+                                                      line: 37
+                                                      character: 49
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: then
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 950
+                                                        line: 37
+                                                        character: 49
+                                                      end_position:
+                                                        bytes: 951
+                                                        line: 37
+                                                        character: 49
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: "\n"
+                                                block:
+                                                  stmts: []
+                                                  last_stmt:
+                                                    - Break:
+                                                        leading_trivia:
+                                                          - start_position:
+                                                              bytes: 951
+                                                              line: 38
+                                                              character: 1
+                                                            end_position:
+                                                              bytes: 955
+                                                              line: 38
+                                                              character: 5
+                                                            token_type:
+                                                              type: Whitespace
+                                                              characters: "\t\t\t\t"
+                                                        token:
+                                                          start_position:
+                                                            bytes: 955
+                                                            line: 38
+                                                            character: 5
+                                                          end_position:
+                                                            bytes: 960
+                                                            line: 38
+                                                            character: 10
+                                                          token_type:
+                                                            type: Symbol
+                                                            symbol: break
+                                                        trailing_trivia:
+                                                          - start_position:
+                                                              bytes: 960
+                                                              line: 38
+                                                              character: 10
+                                                            end_position:
+                                                              bytes: 961
+                                                              line: 38
+                                                              character: 10
+                                                            token_type:
+                                                              type: Whitespace
+                                                              characters: "\n"
+                                                    - ~
+                                                else_if:
+                                                  - else_if_token:
+                                                      leading_trivia:
+                                                        - start_position:
+                                                            bytes: 961
+                                                            line: 39
+                                                            character: 1
+                                                          end_position:
+                                                            bytes: 964
+                                                            line: 39
+                                                            character: 4
+                                                          token_type:
+                                                            type: Whitespace
+                                                            characters: "\t\t\t"
+                                                      token:
+                                                        start_position:
+                                                          bytes: 964
+                                                          line: 39
+                                                          character: 4
+                                                        end_position:
+                                                          bytes: 970
+                                                          line: 39
+                                                          character: 10
+                                                        token_type:
+                                                          type: Symbol
+                                                          symbol: elseif
+                                                      trailing_trivia:
+                                                        - start_position:
+                                                            bytes: 970
+                                                            line: 39
+                                                            character: 10
+                                                          end_position:
+                                                            bytes: 971
+                                                            line: 39
+                                                            character: 11
+                                                          token_type:
+                                                            type: Whitespace
+                                                            characters: " "
+                                                    condition:
+                                                      BinaryOperator:
+                                                        lhs:
+                                                          Var:
+                                                            Name:
+                                                              leading_trivia: []
+                                                              token:
+                                                                start_position:
+                                                                  bytes: 971
+                                                                  line: 39
+                                                                  character: 11
+                                                                end_position:
+                                                                  bytes: 974
+                                                                  line: 39
+                                                                  character: 14
+                                                                token_type:
+                                                                  type: Identifier
+                                                                  identifier: hit
+                                                              trailing_trivia:
+                                                                - start_position:
+                                                                    bytes: 974
+                                                                    line: 39
+                                                                    character: 14
+                                                                  end_position:
+                                                                    bytes: 975
+                                                                    line: 39
+                                                                    character: 15
+                                                                  token_type:
+                                                                    type: Whitespace
+                                                                    characters: " "
+                                                        binop:
+                                                          And:
+                                                            leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 975
+                                                                line: 39
+                                                                character: 15
+                                                              end_position:
+                                                                bytes: 978
+                                                                line: 39
+                                                                character: 18
+                                                              token_type:
+                                                                type: Symbol
+                                                                symbol: and
+                                                            trailing_trivia:
+                                                              - start_position:
+                                                                  bytes: 978
+                                                                  line: 39
+                                                                  character: 18
+                                                                end_position:
+                                                                  bytes: 979
+                                                                  line: 39
+                                                                  character: 19
+                                                                token_type:
+                                                                  type: Whitespace
+                                                                  characters: " "
+                                                        rhs:
+                                                          FunctionCall:
+                                                            prefix:
+                                                              Name:
+                                                                leading_trivia: []
+                                                                token:
+                                                                  start_position:
+                                                                    bytes: 979
+                                                                    line: 39
+                                                                    character: 19
+                                                                  end_position:
+                                                                    bytes: 987
+                                                                    line: 39
+                                                                    character: 27
+                                                                  token_type:
+                                                                    type: Identifier
+                                                                    identifier: ignoreIf
+                                                                trailing_trivia: []
+                                                            suffixes:
+                                                              - Call:
+                                                                  AnonymousCall:
+                                                                    Parentheses:
+                                                                      parentheses:
+                                                                        tokens:
+                                                                          - leading_trivia: []
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 987
+                                                                                line: 39
+                                                                                character: 27
+                                                                              end_position:
+                                                                                bytes: 988
+                                                                                line: 39
+                                                                                character: 28
+                                                                              token_type:
+                                                                                type: Symbol
+                                                                                symbol: (
+                                                                            trailing_trivia: []
+                                                                          - leading_trivia: []
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 991
+                                                                                line: 39
+                                                                                character: 31
+                                                                              end_position:
+                                                                                bytes: 992
+                                                                                line: 39
+                                                                                character: 32
+                                                                              token_type:
+                                                                                type: Symbol
+                                                                                symbol: )
+                                                                            trailing_trivia:
+                                                                              - start_position:
+                                                                                  bytes: 992
+                                                                                  line: 39
+                                                                                  character: 32
+                                                                                end_position:
+                                                                                  bytes: 993
+                                                                                  line: 39
+                                                                                  character: 33
+                                                                                token_type:
+                                                                                  type: Whitespace
+                                                                                  characters: " "
+                                                                      arguments:
+                                                                        pairs:
+                                                                          - End:
+                                                                              Var:
+                                                                                Name:
+                                                                                  leading_trivia: []
+                                                                                  token:
+                                                                                    start_position:
+                                                                                      bytes: 988
+                                                                                      line: 39
+                                                                                      character: 28
+                                                                                    end_position:
+                                                                                      bytes: 991
+                                                                                      line: 39
+                                                                                      character: 31
+                                                                                    token_type:
+                                                                                      type: Identifier
+                                                                                      identifier: hit
+                                                                                  trailing_trivia: []
+                                                    then_token:
+                                                      leading_trivia: []
+                                                      token:
+                                                        start_position:
+                                                          bytes: 993
+                                                          line: 39
+                                                          character: 33
+                                                        end_position:
+                                                          bytes: 997
+                                                          line: 39
+                                                          character: 37
+                                                        token_type:
+                                                          type: Symbol
+                                                          symbol: then
+                                                      trailing_trivia:
+                                                        - start_position:
+                                                            bytes: 997
+                                                            line: 39
+                                                            character: 37
+                                                          end_position:
+                                                            bytes: 998
+                                                            line: 39
+                                                            character: 37
+                                                          token_type:
+                                                            type: Whitespace
+                                                            characters: "\n"
+                                                    block:
+                                                      stmts:
+                                                        - - FunctionCall:
+                                                              prefix:
+                                                                Name:
+                                                                  leading_trivia:
+                                                                    - start_position:
+                                                                        bytes: 998
+                                                                        line: 40
+                                                                        character: 1
+                                                                      end_position:
+                                                                        bytes: 1002
+                                                                        line: 40
+                                                                        character: 5
+                                                                      token_type:
+                                                                        type: Whitespace
+                                                                        characters: "\t\t\t\t"
+                                                                  token:
+                                                                    start_position:
+                                                                      bytes: 1002
+                                                                      line: 40
+                                                                      character: 5
+                                                                    end_position:
+                                                                      bytes: 1007
+                                                                      line: 40
+                                                                      character: 10
+                                                                    token_type:
+                                                                      type: Identifier
+                                                                      identifier: debug
+                                                                  trailing_trivia: []
+                                                              suffixes:
+                                                                - Call:
+                                                                    AnonymousCall:
+                                                                      Parentheses:
+                                                                        parentheses:
+                                                                          tokens:
+                                                                            - leading_trivia: []
+                                                                              token:
+                                                                                start_position:
+                                                                                  bytes: 1007
+                                                                                  line: 40
+                                                                                  character: 10
+                                                                                end_position:
+                                                                                  bytes: 1008
+                                                                                  line: 40
+                                                                                  character: 11
+                                                                                token_type:
+                                                                                  type: Symbol
+                                                                                  symbol: (
+                                                                              trailing_trivia: []
+                                                                            - leading_trivia: []
+                                                                              token:
+                                                                                start_position:
+                                                                                  bytes: 1044
+                                                                                  line: 40
+                                                                                  character: 47
+                                                                                end_position:
+                                                                                  bytes: 1045
+                                                                                  line: 40
+                                                                                  character: 48
+                                                                                token_type:
+                                                                                  type: Symbol
+                                                                                  symbol: )
+                                                                              trailing_trivia:
+                                                                                - start_position:
+                                                                                    bytes: 1045
+                                                                                    line: 40
+                                                                                    character: 48
+                                                                                  end_position:
+                                                                                    bytes: 1046
+                                                                                    line: 40
+                                                                                    character: 48
+                                                                                  token_type:
+                                                                                    type: Whitespace
+                                                                                    characters: "\n"
+                                                                        arguments:
+                                                                          pairs:
+                                                                            - Punctuated:
+                                                                                - String:
+                                                                                    leading_trivia: []
+                                                                                    token:
+                                                                                      start_position:
+                                                                                        bytes: 1008
+                                                                                        line: 40
+                                                                                        character: 11
+                                                                                      end_position:
+                                                                                        bytes: 1025
+                                                                                        line: 40
+                                                                                        character: 28
+                                                                                      token_type:
+                                                                                        type: StringLiteral
+                                                                                        literal: IGNORING OFF IF
+                                                                                        quote_type: Double
+                                                                                    trailing_trivia: []
+                                                                                - leading_trivia: []
+                                                                                  token:
+                                                                                    start_position:
+                                                                                      bytes: 1025
+                                                                                      line: 40
+                                                                                      character: 28
+                                                                                    end_position:
+                                                                                      bytes: 1026
+                                                                                      line: 40
+                                                                                      character: 29
+                                                                                    token_type:
+                                                                                      type: Symbol
+                                                                                      symbol: ","
+                                                                                  trailing_trivia:
+                                                                                    - start_position:
+                                                                                        bytes: 1026
+                                                                                        line: 40
+                                                                                        character: 29
+                                                                                      end_position:
+                                                                                        bytes: 1027
+                                                                                        line: 40
+                                                                                        character: 30
+                                                                                      token_type:
+                                                                                        type: Whitespace
+                                                                                        characters: " "
+                                                                            - End:
+                                                                                FunctionCall:
+                                                                                  prefix:
+                                                                                    Name:
+                                                                                      leading_trivia: []
+                                                                                      token:
+                                                                                        start_position:
+                                                                                          bytes: 1027
+                                                                                          line: 40
+                                                                                          character: 30
+                                                                                        end_position:
+                                                                                          bytes: 1030
+                                                                                          line: 40
+                                                                                          character: 33
+                                                                                        token_type:
+                                                                                          type: Identifier
+                                                                                          identifier: hit
+                                                                                      trailing_trivia: []
+                                                                                  suffixes:
+                                                                                    - Call:
+                                                                                        MethodCall:
+                                                                                          colon_token:
+                                                                                            leading_trivia: []
+                                                                                            token:
+                                                                                              start_position:
+                                                                                                bytes: 1030
+                                                                                                line: 40
+                                                                                                character: 33
+                                                                                              end_position:
+                                                                                                bytes: 1031
+                                                                                                line: 40
+                                                                                                character: 34
+                                                                                              token_type:
+                                                                                                type: Symbol
+                                                                                                symbol: ":"
+                                                                                            trailing_trivia: []
+                                                                                          name:
+                                                                                            leading_trivia: []
+                                                                                            token:
+                                                                                              start_position:
+                                                                                                bytes: 1031
+                                                                                                line: 40
+                                                                                                character: 34
+                                                                                              end_position:
+                                                                                                bytes: 1042
+                                                                                                line: 40
+                                                                                                character: 45
+                                                                                              token_type:
+                                                                                                type: Identifier
+                                                                                                identifier: GetFullName
+                                                                                            trailing_trivia: []
+                                                                                          args:
+                                                                                            Parentheses:
+                                                                                              parentheses:
+                                                                                                tokens:
+                                                                                                  - leading_trivia: []
+                                                                                                    token:
+                                                                                                      start_position:
+                                                                                                        bytes: 1042
+                                                                                                        line: 40
+                                                                                                        character: 45
+                                                                                                      end_position:
+                                                                                                        bytes: 1043
+                                                                                                        line: 40
+                                                                                                        character: 46
+                                                                                                      token_type:
+                                                                                                        type: Symbol
+                                                                                                        symbol: (
+                                                                                                    trailing_trivia: []
+                                                                                                  - leading_trivia: []
+                                                                                                    token:
+                                                                                                      start_position:
+                                                                                                        bytes: 1043
+                                                                                                        line: 40
+                                                                                                        character: 46
+                                                                                                      end_position:
+                                                                                                        bytes: 1044
+                                                                                                        line: 40
+                                                                                                        character: 47
+                                                                                                      token_type:
+                                                                                                        type: Symbol
+                                                                                                        symbol: )
+                                                                                                    trailing_trivia: []
+                                                                                              arguments:
+                                                                                                pairs: []
+                                                          - ~
+                                                        - - Assignment:
+                                                              var_list:
+                                                                pairs:
+                                                                  - End:
+                                                                      Expression:
+                                                                        prefix:
+                                                                          Name:
+                                                                            leading_trivia:
+                                                                              - start_position:
+                                                                                  bytes: 1046
+                                                                                  line: 41
+                                                                                  character: 1
+                                                                                end_position:
+                                                                                  bytes: 1050
+                                                                                  line: 41
+                                                                                  character: 5
+                                                                                token_type:
+                                                                                  type: Whitespace
+                                                                                  characters: "\t\t\t\t"
+                                                                            token:
+                                                                              start_position:
+                                                                                bytes: 1050
+                                                                                line: 41
+                                                                                character: 5
+                                                                              end_position:
+                                                                                bytes: 1059
+                                                                                line: 41
+                                                                                character: 14
+                                                                              token_type:
+                                                                                type: Identifier
+                                                                                identifier: blacklist
+                                                                            trailing_trivia: []
+                                                                        suffixes:
+                                                                          - Index:
+                                                                              Brackets:
+                                                                                brackets:
+                                                                                  tokens:
+                                                                                    - leading_trivia: []
+                                                                                      token:
+                                                                                        start_position:
+                                                                                          bytes: 1059
+                                                                                          line: 41
+                                                                                          character: 14
+                                                                                        end_position:
+                                                                                          bytes: 1060
+                                                                                          line: 41
+                                                                                          character: 15
+                                                                                        token_type:
+                                                                                          type: Symbol
+                                                                                          symbol: "["
+                                                                                      trailing_trivia: []
+                                                                                    - leading_trivia: []
+                                                                                      token:
+                                                                                        start_position:
+                                                                                          bytes: 1074
+                                                                                          line: 41
+                                                                                          character: 29
+                                                                                        end_position:
+                                                                                          bytes: 1075
+                                                                                          line: 41
+                                                                                          character: 30
+                                                                                        token_type:
+                                                                                          type: Symbol
+                                                                                          symbol: "]"
+                                                                                      trailing_trivia:
+                                                                                        - start_position:
+                                                                                            bytes: 1075
+                                                                                            line: 41
+                                                                                            character: 30
+                                                                                          end_position:
+                                                                                            bytes: 1076
+                                                                                            line: 41
+                                                                                            character: 31
+                                                                                          token_type:
+                                                                                            type: Whitespace
+                                                                                            characters: " "
+                                                                                expression:
+                                                                                  BinaryOperator:
+                                                                                    lhs:
+                                                                                      UnaryOperator:
+                                                                                        unop:
+                                                                                          Hash:
+                                                                                            leading_trivia: []
+                                                                                            token:
+                                                                                              start_position:
+                                                                                                bytes: 1060
+                                                                                                line: 41
+                                                                                                character: 15
+                                                                                              end_position:
+                                                                                                bytes: 1061
+                                                                                                line: 41
+                                                                                                character: 16
+                                                                                              token_type:
+                                                                                                type: Symbol
+                                                                                                symbol: "#"
+                                                                                            trailing_trivia: []
+                                                                                        expression:
+                                                                                          Var:
+                                                                                            Name:
+                                                                                              leading_trivia: []
+                                                                                              token:
+                                                                                                start_position:
+                                                                                                  bytes: 1061
+                                                                                                  line: 41
+                                                                                                  character: 16
+                                                                                                end_position:
+                                                                                                  bytes: 1070
+                                                                                                  line: 41
+                                                                                                  character: 25
+                                                                                                token_type:
+                                                                                                  type: Identifier
+                                                                                                  identifier: blacklist
+                                                                                              trailing_trivia:
+                                                                                                - start_position:
+                                                                                                    bytes: 1070
+                                                                                                    line: 41
+                                                                                                    character: 25
+                                                                                                  end_position:
+                                                                                                    bytes: 1071
+                                                                                                    line: 41
+                                                                                                    character: 26
+                                                                                                  token_type:
+                                                                                                    type: Whitespace
+                                                                                                    characters: " "
+                                                                                    binop:
+                                                                                      Plus:
+                                                                                        leading_trivia: []
+                                                                                        token:
+                                                                                          start_position:
+                                                                                            bytes: 1071
+                                                                                            line: 41
+                                                                                            character: 26
+                                                                                          end_position:
+                                                                                            bytes: 1072
+                                                                                            line: 41
+                                                                                            character: 27
+                                                                                          token_type:
+                                                                                            type: Symbol
+                                                                                            symbol: +
+                                                                                        trailing_trivia:
+                                                                                          - start_position:
+                                                                                              bytes: 1072
+                                                                                              line: 41
+                                                                                              character: 27
+                                                                                            end_position:
+                                                                                              bytes: 1073
+                                                                                              line: 41
+                                                                                              character: 28
+                                                                                            token_type:
+                                                                                              type: Whitespace
+                                                                                              characters: " "
+                                                                                    rhs:
+                                                                                      Number:
+                                                                                        leading_trivia: []
+                                                                                        token:
+                                                                                          start_position:
+                                                                                            bytes: 1073
+                                                                                            line: 41
+                                                                                            character: 28
+                                                                                          end_position:
+                                                                                            bytes: 1074
+                                                                                            line: 41
+                                                                                            character: 29
+                                                                                          token_type:
+                                                                                            type: Number
+                                                                                            text: "1"
+                                                                                        trailing_trivia: []
+                                                              equal_token:
+                                                                leading_trivia: []
+                                                                token:
+                                                                  start_position:
+                                                                    bytes: 1076
+                                                                    line: 41
+                                                                    character: 31
+                                                                  end_position:
+                                                                    bytes: 1077
+                                                                    line: 41
+                                                                    character: 32
+                                                                  token_type:
+                                                                    type: Symbol
+                                                                    symbol: "="
+                                                                trailing_trivia:
+                                                                  - start_position:
+                                                                      bytes: 1077
+                                                                      line: 41
+                                                                      character: 32
+                                                                    end_position:
+                                                                      bytes: 1078
+                                                                      line: 41
+                                                                      character: 33
+                                                                    token_type:
+                                                                      type: Whitespace
+                                                                      characters: " "
+                                                              expr_list:
+                                                                pairs:
+                                                                  - End:
+                                                                      Var:
+                                                                        Name:
+                                                                          leading_trivia: []
+                                                                          token:
+                                                                            start_position:
+                                                                              bytes: 1078
+                                                                              line: 41
+                                                                              character: 33
+                                                                            end_position:
+                                                                              bytes: 1081
+                                                                              line: 41
+                                                                              character: 36
+                                                                            token_type:
+                                                                              type: Identifier
+                                                                              identifier: hit
+                                                                          trailing_trivia:
+                                                                            - start_position:
+                                                                                bytes: 1081
+                                                                                line: 41
+                                                                                character: 36
+                                                                              end_position:
+                                                                                bytes: 1082
+                                                                                line: 41
+                                                                                character: 36
+                                                                              token_type:
+                                                                                type: Whitespace
+                                                                                characters: "\n"
+                                                          - ~
+                                                else_token:
+                                                  leading_trivia:
+                                                    - start_position:
+                                                        bytes: 1082
+                                                        line: 42
+                                                        character: 1
+                                                      end_position:
+                                                        bytes: 1085
+                                                        line: 42
+                                                        character: 4
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: "\t\t\t"
+                                                  token:
+                                                    start_position:
+                                                      bytes: 1085
+                                                      line: 42
+                                                      character: 4
+                                                    end_position:
+                                                      bytes: 1089
+                                                      line: 42
+                                                      character: 8
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: else
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 1089
+                                                        line: 42
+                                                        character: 8
+                                                      end_position:
+                                                        bytes: 1090
+                                                        line: 42
+                                                        character: 8
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: "\n"
+                                                else:
+                                                  stmts: []
+                                                  last_stmt:
+                                                    - Break:
+                                                        leading_trivia:
+                                                          - start_position:
+                                                              bytes: 1090
+                                                              line: 43
+                                                              character: 1
+                                                            end_position:
+                                                              bytes: 1094
+                                                              line: 43
+                                                              character: 5
+                                                            token_type:
+                                                              type: Whitespace
+                                                              characters: "\t\t\t\t"
+                                                        token:
+                                                          start_position:
+                                                            bytes: 1094
+                                                            line: 43
+                                                            character: 5
+                                                          end_position:
+                                                            bytes: 1099
+                                                            line: 43
+                                                            character: 10
+                                                          token_type:
+                                                            type: Symbol
+                                                            symbol: break
+                                                        trailing_trivia:
+                                                          - start_position:
+                                                              bytes: 1099
+                                                              line: 43
+                                                              character: 10
+                                                            end_position:
+                                                              bytes: 1100
+                                                              line: 43
+                                                              character: 10
+                                                            token_type:
+                                                              type: Whitespace
+                                                              characters: "\n"
+                                                    - ~
+                                                end_token:
+                                                  leading_trivia:
+                                                    - start_position:
+                                                        bytes: 1100
+                                                        line: 44
+                                                        character: 1
+                                                      end_position:
+                                                        bytes: 1103
+                                                        line: 44
+                                                        character: 4
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: "\t\t\t"
+                                                  token:
+                                                    start_position:
+                                                      bytes: 1103
+                                                      line: 44
+                                                      character: 4
+                                                    end_position:
+                                                      bytes: 1106
+                                                      line: 44
+                                                      character: 7
+                                                    token_type:
+                                                      type: Symbol
+                                                      symbol: end
+                                                  trailing_trivia:
+                                                    - start_position:
+                                                        bytes: 1106
+                                                        line: 44
+                                                        character: 7
+                                                      end_position:
+                                                        bytes: 1107
+                                                        line: 44
+                                                        character: 7
+                                                      token_type:
+                                                        type: Whitespace
+                                                        characters: "\n"
+                                            - ~
+                                      end_token:
+                                        leading_trivia:
+                                          - start_position:
+                                              bytes: 1107
+                                              line: 45
+                                              character: 1
+                                            end_position:
+                                              bytes: 1109
+                                              line: 45
+                                              character: 3
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\t\t"
+                                        token:
+                                          start_position:
+                                            bytes: 1109
+                                            line: 45
+                                            character: 3
+                                          end_position:
+                                            bytes: 1112
+                                            line: 45
+                                            character: 6
+                                          token_type:
+                                            type: Symbol
+                                            symbol: end
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 1112
+                                              line: 45
+                                              character: 6
+                                            end_position:
+                                              bytes: 1113
+                                              line: 45
+                                              character: 6
+                                            token_type:
+                                              type: Whitespace
+                                              characters: "\n"
+                                  - ~
+                            end_token:
+                              leading_trivia:
+                                - start_position:
+                                    bytes: 1113
+                                    line: 46
+                                    character: 1
+                                  end_position:
+                                    bytes: 1114
+                                    line: 46
+                                    character: 2
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\t"
+                              token:
+                                start_position:
+                                  bytes: 1114
+                                  line: 46
+                                  character: 2
+                                end_position:
+                                  bytes: 1117
+                                  line: 46
+                                  character: 5
+                                token_type:
+                                  type: Symbol
+                                  symbol: end
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 1117
+                                    line: 46
+                                    character: 5
+                                  end_position:
+                                    bytes: 1118
+                                    line: 46
+                                    character: 5
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\n"
+                        - ~
+                      - - FunctionCall:
+                            prefix:
+                              Name:
+                                leading_trivia:
+                                  - start_position:
+                                      bytes: 1118
+                                      line: 47
+                                      character: 1
+                                    end_position:
+                                      bytes: 1119
+                                      line: 47
+                                      character: 1
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "\n"
+                                  - start_position:
+                                      bytes: 1119
+                                      line: 48
+                                      character: 1
+                                    end_position:
+                                      bytes: 1120
+                                      line: 48
+                                      character: 2
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "\t"
+                                token:
+                                  start_position:
+                                    bytes: 1120
+                                    line: 48
+                                    character: 2
+                                  end_position:
+                                    bytes: 1125
+                                    line: 48
+                                    character: 7
+                                  token_type:
+                                    type: Identifier
+                                    identifier: debug
+                                trailing_trivia: []
+                            suffixes:
+                              - Call:
+                                  AnonymousCall:
+                                    Parentheses:
+                                      parentheses:
+                                        tokens:
+                                          - leading_trivia: []
+                                            token:
+                                              start_position:
+                                                bytes: 1125
+                                                line: 48
+                                                character: 7
+                                              end_position:
+                                                bytes: 1126
+                                                line: 48
+                                                character: 8
+                                              token_type:
+                                                type: Symbol
+                                                symbol: (
+                                            trailing_trivia: []
+                                          - leading_trivia: []
+                                            token:
+                                              start_position:
+                                                bytes: 1165
+                                                line: 48
+                                                character: 47
+                                              end_position:
+                                                bytes: 1166
+                                                line: 48
+                                                character: 48
+                                              token_type:
+                                                type: Symbol
+                                                symbol: )
+                                            trailing_trivia:
+                                              - start_position:
+                                                  bytes: 1166
+                                                  line: 48
+                                                  character: 48
+                                                end_position:
+                                                  bytes: 1167
+                                                  line: 48
+                                                  character: 48
+                                                token_type:
+                                                  type: Whitespace
+                                                  characters: "\n"
+                                      arguments:
+                                        pairs:
+                                          - Punctuated:
+                                              - String:
+                                                  leading_trivia: []
+                                                  token:
+                                                    start_position:
+                                                      bytes: 1126
+                                                      line: 48
+                                                      character: 8
+                                                    end_position:
+                                                      bytes: 1138
+                                                      line: 48
+                                                      character: 20
+                                                    token_type:
+                                                      type: StringLiteral
+                                                      literal: LOS RESULT
+                                                      quote_type: Double
+                                                  trailing_trivia: []
+                                              - leading_trivia: []
+                                                token:
+                                                  start_position:
+                                                    bytes: 1138
+                                                    line: 48
+                                                    character: 20
+                                                  end_position:
+                                                    bytes: 1139
+                                                    line: 48
+                                                    character: 21
+                                                  token_type:
+                                                    type: Symbol
+                                                    symbol: ","
+                                                trailing_trivia:
+                                                  - start_position:
+                                                      bytes: 1139
+                                                      line: 48
+                                                      character: 21
+                                                    end_position:
+                                                      bytes: 1140
+                                                      line: 48
+                                                      character: 22
+                                                    token_type:
+                                                      type: Whitespace
+                                                      characters: " "
+                                          - End:
+                                              BinaryOperator:
+                                                lhs:
+                                                  Var:
+                                                    Name:
+                                                      leading_trivia: []
+                                                      token:
+                                                        start_position:
+                                                          bytes: 1140
+                                                          line: 48
+                                                          character: 22
+                                                        end_position:
+                                                          bytes: 1143
+                                                          line: 48
+                                                          character: 25
+                                                        token_type:
+                                                          type: Identifier
+                                                          identifier: hit
+                                                      trailing_trivia:
+                                                        - start_position:
+                                                            bytes: 1143
+                                                            line: 48
+                                                            character: 25
+                                                          end_position:
+                                                            bytes: 1144
+                                                            line: 48
+                                                            character: 26
+                                                          token_type:
+                                                            type: Whitespace
+                                                            characters: " "
+                                                binop:
+                                                  And:
+                                                    leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 1144
+                                                        line: 48
+                                                        character: 26
+                                                      end_position:
+                                                        bytes: 1147
+                                                        line: 48
+                                                        character: 29
+                                                      token_type:
+                                                        type: Symbol
+                                                        symbol: and
+                                                    trailing_trivia:
+                                                      - start_position:
+                                                          bytes: 1147
+                                                          line: 48
+                                                          character: 29
+                                                        end_position:
+                                                          bytes: 1148
+                                                          line: 48
+                                                          character: 30
+                                                        token_type:
+                                                          type: Whitespace
+                                                          characters: " "
+                                                rhs:
+                                                  FunctionCall:
+                                                    prefix:
+                                                      Name:
+                                                        leading_trivia: []
+                                                        token:
+                                                          start_position:
+                                                            bytes: 1148
+                                                            line: 48
+                                                            character: 30
+                                                          end_position:
+                                                            bytes: 1151
+                                                            line: 48
+                                                            character: 33
+                                                          token_type:
+                                                            type: Identifier
+                                                            identifier: hit
+                                                        trailing_trivia: []
+                                                    suffixes:
+                                                      - Call:
+                                                          MethodCall:
+                                                            colon_token:
+                                                              leading_trivia: []
+                                                              token:
+                                                                start_position:
+                                                                  bytes: 1151
+                                                                  line: 48
+                                                                  character: 33
+                                                                end_position:
+                                                                  bytes: 1152
+                                                                  line: 48
+                                                                  character: 34
+                                                                token_type:
+                                                                  type: Symbol
+                                                                  symbol: ":"
+                                                              trailing_trivia: []
+                                                            name:
+                                                              leading_trivia: []
+                                                              token:
+                                                                start_position:
+                                                                  bytes: 1152
+                                                                  line: 48
+                                                                  character: 34
+                                                                end_position:
+                                                                  bytes: 1163
+                                                                  line: 48
+                                                                  character: 45
+                                                                token_type:
+                                                                  type: Identifier
+                                                                  identifier: GetFullName
+                                                              trailing_trivia: []
+                                                            args:
+                                                              Parentheses:
+                                                                parentheses:
+                                                                  tokens:
+                                                                    - leading_trivia: []
+                                                                      token:
+                                                                        start_position:
+                                                                          bytes: 1163
+                                                                          line: 48
+                                                                          character: 45
+                                                                        end_position:
+                                                                          bytes: 1164
+                                                                          line: 48
+                                                                          character: 46
+                                                                        token_type:
+                                                                          type: Symbol
+                                                                          symbol: (
+                                                                      trailing_trivia: []
+                                                                    - leading_trivia: []
+                                                                      token:
+                                                                        start_position:
+                                                                          bytes: 1164
+                                                                          line: 48
+                                                                          character: 46
+                                                                        end_position:
+                                                                          bytes: 1165
+                                                                          line: 48
+                                                                          character: 47
+                                                                        token_type:
+                                                                          type: Symbol
+                                                                          symbol: )
+                                                                      trailing_trivia: []
+                                                                arguments:
+                                                                  pairs: []
+                        - ~
+                    last_stmt:
+                      - Return:
+                          token:
+                            leading_trivia:
+                              - start_position:
+                                  bytes: 1167
+                                  line: 49
+                                  character: 1
+                                end_position:
+                                  bytes: 1168
+                                  line: 49
+                                  character: 1
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+                              - start_position:
+                                  bytes: 1168
+                                  line: 50
+                                  character: 1
+                                end_position:
+                                  bytes: 1169
+                                  line: 50
+                                  character: 2
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\t"
+                            token:
+                              start_position:
+                                bytes: 1169
+                                line: 50
+                                character: 2
+                              end_position:
+                                bytes: 1175
+                                line: 50
+                                character: 8
+                              token_type:
+                                type: Symbol
+                                symbol: return
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 1175
+                                  line: 50
+                                  character: 8
+                                end_position:
+                                  bytes: 1176
+                                  line: 50
+                                  character: 9
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                          returns:
+                            pairs:
+                              - Punctuated:
+                                  - BinaryOperator:
+                                      lhs:
+                                        Var:
+                                          Name:
+                                            leading_trivia: []
+                                            token:
+                                              start_position:
+                                                bytes: 1176
+                                                line: 50
+                                                character: 9
+                                              end_position:
+                                                bytes: 1179
+                                                line: 50
+                                                character: 12
+                                              token_type:
+                                                type: Identifier
+                                                identifier: hit
+                                            trailing_trivia:
+                                              - start_position:
+                                                  bytes: 1179
+                                                  line: 50
+                                                  character: 12
+                                                end_position:
+                                                  bytes: 1180
+                                                  line: 50
+                                                  character: 13
+                                                token_type:
+                                                  type: Whitespace
+                                                  characters: " "
+                                      binop:
+                                        And:
+                                          leading_trivia: []
+                                          token:
+                                            start_position:
+                                              bytes: 1180
+                                              line: 50
+                                              character: 13
+                                            end_position:
+                                              bytes: 1183
+                                              line: 50
+                                              character: 16
+                                            token_type:
+                                              type: Symbol
+                                              symbol: and
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 1183
+                                                line: 50
+                                                character: 16
+                                              end_position:
+                                                bytes: 1184
+                                                line: 50
+                                                character: 17
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+                                      rhs:
+                                        FunctionCall:
+                                          prefix:
+                                            Name:
+                                              leading_trivia: []
+                                              token:
+                                                start_position:
+                                                  bytes: 1184
+                                                  line: 50
+                                                  character: 17
+                                                end_position:
+                                                  bytes: 1187
+                                                  line: 50
+                                                  character: 20
+                                                token_type:
+                                                  type: Identifier
+                                                  identifier: hit
+                                              trailing_trivia: []
+                                          suffixes:
+                                            - Call:
+                                                MethodCall:
+                                                  colon_token:
+                                                    leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 1187
+                                                        line: 50
+                                                        character: 20
+                                                      end_position:
+                                                        bytes: 1188
+                                                        line: 50
+                                                        character: 21
+                                                      token_type:
+                                                        type: Symbol
+                                                        symbol: ":"
+                                                    trailing_trivia: []
+                                                  name:
+                                                    leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 1188
+                                                        line: 50
+                                                        character: 21
+                                                      end_position:
+                                                        bytes: 1202
+                                                        line: 50
+                                                        character: 35
+                                                      token_type:
+                                                        type: Identifier
+                                                        identifier: IsDescendantOf
+                                                    trailing_trivia: []
+                                                  args:
+                                                    Parentheses:
+                                                      parentheses:
+                                                        tokens:
+                                                          - leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 1202
+                                                                line: 50
+                                                                character: 35
+                                                              end_position:
+                                                                bytes: 1203
+                                                                line: 50
+                                                                character: 36
+                                                              token_type:
+                                                                type: Symbol
+                                                                symbol: (
+                                                            trailing_trivia: []
+                                                          - leading_trivia: []
+                                                            token:
+                                                              start_position:
+                                                                bytes: 1212
+                                                                line: 50
+                                                                character: 45
+                                                              end_position:
+                                                                bytes: 1213
+                                                                line: 50
+                                                                character: 46
+                                                              token_type:
+                                                                type: Symbol
+                                                                symbol: )
+                                                            trailing_trivia: []
+                                                      arguments:
+                                                        pairs:
+                                                          - End:
+                                                              Var:
+                                                                Name:
+                                                                  leading_trivia: []
+                                                                  token:
+                                                                    start_position:
+                                                                      bytes: 1203
+                                                                      line: 50
+                                                                      character: 36
+                                                                    end_position:
+                                                                      bytes: 1212
+                                                                      line: 50
+                                                                      character: 45
+                                                                    token_type:
+                                                                      type: Identifier
+                                                                      identifier: character
+                                                                  trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 1213
+                                        line: 50
+                                        character: 46
+                                      end_position:
+                                        bytes: 1214
+                                        line: 50
+                                        character: 47
+                                      token_type:
+                                        type: Symbol
+                                        symbol: ","
+                                    trailing_trivia:
+                                      - start_position:
+                                          bytes: 1214
+                                          line: 50
+                                          character: 47
+                                        end_position:
+                                          bytes: 1215
+                                          line: 50
+                                          character: 48
+                                        token_type:
+                                          type: Whitespace
+                                          characters: " "
+                              - End:
+                                  Var:
+                                    Name:
+                                      leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 1215
+                                          line: 50
+                                          character: 48
+                                        end_position:
+                                          bytes: 1220
+                                          line: 50
+                                          character: 53
+                                        token_type:
+                                          type: Identifier
+                                          identifier: point
+                                      trailing_trivia:
+                                        - start_position:
+                                            bytes: 1220
+                                            line: 50
+                                            character: 53
+                                          end_position:
+                                            bytes: 1221
+                                            line: 50
+                                            character: 53
+                                          token_type:
+                                            type: Whitespace
+                                            characters: "\n"
+                      - ~
+                  end_token:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 1221
+                        line: 51
+                        character: 1
+                      end_position:
+                        bytes: 1224
+                        line: 51
+                        character: 4
+                      token_type:
+                        type: Symbol
+                        symbol: end
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 1224
+                          line: 51
+                          character: 4
+                        end_position:
+                          bytes: 1225
+                          line: 51
+                          character: 4
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+  - ~
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/no_roblox_syntax/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/no_roblox_syntax/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..e86cb5822206891b034e255015f9c2a094566b50
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/no_roblox_syntax/source.lua
@@ -0,0 +1,51 @@
+-- Taken from https://raw.githubusercontent.com/Kampfkarren/Roblox/master/Modules/LineOfSight.lua
+local ReplicatedStorage = game:GetService("ReplicatedStorage")
+local RunService = game:GetService("RunService")
+
+local Raycast = require(ReplicatedStorage.Modules.Raycast)
+
+local DEBUG = true
+DEBUG = DEBUG and RunService:IsStudio()
+
+local debug
+
+if DEBUG then
+	function debug(table)
+		print("[LineOfSight]", table)
+	end
+else
+	function debug()
+	end
+end
+
+return function(origin, character, range, ignoreIf, blacklist)
+	if typeof(origin) == "Instance" then
+		if origin.Position:FuzzyEq(character.PrimaryPart.Position) then
+			debug("ORIGIN WAS CHARACTER")
+			return origin, origin.Position
+		end
+
+		origin = origin.Position
+	end
+
+	blacklist = blacklist or {}
+
+	local hit, point do
+		while true do
+			hit, point = Raycast(Ray.new(origin, (origin - character.PrimaryPart.Position).Unit * -range), blacklist)
+
+			if hit and hit:IsDescendantOf(character) then
+				break
+			elseif hit and ignoreIf(hit) then
+				debug("IGNORING OFF IF", hit:GetFullName())
+				blacklist[#blacklist + 1] = hit
+			else
+				break
+			end
+		end
+	end
+
+	debug("LOS RESULT", hit and hit:GetFullName())
+
+	return hit and hit:IsDescendantOf(character), point
+end
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/no_roblox_syntax/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/no_roblox_syntax/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..1398d79266a7379872f00a5001eaf14de2185037
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/no_roblox_syntax/tokens.snap
@@ -0,0 +1,4246 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/roblox_cases/pass/no_roblox_syntax
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 97
+    line: 1
+    character: 98
+  token_type:
+    type: SingleLineComment
+    comment: " Taken from https://raw.githubusercontent.com/Kampfkarren/Roblox/master/Modules/LineOfSight.lua"
+- start_position:
+    bytes: 97
+    line: 1
+    character: 98
+  end_position:
+    bytes: 98
+    line: 1
+    character: 98
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 98
+    line: 2
+    character: 1
+  end_position:
+    bytes: 103
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 103
+    line: 2
+    character: 6
+  end_position:
+    bytes: 104
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 104
+    line: 2
+    character: 7
+  end_position:
+    bytes: 121
+    line: 2
+    character: 24
+  token_type:
+    type: Identifier
+    identifier: ReplicatedStorage
+- start_position:
+    bytes: 121
+    line: 2
+    character: 24
+  end_position:
+    bytes: 122
+    line: 2
+    character: 25
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 122
+    line: 2
+    character: 25
+  end_position:
+    bytes: 123
+    line: 2
+    character: 26
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 123
+    line: 2
+    character: 26
+  end_position:
+    bytes: 124
+    line: 2
+    character: 27
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 124
+    line: 2
+    character: 27
+  end_position:
+    bytes: 128
+    line: 2
+    character: 31
+  token_type:
+    type: Identifier
+    identifier: game
+- start_position:
+    bytes: 128
+    line: 2
+    character: 31
+  end_position:
+    bytes: 129
+    line: 2
+    character: 32
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 129
+    line: 2
+    character: 32
+  end_position:
+    bytes: 139
+    line: 2
+    character: 42
+  token_type:
+    type: Identifier
+    identifier: GetService
+- start_position:
+    bytes: 139
+    line: 2
+    character: 42
+  end_position:
+    bytes: 140
+    line: 2
+    character: 43
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 140
+    line: 2
+    character: 43
+  end_position:
+    bytes: 159
+    line: 2
+    character: 62
+  token_type:
+    type: StringLiteral
+    literal: ReplicatedStorage
+    quote_type: Double
+- start_position:
+    bytes: 159
+    line: 2
+    character: 62
+  end_position:
+    bytes: 160
+    line: 2
+    character: 63
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 160
+    line: 2
+    character: 63
+  end_position:
+    bytes: 161
+    line: 2
+    character: 63
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 161
+    line: 3
+    character: 1
+  end_position:
+    bytes: 166
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 166
+    line: 3
+    character: 6
+  end_position:
+    bytes: 167
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 167
+    line: 3
+    character: 7
+  end_position:
+    bytes: 177
+    line: 3
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: RunService
+- start_position:
+    bytes: 177
+    line: 3
+    character: 17
+  end_position:
+    bytes: 178
+    line: 3
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 178
+    line: 3
+    character: 18
+  end_position:
+    bytes: 179
+    line: 3
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 179
+    line: 3
+    character: 19
+  end_position:
+    bytes: 180
+    line: 3
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 180
+    line: 3
+    character: 20
+  end_position:
+    bytes: 184
+    line: 3
+    character: 24
+  token_type:
+    type: Identifier
+    identifier: game
+- start_position:
+    bytes: 184
+    line: 3
+    character: 24
+  end_position:
+    bytes: 185
+    line: 3
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 185
+    line: 3
+    character: 25
+  end_position:
+    bytes: 195
+    line: 3
+    character: 35
+  token_type:
+    type: Identifier
+    identifier: GetService
+- start_position:
+    bytes: 195
+    line: 3
+    character: 35
+  end_position:
+    bytes: 196
+    line: 3
+    character: 36
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 196
+    line: 3
+    character: 36
+  end_position:
+    bytes: 208
+    line: 3
+    character: 48
+  token_type:
+    type: StringLiteral
+    literal: RunService
+    quote_type: Double
+- start_position:
+    bytes: 208
+    line: 3
+    character: 48
+  end_position:
+    bytes: 209
+    line: 3
+    character: 49
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 209
+    line: 3
+    character: 49
+  end_position:
+    bytes: 210
+    line: 3
+    character: 49
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 210
+    line: 4
+    character: 1
+  end_position:
+    bytes: 211
+    line: 4
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 211
+    line: 5
+    character: 1
+  end_position:
+    bytes: 216
+    line: 5
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 216
+    line: 5
+    character: 6
+  end_position:
+    bytes: 217
+    line: 5
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 217
+    line: 5
+    character: 7
+  end_position:
+    bytes: 224
+    line: 5
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: Raycast
+- start_position:
+    bytes: 224
+    line: 5
+    character: 14
+  end_position:
+    bytes: 225
+    line: 5
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 225
+    line: 5
+    character: 15
+  end_position:
+    bytes: 226
+    line: 5
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 226
+    line: 5
+    character: 16
+  end_position:
+    bytes: 227
+    line: 5
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 227
+    line: 5
+    character: 17
+  end_position:
+    bytes: 234
+    line: 5
+    character: 24
+  token_type:
+    type: Identifier
+    identifier: require
+- start_position:
+    bytes: 234
+    line: 5
+    character: 24
+  end_position:
+    bytes: 235
+    line: 5
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 235
+    line: 5
+    character: 25
+  end_position:
+    bytes: 252
+    line: 5
+    character: 42
+  token_type:
+    type: Identifier
+    identifier: ReplicatedStorage
+- start_position:
+    bytes: 252
+    line: 5
+    character: 42
+  end_position:
+    bytes: 253
+    line: 5
+    character: 43
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 253
+    line: 5
+    character: 43
+  end_position:
+    bytes: 260
+    line: 5
+    character: 50
+  token_type:
+    type: Identifier
+    identifier: Modules
+- start_position:
+    bytes: 260
+    line: 5
+    character: 50
+  end_position:
+    bytes: 261
+    line: 5
+    character: 51
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 261
+    line: 5
+    character: 51
+  end_position:
+    bytes: 268
+    line: 5
+    character: 58
+  token_type:
+    type: Identifier
+    identifier: Raycast
+- start_position:
+    bytes: 268
+    line: 5
+    character: 58
+  end_position:
+    bytes: 269
+    line: 5
+    character: 59
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 269
+    line: 5
+    character: 59
+  end_position:
+    bytes: 270
+    line: 5
+    character: 59
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 270
+    line: 6
+    character: 1
+  end_position:
+    bytes: 271
+    line: 6
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 271
+    line: 7
+    character: 1
+  end_position:
+    bytes: 276
+    line: 7
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 276
+    line: 7
+    character: 6
+  end_position:
+    bytes: 277
+    line: 7
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 277
+    line: 7
+    character: 7
+  end_position:
+    bytes: 282
+    line: 7
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: DEBUG
+- start_position:
+    bytes: 282
+    line: 7
+    character: 12
+  end_position:
+    bytes: 283
+    line: 7
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 283
+    line: 7
+    character: 13
+  end_position:
+    bytes: 284
+    line: 7
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 284
+    line: 7
+    character: 14
+  end_position:
+    bytes: 285
+    line: 7
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 285
+    line: 7
+    character: 15
+  end_position:
+    bytes: 289
+    line: 7
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 289
+    line: 7
+    character: 19
+  end_position:
+    bytes: 290
+    line: 7
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 290
+    line: 8
+    character: 1
+  end_position:
+    bytes: 295
+    line: 8
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: DEBUG
+- start_position:
+    bytes: 295
+    line: 8
+    character: 6
+  end_position:
+    bytes: 296
+    line: 8
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 296
+    line: 8
+    character: 7
+  end_position:
+    bytes: 297
+    line: 8
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 297
+    line: 8
+    character: 8
+  end_position:
+    bytes: 298
+    line: 8
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 298
+    line: 8
+    character: 9
+  end_position:
+    bytes: 303
+    line: 8
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: DEBUG
+- start_position:
+    bytes: 303
+    line: 8
+    character: 14
+  end_position:
+    bytes: 304
+    line: 8
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 304
+    line: 8
+    character: 15
+  end_position:
+    bytes: 307
+    line: 8
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: and
+- start_position:
+    bytes: 307
+    line: 8
+    character: 18
+  end_position:
+    bytes: 308
+    line: 8
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 308
+    line: 8
+    character: 19
+  end_position:
+    bytes: 318
+    line: 8
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: RunService
+- start_position:
+    bytes: 318
+    line: 8
+    character: 29
+  end_position:
+    bytes: 319
+    line: 8
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 319
+    line: 8
+    character: 30
+  end_position:
+    bytes: 327
+    line: 8
+    character: 38
+  token_type:
+    type: Identifier
+    identifier: IsStudio
+- start_position:
+    bytes: 327
+    line: 8
+    character: 38
+  end_position:
+    bytes: 328
+    line: 8
+    character: 39
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 328
+    line: 8
+    character: 39
+  end_position:
+    bytes: 329
+    line: 8
+    character: 40
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 329
+    line: 8
+    character: 40
+  end_position:
+    bytes: 330
+    line: 8
+    character: 40
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 330
+    line: 9
+    character: 1
+  end_position:
+    bytes: 331
+    line: 9
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 331
+    line: 10
+    character: 1
+  end_position:
+    bytes: 336
+    line: 10
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 336
+    line: 10
+    character: 6
+  end_position:
+    bytes: 337
+    line: 10
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 337
+    line: 10
+    character: 7
+  end_position:
+    bytes: 342
+    line: 10
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: debug
+- start_position:
+    bytes: 342
+    line: 10
+    character: 12
+  end_position:
+    bytes: 343
+    line: 10
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 343
+    line: 11
+    character: 1
+  end_position:
+    bytes: 344
+    line: 11
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 344
+    line: 12
+    character: 1
+  end_position:
+    bytes: 346
+    line: 12
+    character: 3
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 346
+    line: 12
+    character: 3
+  end_position:
+    bytes: 347
+    line: 12
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 347
+    line: 12
+    character: 4
+  end_position:
+    bytes: 352
+    line: 12
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: DEBUG
+- start_position:
+    bytes: 352
+    line: 12
+    character: 9
+  end_position:
+    bytes: 353
+    line: 12
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 353
+    line: 12
+    character: 10
+  end_position:
+    bytes: 357
+    line: 12
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 357
+    line: 12
+    character: 14
+  end_position:
+    bytes: 358
+    line: 12
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 358
+    line: 13
+    character: 1
+  end_position:
+    bytes: 359
+    line: 13
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 359
+    line: 13
+    character: 2
+  end_position:
+    bytes: 367
+    line: 13
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: function
+- start_position:
+    bytes: 367
+    line: 13
+    character: 10
+  end_position:
+    bytes: 368
+    line: 13
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 368
+    line: 13
+    character: 11
+  end_position:
+    bytes: 373
+    line: 13
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: debug
+- start_position:
+    bytes: 373
+    line: 13
+    character: 16
+  end_position:
+    bytes: 374
+    line: 13
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 374
+    line: 13
+    character: 17
+  end_position:
+    bytes: 379
+    line: 13
+    character: 22
+  token_type:
+    type: Identifier
+    identifier: table
+- start_position:
+    bytes: 379
+    line: 13
+    character: 22
+  end_position:
+    bytes: 380
+    line: 13
+    character: 23
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 380
+    line: 13
+    character: 23
+  end_position:
+    bytes: 381
+    line: 13
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 381
+    line: 14
+    character: 1
+  end_position:
+    bytes: 383
+    line: 14
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\t\t"
+- start_position:
+    bytes: 383
+    line: 14
+    character: 3
+  end_position:
+    bytes: 388
+    line: 14
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: print
+- start_position:
+    bytes: 388
+    line: 14
+    character: 8
+  end_position:
+    bytes: 389
+    line: 14
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 389
+    line: 14
+    character: 9
+  end_position:
+    bytes: 404
+    line: 14
+    character: 24
+  token_type:
+    type: StringLiteral
+    literal: "[LineOfSight]"
+    quote_type: Double
+- start_position:
+    bytes: 404
+    line: 14
+    character: 24
+  end_position:
+    bytes: 405
+    line: 14
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 405
+    line: 14
+    character: 25
+  end_position:
+    bytes: 406
+    line: 14
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 406
+    line: 14
+    character: 26
+  end_position:
+    bytes: 411
+    line: 14
+    character: 31
+  token_type:
+    type: Identifier
+    identifier: table
+- start_position:
+    bytes: 411
+    line: 14
+    character: 31
+  end_position:
+    bytes: 412
+    line: 14
+    character: 32
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 412
+    line: 14
+    character: 32
+  end_position:
+    bytes: 413
+    line: 14
+    character: 32
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 413
+    line: 15
+    character: 1
+  end_position:
+    bytes: 414
+    line: 15
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 414
+    line: 15
+    character: 2
+  end_position:
+    bytes: 417
+    line: 15
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 417
+    line: 15
+    character: 5
+  end_position:
+    bytes: 418
+    line: 15
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 418
+    line: 16
+    character: 1
+  end_position:
+    bytes: 422
+    line: 16
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 422
+    line: 16
+    character: 5
+  end_position:
+    bytes: 423
+    line: 16
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 423
+    line: 17
+    character: 1
+  end_position:
+    bytes: 424
+    line: 17
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 424
+    line: 17
+    character: 2
+  end_position:
+    bytes: 432
+    line: 17
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: function
+- start_position:
+    bytes: 432
+    line: 17
+    character: 10
+  end_position:
+    bytes: 433
+    line: 17
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 433
+    line: 17
+    character: 11
+  end_position:
+    bytes: 438
+    line: 17
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: debug
+- start_position:
+    bytes: 438
+    line: 17
+    character: 16
+  end_position:
+    bytes: 439
+    line: 17
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 439
+    line: 17
+    character: 17
+  end_position:
+    bytes: 440
+    line: 17
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 440
+    line: 17
+    character: 18
+  end_position:
+    bytes: 441
+    line: 17
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 441
+    line: 18
+    character: 1
+  end_position:
+    bytes: 442
+    line: 18
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 442
+    line: 18
+    character: 2
+  end_position:
+    bytes: 445
+    line: 18
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 445
+    line: 18
+    character: 5
+  end_position:
+    bytes: 446
+    line: 18
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 446
+    line: 19
+    character: 1
+  end_position:
+    bytes: 449
+    line: 19
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 449
+    line: 19
+    character: 4
+  end_position:
+    bytes: 450
+    line: 19
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 450
+    line: 20
+    character: 1
+  end_position:
+    bytes: 451
+    line: 20
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 451
+    line: 21
+    character: 1
+  end_position:
+    bytes: 457
+    line: 21
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 457
+    line: 21
+    character: 7
+  end_position:
+    bytes: 458
+    line: 21
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 458
+    line: 21
+    character: 8
+  end_position:
+    bytes: 466
+    line: 21
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: function
+- start_position:
+    bytes: 466
+    line: 21
+    character: 16
+  end_position:
+    bytes: 467
+    line: 21
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 467
+    line: 21
+    character: 17
+  end_position:
+    bytes: 473
+    line: 21
+    character: 23
+  token_type:
+    type: Identifier
+    identifier: origin
+- start_position:
+    bytes: 473
+    line: 21
+    character: 23
+  end_position:
+    bytes: 474
+    line: 21
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 474
+    line: 21
+    character: 24
+  end_position:
+    bytes: 475
+    line: 21
+    character: 25
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 475
+    line: 21
+    character: 25
+  end_position:
+    bytes: 484
+    line: 21
+    character: 34
+  token_type:
+    type: Identifier
+    identifier: character
+- start_position:
+    bytes: 484
+    line: 21
+    character: 34
+  end_position:
+    bytes: 485
+    line: 21
+    character: 35
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 485
+    line: 21
+    character: 35
+  end_position:
+    bytes: 486
+    line: 21
+    character: 36
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 486
+    line: 21
+    character: 36
+  end_position:
+    bytes: 491
+    line: 21
+    character: 41
+  token_type:
+    type: Identifier
+    identifier: range
+- start_position:
+    bytes: 491
+    line: 21
+    character: 41
+  end_position:
+    bytes: 492
+    line: 21
+    character: 42
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 492
+    line: 21
+    character: 42
+  end_position:
+    bytes: 493
+    line: 21
+    character: 43
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 493
+    line: 21
+    character: 43
+  end_position:
+    bytes: 501
+    line: 21
+    character: 51
+  token_type:
+    type: Identifier
+    identifier: ignoreIf
+- start_position:
+    bytes: 501
+    line: 21
+    character: 51
+  end_position:
+    bytes: 502
+    line: 21
+    character: 52
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 502
+    line: 21
+    character: 52
+  end_position:
+    bytes: 503
+    line: 21
+    character: 53
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 503
+    line: 21
+    character: 53
+  end_position:
+    bytes: 512
+    line: 21
+    character: 62
+  token_type:
+    type: Identifier
+    identifier: blacklist
+- start_position:
+    bytes: 512
+    line: 21
+    character: 62
+  end_position:
+    bytes: 513
+    line: 21
+    character: 63
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 513
+    line: 21
+    character: 63
+  end_position:
+    bytes: 514
+    line: 21
+    character: 63
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 514
+    line: 22
+    character: 1
+  end_position:
+    bytes: 515
+    line: 22
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 515
+    line: 22
+    character: 2
+  end_position:
+    bytes: 517
+    line: 22
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 517
+    line: 22
+    character: 4
+  end_position:
+    bytes: 518
+    line: 22
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 518
+    line: 22
+    character: 5
+  end_position:
+    bytes: 524
+    line: 22
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: typeof
+- start_position:
+    bytes: 524
+    line: 22
+    character: 11
+  end_position:
+    bytes: 525
+    line: 22
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 525
+    line: 22
+    character: 12
+  end_position:
+    bytes: 531
+    line: 22
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: origin
+- start_position:
+    bytes: 531
+    line: 22
+    character: 18
+  end_position:
+    bytes: 532
+    line: 22
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 532
+    line: 22
+    character: 19
+  end_position:
+    bytes: 533
+    line: 22
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 533
+    line: 22
+    character: 20
+  end_position:
+    bytes: 535
+    line: 22
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: "=="
+- start_position:
+    bytes: 535
+    line: 22
+    character: 22
+  end_position:
+    bytes: 536
+    line: 22
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 536
+    line: 22
+    character: 23
+  end_position:
+    bytes: 546
+    line: 22
+    character: 33
+  token_type:
+    type: StringLiteral
+    literal: Instance
+    quote_type: Double
+- start_position:
+    bytes: 546
+    line: 22
+    character: 33
+  end_position:
+    bytes: 547
+    line: 22
+    character: 34
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 547
+    line: 22
+    character: 34
+  end_position:
+    bytes: 551
+    line: 22
+    character: 38
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 551
+    line: 22
+    character: 38
+  end_position:
+    bytes: 552
+    line: 22
+    character: 38
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 552
+    line: 23
+    character: 1
+  end_position:
+    bytes: 554
+    line: 23
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\t\t"
+- start_position:
+    bytes: 554
+    line: 23
+    character: 3
+  end_position:
+    bytes: 556
+    line: 23
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 556
+    line: 23
+    character: 5
+  end_position:
+    bytes: 557
+    line: 23
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 557
+    line: 23
+    character: 6
+  end_position:
+    bytes: 563
+    line: 23
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: origin
+- start_position:
+    bytes: 563
+    line: 23
+    character: 12
+  end_position:
+    bytes: 564
+    line: 23
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 564
+    line: 23
+    character: 13
+  end_position:
+    bytes: 572
+    line: 23
+    character: 21
+  token_type:
+    type: Identifier
+    identifier: Position
+- start_position:
+    bytes: 572
+    line: 23
+    character: 21
+  end_position:
+    bytes: 573
+    line: 23
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 573
+    line: 23
+    character: 22
+  end_position:
+    bytes: 580
+    line: 23
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: FuzzyEq
+- start_position:
+    bytes: 580
+    line: 23
+    character: 29
+  end_position:
+    bytes: 581
+    line: 23
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 581
+    line: 23
+    character: 30
+  end_position:
+    bytes: 590
+    line: 23
+    character: 39
+  token_type:
+    type: Identifier
+    identifier: character
+- start_position:
+    bytes: 590
+    line: 23
+    character: 39
+  end_position:
+    bytes: 591
+    line: 23
+    character: 40
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 591
+    line: 23
+    character: 40
+  end_position:
+    bytes: 602
+    line: 23
+    character: 51
+  token_type:
+    type: Identifier
+    identifier: PrimaryPart
+- start_position:
+    bytes: 602
+    line: 23
+    character: 51
+  end_position:
+    bytes: 603
+    line: 23
+    character: 52
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 603
+    line: 23
+    character: 52
+  end_position:
+    bytes: 611
+    line: 23
+    character: 60
+  token_type:
+    type: Identifier
+    identifier: Position
+- start_position:
+    bytes: 611
+    line: 23
+    character: 60
+  end_position:
+    bytes: 612
+    line: 23
+    character: 61
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 612
+    line: 23
+    character: 61
+  end_position:
+    bytes: 613
+    line: 23
+    character: 62
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 613
+    line: 23
+    character: 62
+  end_position:
+    bytes: 617
+    line: 23
+    character: 66
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 617
+    line: 23
+    character: 66
+  end_position:
+    bytes: 618
+    line: 23
+    character: 66
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 618
+    line: 24
+    character: 1
+  end_position:
+    bytes: 621
+    line: 24
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t"
+- start_position:
+    bytes: 621
+    line: 24
+    character: 4
+  end_position:
+    bytes: 626
+    line: 24
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: debug
+- start_position:
+    bytes: 626
+    line: 24
+    character: 9
+  end_position:
+    bytes: 627
+    line: 24
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 627
+    line: 24
+    character: 10
+  end_position:
+    bytes: 649
+    line: 24
+    character: 32
+  token_type:
+    type: StringLiteral
+    literal: ORIGIN WAS CHARACTER
+    quote_type: Double
+- start_position:
+    bytes: 649
+    line: 24
+    character: 32
+  end_position:
+    bytes: 650
+    line: 24
+    character: 33
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 650
+    line: 24
+    character: 33
+  end_position:
+    bytes: 651
+    line: 24
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 651
+    line: 25
+    character: 1
+  end_position:
+    bytes: 654
+    line: 25
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t"
+- start_position:
+    bytes: 654
+    line: 25
+    character: 4
+  end_position:
+    bytes: 660
+    line: 25
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 660
+    line: 25
+    character: 10
+  end_position:
+    bytes: 661
+    line: 25
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 661
+    line: 25
+    character: 11
+  end_position:
+    bytes: 667
+    line: 25
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: origin
+- start_position:
+    bytes: 667
+    line: 25
+    character: 17
+  end_position:
+    bytes: 668
+    line: 25
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 668
+    line: 25
+    character: 18
+  end_position:
+    bytes: 669
+    line: 25
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 669
+    line: 25
+    character: 19
+  end_position:
+    bytes: 675
+    line: 25
+    character: 25
+  token_type:
+    type: Identifier
+    identifier: origin
+- start_position:
+    bytes: 675
+    line: 25
+    character: 25
+  end_position:
+    bytes: 676
+    line: 25
+    character: 26
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 676
+    line: 25
+    character: 26
+  end_position:
+    bytes: 684
+    line: 25
+    character: 34
+  token_type:
+    type: Identifier
+    identifier: Position
+- start_position:
+    bytes: 684
+    line: 25
+    character: 34
+  end_position:
+    bytes: 685
+    line: 25
+    character: 34
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 685
+    line: 26
+    character: 1
+  end_position:
+    bytes: 687
+    line: 26
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\t\t"
+- start_position:
+    bytes: 687
+    line: 26
+    character: 3
+  end_position:
+    bytes: 690
+    line: 26
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 690
+    line: 26
+    character: 6
+  end_position:
+    bytes: 691
+    line: 26
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 691
+    line: 27
+    character: 1
+  end_position:
+    bytes: 692
+    line: 27
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 692
+    line: 28
+    character: 1
+  end_position:
+    bytes: 694
+    line: 28
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\t\t"
+- start_position:
+    bytes: 694
+    line: 28
+    character: 3
+  end_position:
+    bytes: 700
+    line: 28
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: origin
+- start_position:
+    bytes: 700
+    line: 28
+    character: 9
+  end_position:
+    bytes: 701
+    line: 28
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 701
+    line: 28
+    character: 10
+  end_position:
+    bytes: 702
+    line: 28
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 702
+    line: 28
+    character: 11
+  end_position:
+    bytes: 703
+    line: 28
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 703
+    line: 28
+    character: 12
+  end_position:
+    bytes: 709
+    line: 28
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: origin
+- start_position:
+    bytes: 709
+    line: 28
+    character: 18
+  end_position:
+    bytes: 710
+    line: 28
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 710
+    line: 28
+    character: 19
+  end_position:
+    bytes: 718
+    line: 28
+    character: 27
+  token_type:
+    type: Identifier
+    identifier: Position
+- start_position:
+    bytes: 718
+    line: 28
+    character: 27
+  end_position:
+    bytes: 719
+    line: 28
+    character: 27
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 719
+    line: 29
+    character: 1
+  end_position:
+    bytes: 720
+    line: 29
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 720
+    line: 29
+    character: 2
+  end_position:
+    bytes: 723
+    line: 29
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 723
+    line: 29
+    character: 5
+  end_position:
+    bytes: 724
+    line: 29
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 724
+    line: 30
+    character: 1
+  end_position:
+    bytes: 725
+    line: 30
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 725
+    line: 31
+    character: 1
+  end_position:
+    bytes: 726
+    line: 31
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 726
+    line: 31
+    character: 2
+  end_position:
+    bytes: 735
+    line: 31
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: blacklist
+- start_position:
+    bytes: 735
+    line: 31
+    character: 11
+  end_position:
+    bytes: 736
+    line: 31
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 736
+    line: 31
+    character: 12
+  end_position:
+    bytes: 737
+    line: 31
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 737
+    line: 31
+    character: 13
+  end_position:
+    bytes: 738
+    line: 31
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 738
+    line: 31
+    character: 14
+  end_position:
+    bytes: 747
+    line: 31
+    character: 23
+  token_type:
+    type: Identifier
+    identifier: blacklist
+- start_position:
+    bytes: 747
+    line: 31
+    character: 23
+  end_position:
+    bytes: 748
+    line: 31
+    character: 24
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 748
+    line: 31
+    character: 24
+  end_position:
+    bytes: 750
+    line: 31
+    character: 26
+  token_type:
+    type: Symbol
+    symbol: or
+- start_position:
+    bytes: 750
+    line: 31
+    character: 26
+  end_position:
+    bytes: 751
+    line: 31
+    character: 27
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 751
+    line: 31
+    character: 27
+  end_position:
+    bytes: 752
+    line: 31
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 752
+    line: 31
+    character: 28
+  end_position:
+    bytes: 753
+    line: 31
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 753
+    line: 31
+    character: 29
+  end_position:
+    bytes: 754
+    line: 31
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 754
+    line: 32
+    character: 1
+  end_position:
+    bytes: 755
+    line: 32
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 755
+    line: 33
+    character: 1
+  end_position:
+    bytes: 756
+    line: 33
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 756
+    line: 33
+    character: 2
+  end_position:
+    bytes: 761
+    line: 33
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 761
+    line: 33
+    character: 7
+  end_position:
+    bytes: 762
+    line: 33
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 762
+    line: 33
+    character: 8
+  end_position:
+    bytes: 765
+    line: 33
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 765
+    line: 33
+    character: 11
+  end_position:
+    bytes: 766
+    line: 33
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 766
+    line: 33
+    character: 12
+  end_position:
+    bytes: 767
+    line: 33
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 767
+    line: 33
+    character: 13
+  end_position:
+    bytes: 772
+    line: 33
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: point
+- start_position:
+    bytes: 772
+    line: 33
+    character: 18
+  end_position:
+    bytes: 773
+    line: 33
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 773
+    line: 33
+    character: 19
+  end_position:
+    bytes: 775
+    line: 33
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 775
+    line: 33
+    character: 21
+  end_position:
+    bytes: 776
+    line: 33
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 776
+    line: 34
+    character: 1
+  end_position:
+    bytes: 778
+    line: 34
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\t\t"
+- start_position:
+    bytes: 778
+    line: 34
+    character: 3
+  end_position:
+    bytes: 783
+    line: 34
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: while
+- start_position:
+    bytes: 783
+    line: 34
+    character: 8
+  end_position:
+    bytes: 784
+    line: 34
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 784
+    line: 34
+    character: 9
+  end_position:
+    bytes: 788
+    line: 34
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "true"
+- start_position:
+    bytes: 788
+    line: 34
+    character: 13
+  end_position:
+    bytes: 789
+    line: 34
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 789
+    line: 34
+    character: 14
+  end_position:
+    bytes: 791
+    line: 34
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 791
+    line: 34
+    character: 16
+  end_position:
+    bytes: 792
+    line: 34
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 792
+    line: 35
+    character: 1
+  end_position:
+    bytes: 795
+    line: 35
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t"
+- start_position:
+    bytes: 795
+    line: 35
+    character: 4
+  end_position:
+    bytes: 798
+    line: 35
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 798
+    line: 35
+    character: 7
+  end_position:
+    bytes: 799
+    line: 35
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 799
+    line: 35
+    character: 8
+  end_position:
+    bytes: 800
+    line: 35
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 800
+    line: 35
+    character: 9
+  end_position:
+    bytes: 805
+    line: 35
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: point
+- start_position:
+    bytes: 805
+    line: 35
+    character: 14
+  end_position:
+    bytes: 806
+    line: 35
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 806
+    line: 35
+    character: 15
+  end_position:
+    bytes: 807
+    line: 35
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 807
+    line: 35
+    character: 16
+  end_position:
+    bytes: 808
+    line: 35
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 808
+    line: 35
+    character: 17
+  end_position:
+    bytes: 815
+    line: 35
+    character: 24
+  token_type:
+    type: Identifier
+    identifier: Raycast
+- start_position:
+    bytes: 815
+    line: 35
+    character: 24
+  end_position:
+    bytes: 816
+    line: 35
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 816
+    line: 35
+    character: 25
+  end_position:
+    bytes: 819
+    line: 35
+    character: 28
+  token_type:
+    type: Identifier
+    identifier: Ray
+- start_position:
+    bytes: 819
+    line: 35
+    character: 28
+  end_position:
+    bytes: 820
+    line: 35
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 820
+    line: 35
+    character: 29
+  end_position:
+    bytes: 823
+    line: 35
+    character: 32
+  token_type:
+    type: Identifier
+    identifier: new
+- start_position:
+    bytes: 823
+    line: 35
+    character: 32
+  end_position:
+    bytes: 824
+    line: 35
+    character: 33
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 824
+    line: 35
+    character: 33
+  end_position:
+    bytes: 830
+    line: 35
+    character: 39
+  token_type:
+    type: Identifier
+    identifier: origin
+- start_position:
+    bytes: 830
+    line: 35
+    character: 39
+  end_position:
+    bytes: 831
+    line: 35
+    character: 40
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 831
+    line: 35
+    character: 40
+  end_position:
+    bytes: 832
+    line: 35
+    character: 41
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 832
+    line: 35
+    character: 41
+  end_position:
+    bytes: 833
+    line: 35
+    character: 42
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 833
+    line: 35
+    character: 42
+  end_position:
+    bytes: 839
+    line: 35
+    character: 48
+  token_type:
+    type: Identifier
+    identifier: origin
+- start_position:
+    bytes: 839
+    line: 35
+    character: 48
+  end_position:
+    bytes: 840
+    line: 35
+    character: 49
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 840
+    line: 35
+    character: 49
+  end_position:
+    bytes: 841
+    line: 35
+    character: 50
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 841
+    line: 35
+    character: 50
+  end_position:
+    bytes: 842
+    line: 35
+    character: 51
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 842
+    line: 35
+    character: 51
+  end_position:
+    bytes: 851
+    line: 35
+    character: 60
+  token_type:
+    type: Identifier
+    identifier: character
+- start_position:
+    bytes: 851
+    line: 35
+    character: 60
+  end_position:
+    bytes: 852
+    line: 35
+    character: 61
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 852
+    line: 35
+    character: 61
+  end_position:
+    bytes: 863
+    line: 35
+    character: 72
+  token_type:
+    type: Identifier
+    identifier: PrimaryPart
+- start_position:
+    bytes: 863
+    line: 35
+    character: 72
+  end_position:
+    bytes: 864
+    line: 35
+    character: 73
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 864
+    line: 35
+    character: 73
+  end_position:
+    bytes: 872
+    line: 35
+    character: 81
+  token_type:
+    type: Identifier
+    identifier: Position
+- start_position:
+    bytes: 872
+    line: 35
+    character: 81
+  end_position:
+    bytes: 873
+    line: 35
+    character: 82
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 873
+    line: 35
+    character: 82
+  end_position:
+    bytes: 874
+    line: 35
+    character: 83
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 874
+    line: 35
+    character: 83
+  end_position:
+    bytes: 878
+    line: 35
+    character: 87
+  token_type:
+    type: Identifier
+    identifier: Unit
+- start_position:
+    bytes: 878
+    line: 35
+    character: 87
+  end_position:
+    bytes: 879
+    line: 35
+    character: 88
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 879
+    line: 35
+    character: 88
+  end_position:
+    bytes: 880
+    line: 35
+    character: 89
+  token_type:
+    type: Symbol
+    symbol: "*"
+- start_position:
+    bytes: 880
+    line: 35
+    character: 89
+  end_position:
+    bytes: 881
+    line: 35
+    character: 90
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 881
+    line: 35
+    character: 90
+  end_position:
+    bytes: 882
+    line: 35
+    character: 91
+  token_type:
+    type: Symbol
+    symbol: "-"
+- start_position:
+    bytes: 882
+    line: 35
+    character: 91
+  end_position:
+    bytes: 887
+    line: 35
+    character: 96
+  token_type:
+    type: Identifier
+    identifier: range
+- start_position:
+    bytes: 887
+    line: 35
+    character: 96
+  end_position:
+    bytes: 888
+    line: 35
+    character: 97
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 888
+    line: 35
+    character: 97
+  end_position:
+    bytes: 889
+    line: 35
+    character: 98
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 889
+    line: 35
+    character: 98
+  end_position:
+    bytes: 890
+    line: 35
+    character: 99
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 890
+    line: 35
+    character: 99
+  end_position:
+    bytes: 899
+    line: 35
+    character: 108
+  token_type:
+    type: Identifier
+    identifier: blacklist
+- start_position:
+    bytes: 899
+    line: 35
+    character: 108
+  end_position:
+    bytes: 900
+    line: 35
+    character: 109
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 900
+    line: 35
+    character: 109
+  end_position:
+    bytes: 901
+    line: 35
+    character: 109
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 901
+    line: 36
+    character: 1
+  end_position:
+    bytes: 902
+    line: 36
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 902
+    line: 37
+    character: 1
+  end_position:
+    bytes: 905
+    line: 37
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t"
+- start_position:
+    bytes: 905
+    line: 37
+    character: 4
+  end_position:
+    bytes: 907
+    line: 37
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 907
+    line: 37
+    character: 6
+  end_position:
+    bytes: 908
+    line: 37
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 908
+    line: 37
+    character: 7
+  end_position:
+    bytes: 911
+    line: 37
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 911
+    line: 37
+    character: 10
+  end_position:
+    bytes: 912
+    line: 37
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 912
+    line: 37
+    character: 11
+  end_position:
+    bytes: 915
+    line: 37
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: and
+- start_position:
+    bytes: 915
+    line: 37
+    character: 14
+  end_position:
+    bytes: 916
+    line: 37
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 916
+    line: 37
+    character: 15
+  end_position:
+    bytes: 919
+    line: 37
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 919
+    line: 37
+    character: 18
+  end_position:
+    bytes: 920
+    line: 37
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 920
+    line: 37
+    character: 19
+  end_position:
+    bytes: 934
+    line: 37
+    character: 33
+  token_type:
+    type: Identifier
+    identifier: IsDescendantOf
+- start_position:
+    bytes: 934
+    line: 37
+    character: 33
+  end_position:
+    bytes: 935
+    line: 37
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 935
+    line: 37
+    character: 34
+  end_position:
+    bytes: 944
+    line: 37
+    character: 43
+  token_type:
+    type: Identifier
+    identifier: character
+- start_position:
+    bytes: 944
+    line: 37
+    character: 43
+  end_position:
+    bytes: 945
+    line: 37
+    character: 44
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 945
+    line: 37
+    character: 44
+  end_position:
+    bytes: 946
+    line: 37
+    character: 45
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 946
+    line: 37
+    character: 45
+  end_position:
+    bytes: 950
+    line: 37
+    character: 49
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 950
+    line: 37
+    character: 49
+  end_position:
+    bytes: 951
+    line: 37
+    character: 49
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 951
+    line: 38
+    character: 1
+  end_position:
+    bytes: 955
+    line: 38
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t\t"
+- start_position:
+    bytes: 955
+    line: 38
+    character: 5
+  end_position:
+    bytes: 960
+    line: 38
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: break
+- start_position:
+    bytes: 960
+    line: 38
+    character: 10
+  end_position:
+    bytes: 961
+    line: 38
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 961
+    line: 39
+    character: 1
+  end_position:
+    bytes: 964
+    line: 39
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t"
+- start_position:
+    bytes: 964
+    line: 39
+    character: 4
+  end_position:
+    bytes: 970
+    line: 39
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: elseif
+- start_position:
+    bytes: 970
+    line: 39
+    character: 10
+  end_position:
+    bytes: 971
+    line: 39
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 971
+    line: 39
+    character: 11
+  end_position:
+    bytes: 974
+    line: 39
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 974
+    line: 39
+    character: 14
+  end_position:
+    bytes: 975
+    line: 39
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 975
+    line: 39
+    character: 15
+  end_position:
+    bytes: 978
+    line: 39
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: and
+- start_position:
+    bytes: 978
+    line: 39
+    character: 18
+  end_position:
+    bytes: 979
+    line: 39
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 979
+    line: 39
+    character: 19
+  end_position:
+    bytes: 987
+    line: 39
+    character: 27
+  token_type:
+    type: Identifier
+    identifier: ignoreIf
+- start_position:
+    bytes: 987
+    line: 39
+    character: 27
+  end_position:
+    bytes: 988
+    line: 39
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 988
+    line: 39
+    character: 28
+  end_position:
+    bytes: 991
+    line: 39
+    character: 31
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 991
+    line: 39
+    character: 31
+  end_position:
+    bytes: 992
+    line: 39
+    character: 32
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 992
+    line: 39
+    character: 32
+  end_position:
+    bytes: 993
+    line: 39
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 993
+    line: 39
+    character: 33
+  end_position:
+    bytes: 997
+    line: 39
+    character: 37
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 997
+    line: 39
+    character: 37
+  end_position:
+    bytes: 998
+    line: 39
+    character: 37
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 998
+    line: 40
+    character: 1
+  end_position:
+    bytes: 1002
+    line: 40
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t\t"
+- start_position:
+    bytes: 1002
+    line: 40
+    character: 5
+  end_position:
+    bytes: 1007
+    line: 40
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: debug
+- start_position:
+    bytes: 1007
+    line: 40
+    character: 10
+  end_position:
+    bytes: 1008
+    line: 40
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 1008
+    line: 40
+    character: 11
+  end_position:
+    bytes: 1025
+    line: 40
+    character: 28
+  token_type:
+    type: StringLiteral
+    literal: IGNORING OFF IF
+    quote_type: Double
+- start_position:
+    bytes: 1025
+    line: 40
+    character: 28
+  end_position:
+    bytes: 1026
+    line: 40
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 1026
+    line: 40
+    character: 29
+  end_position:
+    bytes: 1027
+    line: 40
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1027
+    line: 40
+    character: 30
+  end_position:
+    bytes: 1030
+    line: 40
+    character: 33
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 1030
+    line: 40
+    character: 33
+  end_position:
+    bytes: 1031
+    line: 40
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 1031
+    line: 40
+    character: 34
+  end_position:
+    bytes: 1042
+    line: 40
+    character: 45
+  token_type:
+    type: Identifier
+    identifier: GetFullName
+- start_position:
+    bytes: 1042
+    line: 40
+    character: 45
+  end_position:
+    bytes: 1043
+    line: 40
+    character: 46
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 1043
+    line: 40
+    character: 46
+  end_position:
+    bytes: 1044
+    line: 40
+    character: 47
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 1044
+    line: 40
+    character: 47
+  end_position:
+    bytes: 1045
+    line: 40
+    character: 48
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 1045
+    line: 40
+    character: 48
+  end_position:
+    bytes: 1046
+    line: 40
+    character: 48
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1046
+    line: 41
+    character: 1
+  end_position:
+    bytes: 1050
+    line: 41
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t\t"
+- start_position:
+    bytes: 1050
+    line: 41
+    character: 5
+  end_position:
+    bytes: 1059
+    line: 41
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: blacklist
+- start_position:
+    bytes: 1059
+    line: 41
+    character: 14
+  end_position:
+    bytes: 1060
+    line: 41
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 1060
+    line: 41
+    character: 15
+  end_position:
+    bytes: 1061
+    line: 41
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "#"
+- start_position:
+    bytes: 1061
+    line: 41
+    character: 16
+  end_position:
+    bytes: 1070
+    line: 41
+    character: 25
+  token_type:
+    type: Identifier
+    identifier: blacklist
+- start_position:
+    bytes: 1070
+    line: 41
+    character: 25
+  end_position:
+    bytes: 1071
+    line: 41
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1071
+    line: 41
+    character: 26
+  end_position:
+    bytes: 1072
+    line: 41
+    character: 27
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 1072
+    line: 41
+    character: 27
+  end_position:
+    bytes: 1073
+    line: 41
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1073
+    line: 41
+    character: 28
+  end_position:
+    bytes: 1074
+    line: 41
+    character: 29
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 1074
+    line: 41
+    character: 29
+  end_position:
+    bytes: 1075
+    line: 41
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 1075
+    line: 41
+    character: 30
+  end_position:
+    bytes: 1076
+    line: 41
+    character: 31
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1076
+    line: 41
+    character: 31
+  end_position:
+    bytes: 1077
+    line: 41
+    character: 32
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 1077
+    line: 41
+    character: 32
+  end_position:
+    bytes: 1078
+    line: 41
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1078
+    line: 41
+    character: 33
+  end_position:
+    bytes: 1081
+    line: 41
+    character: 36
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 1081
+    line: 41
+    character: 36
+  end_position:
+    bytes: 1082
+    line: 41
+    character: 36
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1082
+    line: 42
+    character: 1
+  end_position:
+    bytes: 1085
+    line: 42
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t"
+- start_position:
+    bytes: 1085
+    line: 42
+    character: 4
+  end_position:
+    bytes: 1089
+    line: 42
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: else
+- start_position:
+    bytes: 1089
+    line: 42
+    character: 8
+  end_position:
+    bytes: 1090
+    line: 42
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1090
+    line: 43
+    character: 1
+  end_position:
+    bytes: 1094
+    line: 43
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t\t"
+- start_position:
+    bytes: 1094
+    line: 43
+    character: 5
+  end_position:
+    bytes: 1099
+    line: 43
+    character: 10
+  token_type:
+    type: Symbol
+    symbol: break
+- start_position:
+    bytes: 1099
+    line: 43
+    character: 10
+  end_position:
+    bytes: 1100
+    line: 43
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1100
+    line: 44
+    character: 1
+  end_position:
+    bytes: 1103
+    line: 44
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\t\t\t"
+- start_position:
+    bytes: 1103
+    line: 44
+    character: 4
+  end_position:
+    bytes: 1106
+    line: 44
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 1106
+    line: 44
+    character: 7
+  end_position:
+    bytes: 1107
+    line: 44
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1107
+    line: 45
+    character: 1
+  end_position:
+    bytes: 1109
+    line: 45
+    character: 3
+  token_type:
+    type: Whitespace
+    characters: "\t\t"
+- start_position:
+    bytes: 1109
+    line: 45
+    character: 3
+  end_position:
+    bytes: 1112
+    line: 45
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 1112
+    line: 45
+    character: 6
+  end_position:
+    bytes: 1113
+    line: 45
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1113
+    line: 46
+    character: 1
+  end_position:
+    bytes: 1114
+    line: 46
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 1114
+    line: 46
+    character: 2
+  end_position:
+    bytes: 1117
+    line: 46
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 1117
+    line: 46
+    character: 5
+  end_position:
+    bytes: 1118
+    line: 46
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1118
+    line: 47
+    character: 1
+  end_position:
+    bytes: 1119
+    line: 47
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1119
+    line: 48
+    character: 1
+  end_position:
+    bytes: 1120
+    line: 48
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 1120
+    line: 48
+    character: 2
+  end_position:
+    bytes: 1125
+    line: 48
+    character: 7
+  token_type:
+    type: Identifier
+    identifier: debug
+- start_position:
+    bytes: 1125
+    line: 48
+    character: 7
+  end_position:
+    bytes: 1126
+    line: 48
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 1126
+    line: 48
+    character: 8
+  end_position:
+    bytes: 1138
+    line: 48
+    character: 20
+  token_type:
+    type: StringLiteral
+    literal: LOS RESULT
+    quote_type: Double
+- start_position:
+    bytes: 1138
+    line: 48
+    character: 20
+  end_position:
+    bytes: 1139
+    line: 48
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 1139
+    line: 48
+    character: 21
+  end_position:
+    bytes: 1140
+    line: 48
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1140
+    line: 48
+    character: 22
+  end_position:
+    bytes: 1143
+    line: 48
+    character: 25
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 1143
+    line: 48
+    character: 25
+  end_position:
+    bytes: 1144
+    line: 48
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1144
+    line: 48
+    character: 26
+  end_position:
+    bytes: 1147
+    line: 48
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: and
+- start_position:
+    bytes: 1147
+    line: 48
+    character: 29
+  end_position:
+    bytes: 1148
+    line: 48
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1148
+    line: 48
+    character: 30
+  end_position:
+    bytes: 1151
+    line: 48
+    character: 33
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 1151
+    line: 48
+    character: 33
+  end_position:
+    bytes: 1152
+    line: 48
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 1152
+    line: 48
+    character: 34
+  end_position:
+    bytes: 1163
+    line: 48
+    character: 45
+  token_type:
+    type: Identifier
+    identifier: GetFullName
+- start_position:
+    bytes: 1163
+    line: 48
+    character: 45
+  end_position:
+    bytes: 1164
+    line: 48
+    character: 46
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 1164
+    line: 48
+    character: 46
+  end_position:
+    bytes: 1165
+    line: 48
+    character: 47
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 1165
+    line: 48
+    character: 47
+  end_position:
+    bytes: 1166
+    line: 48
+    character: 48
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 1166
+    line: 48
+    character: 48
+  end_position:
+    bytes: 1167
+    line: 48
+    character: 48
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1167
+    line: 49
+    character: 1
+  end_position:
+    bytes: 1168
+    line: 49
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1168
+    line: 50
+    character: 1
+  end_position:
+    bytes: 1169
+    line: 50
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 1169
+    line: 50
+    character: 2
+  end_position:
+    bytes: 1175
+    line: 50
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 1175
+    line: 50
+    character: 8
+  end_position:
+    bytes: 1176
+    line: 50
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1176
+    line: 50
+    character: 9
+  end_position:
+    bytes: 1179
+    line: 50
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 1179
+    line: 50
+    character: 12
+  end_position:
+    bytes: 1180
+    line: 50
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1180
+    line: 50
+    character: 13
+  end_position:
+    bytes: 1183
+    line: 50
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: and
+- start_position:
+    bytes: 1183
+    line: 50
+    character: 16
+  end_position:
+    bytes: 1184
+    line: 50
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1184
+    line: 50
+    character: 17
+  end_position:
+    bytes: 1187
+    line: 50
+    character: 20
+  token_type:
+    type: Identifier
+    identifier: hit
+- start_position:
+    bytes: 1187
+    line: 50
+    character: 20
+  end_position:
+    bytes: 1188
+    line: 50
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 1188
+    line: 50
+    character: 21
+  end_position:
+    bytes: 1202
+    line: 50
+    character: 35
+  token_type:
+    type: Identifier
+    identifier: IsDescendantOf
+- start_position:
+    bytes: 1202
+    line: 50
+    character: 35
+  end_position:
+    bytes: 1203
+    line: 50
+    character: 36
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 1203
+    line: 50
+    character: 36
+  end_position:
+    bytes: 1212
+    line: 50
+    character: 45
+  token_type:
+    type: Identifier
+    identifier: character
+- start_position:
+    bytes: 1212
+    line: 50
+    character: 45
+  end_position:
+    bytes: 1213
+    line: 50
+    character: 46
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 1213
+    line: 50
+    character: 46
+  end_position:
+    bytes: 1214
+    line: 50
+    character: 47
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 1214
+    line: 50
+    character: 47
+  end_position:
+    bytes: 1215
+    line: 50
+    character: 48
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 1215
+    line: 50
+    character: 48
+  end_position:
+    bytes: 1220
+    line: 50
+    character: 53
+  token_type:
+    type: Identifier
+    identifier: point
+- start_position:
+    bytes: 1220
+    line: 50
+    character: 53
+  end_position:
+    bytes: 1221
+    line: 50
+    character: 53
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1221
+    line: 51
+    character: 1
+  end_position:
+    bytes: 1224
+    line: 51
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 1224
+    line: 51
+    character: 4
+  end_position:
+    bytes: 1225
+    line: 51
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 1225
+    line: 52
+    character: 1
+  end_position:
+    bytes: 1225
+    line: 52
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..57bbae685c1370920bc1aa5df4202995fa523fda
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types/ast.snap
@@ -0,0 +1,3823 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/roblox_cases/pass/types
+---
+stmts:
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 0
+                line: 1
+                character: 1
+              end_position:
+                bytes: 9
+                line: 1
+                character: 10
+              token_type:
+                type: SingleLineComment
+                comment: "!strict"
+            - start_position:
+                bytes: 9
+                line: 1
+                character: 10
+              end_position:
+                bytes: 10
+                line: 1
+                character: 10
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          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: 20
+                    line: 2
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: _fn3
+                trailing_trivia:
+                  - start_position:
+                      bytes: 20
+                      line: 2
+                      character: 11
+                    end_position:
+                      bytes: 21
+                      line: 2
+                      character: 11
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+        equal_token: ~
+        expr_list:
+          pairs: []
+    - ~
+  - - TypeDeclaration:
+        type_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 21
+              line: 3
+              character: 1
+            end_position:
+              bytes: 25
+              line: 3
+              character: 5
+            token_type:
+              type: Identifier
+              identifier: type
+          trailing_trivia:
+            - start_position:
+                bytes: 25
+                line: 3
+                character: 5
+              end_position:
+                bytes: 26
+                line: 3
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        base:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 26
+              line: 3
+              character: 6
+            end_position:
+              bytes: 32
+              line: 3
+              character: 12
+            token_type:
+              type: Identifier
+              identifier: Object
+          trailing_trivia:
+            - start_position:
+                bytes: 32
+                line: 3
+                character: 12
+              end_position:
+                bytes: 33
+                line: 3
+                character: 13
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 33
+              line: 3
+              character: 13
+            end_position:
+              bytes: 34
+              line: 3
+              character: 14
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 34
+                line: 3
+                character: 14
+              end_position:
+                bytes: 35
+                line: 3
+                character: 15
+              token_type:
+                type: Whitespace
+                characters: " "
+        declare_as:
+          Table:
+            braces:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 35
+                      line: 3
+                      character: 15
+                    end_position:
+                      bytes: 36
+                      line: 3
+                      character: 16
+                    token_type:
+                      type: Symbol
+                      symbol: "{"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 36
+                        line: 3
+                        character: 16
+                      end_position:
+                        bytes: 37
+                        line: 3
+                        character: 17
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 58
+                      line: 3
+                      character: 38
+                    end_position:
+                      bytes: 59
+                      line: 3
+                      character: 39
+                    token_type:
+                      type: Symbol
+                      symbol: "}"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 59
+                        line: 3
+                        character: 39
+                      end_position:
+                        bytes: 60
+                        line: 3
+                        character: 39
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+            fields:
+              pairs:
+                - Punctuated:
+                    - key:
+                        Name:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 37
+                              line: 3
+                              character: 17
+                            end_position:
+                              bytes: 38
+                              line: 3
+                              character: 18
+                            token_type:
+                              type: Identifier
+                              identifier: x
+                          trailing_trivia: []
+                      colon:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 38
+                            line: 3
+                            character: 18
+                          end_position:
+                            bytes: 39
+                            line: 3
+                            character: 19
+                          token_type:
+                            type: Symbol
+                            symbol: ":"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 39
+                              line: 3
+                              character: 19
+                            end_position:
+                              bytes: 40
+                              line: 3
+                              character: 20
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      value:
+                        Basic:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 40
+                              line: 3
+                              character: 20
+                            end_position:
+                              bytes: 46
+                              line: 3
+                              character: 26
+                            token_type:
+                              type: Identifier
+                              identifier: number
+                          trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 46
+                          line: 3
+                          character: 26
+                        end_position:
+                          bytes: 47
+                          line: 3
+                          character: 27
+                        token_type:
+                          type: Symbol
+                          symbol: ","
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 47
+                            line: 3
+                            character: 27
+                          end_position:
+                            bytes: 48
+                            line: 3
+                            character: 28
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                - End:
+                    key:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 48
+                            line: 3
+                            character: 28
+                          end_position:
+                            bytes: 49
+                            line: 3
+                            character: 29
+                          token_type:
+                            type: Identifier
+                            identifier: y
+                        trailing_trivia: []
+                    colon:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 49
+                          line: 3
+                          character: 29
+                        end_position:
+                          bytes: 50
+                          line: 3
+                          character: 30
+                        token_type:
+                          type: Symbol
+                          symbol: ":"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 50
+                            line: 3
+                            character: 30
+                          end_position:
+                            bytes: 51
+                            line: 3
+                            character: 31
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                    value:
+                      Basic:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 51
+                            line: 3
+                            character: 31
+                          end_position:
+                            bytes: 57
+                            line: 3
+                            character: 37
+                          token_type:
+                            type: Identifier
+                            identifier: number
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 57
+                              line: 3
+                              character: 37
+                            end_position:
+                              bytes: 58
+                              line: 3
+                              character: 38
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+    - ~
+  - - TypeDeclaration:
+        type_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 60
+              line: 4
+              character: 1
+            end_position:
+              bytes: 64
+              line: 4
+              character: 5
+            token_type:
+              type: Identifier
+              identifier: type
+          trailing_trivia:
+            - start_position:
+                bytes: 64
+                line: 4
+                character: 5
+              end_position:
+                bytes: 65
+                line: 4
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        base:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 65
+              line: 4
+              character: 6
+            end_position:
+              bytes: 71
+              line: 4
+              character: 12
+            token_type:
+              type: Identifier
+              identifier: Typeof
+          trailing_trivia:
+            - start_position:
+                bytes: 71
+                line: 4
+                character: 12
+              end_position:
+                bytes: 72
+                line: 4
+                character: 13
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 72
+              line: 4
+              character: 13
+            end_position:
+              bytes: 73
+              line: 4
+              character: 14
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 73
+                line: 4
+                character: 14
+              end_position:
+                bytes: 74
+                line: 4
+                character: 15
+              token_type:
+                type: Whitespace
+                characters: " "
+        declare_as:
+          Typeof:
+            typeof_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 74
+                  line: 4
+                  character: 15
+                end_position:
+                  bytes: 80
+                  line: 4
+                  character: 21
+                token_type:
+                  type: Identifier
+                  identifier: typeof
+              trailing_trivia: []
+            parentheses:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 80
+                      line: 4
+                      character: 21
+                    end_position:
+                      bytes: 81
+                      line: 4
+                      character: 22
+                    token_type:
+                      type: Symbol
+                      symbol: (
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 95
+                      line: 4
+                      character: 36
+                    end_position:
+                      bytes: 96
+                      line: 4
+                      character: 37
+                    token_type:
+                      type: Symbol
+                      symbol: )
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 96
+                        line: 4
+                        character: 37
+                      end_position:
+                        bytes: 97
+                        line: 4
+                        character: 37
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+            inner:
+              BinaryOperator:
+                lhs:
+                  BinaryOperator:
+                    lhs:
+                      Number:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 81
+                            line: 4
+                            character: 22
+                          end_position:
+                            bytes: 82
+                            line: 4
+                            character: 23
+                          token_type:
+                            type: Number
+                            text: "2"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 82
+                              line: 4
+                              character: 23
+                            end_position:
+                              bytes: 83
+                              line: 4
+                              character: 24
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                    binop:
+                      Plus:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 83
+                            line: 4
+                            character: 24
+                          end_position:
+                            bytes: 84
+                            line: 4
+                            character: 25
+                          token_type:
+                            type: Symbol
+                            symbol: +
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 84
+                              line: 4
+                              character: 25
+                            end_position:
+                              bytes: 85
+                              line: 4
+                              character: 26
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                    rhs:
+                      Number:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 85
+                            line: 4
+                            character: 26
+                          end_position:
+                            bytes: 86
+                            line: 4
+                            character: 27
+                          token_type:
+                            type: Number
+                            text: "2"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 86
+                              line: 4
+                              character: 27
+                            end_position:
+                              bytes: 87
+                              line: 4
+                              character: 28
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                binop:
+                  Plus:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 87
+                        line: 4
+                        character: 28
+                      end_position:
+                        bytes: 88
+                        line: 4
+                        character: 29
+                      token_type:
+                        type: Symbol
+                        symbol: +
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 88
+                          line: 4
+                          character: 29
+                        end_position:
+                          bytes: 89
+                          line: 4
+                          character: 30
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                rhs:
+                  FunctionCall:
+                    prefix:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 89
+                            line: 4
+                            character: 30
+                          end_position:
+                            bytes: 93
+                            line: 4
+                            character: 34
+                          token_type:
+                            type: Identifier
+                            identifier: _fn3
+                        trailing_trivia: []
+                    suffixes:
+                      - Call:
+                          AnonymousCall:
+                            Parentheses:
+                              parentheses:
+                                tokens:
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 93
+                                        line: 4
+                                        character: 34
+                                      end_position:
+                                        bytes: 94
+                                        line: 4
+                                        character: 35
+                                      token_type:
+                                        type: Symbol
+                                        symbol: (
+                                    trailing_trivia: []
+                                  - leading_trivia: []
+                                    token:
+                                      start_position:
+                                        bytes: 94
+                                        line: 4
+                                        character: 35
+                                      end_position:
+                                        bytes: 95
+                                        line: 4
+                                        character: 36
+                                      token_type:
+                                        type: Symbol
+                                        symbol: )
+                                    trailing_trivia: []
+                              arguments:
+                                pairs: []
+    - ~
+  - - TypeDeclaration:
+        type_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 97
+              line: 5
+              character: 1
+            end_position:
+              bytes: 101
+              line: 5
+              character: 5
+            token_type:
+              type: Identifier
+              identifier: type
+          trailing_trivia:
+            - start_position:
+                bytes: 101
+                line: 5
+                character: 5
+              end_position:
+                bytes: 102
+                line: 5
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        base:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 102
+              line: 5
+              character: 6
+            end_position:
+              bytes: 109
+              line: 5
+              character: 13
+            token_type:
+              type: Identifier
+              identifier: Element
+          trailing_trivia:
+            - start_position:
+                bytes: 109
+                line: 5
+                character: 13
+              end_position:
+                bytes: 110
+                line: 5
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 110
+              line: 5
+              character: 14
+            end_position:
+              bytes: 111
+              line: 5
+              character: 15
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 111
+                line: 5
+                character: 15
+              end_position:
+                bytes: 112
+                line: 5
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        declare_as:
+          Table:
+            braces:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 112
+                      line: 5
+                      character: 16
+                    end_position:
+                      bytes: 113
+                      line: 5
+                      character: 17
+                    token_type:
+                      type: Symbol
+                      symbol: "{"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 113
+                        line: 5
+                        character: 17
+                      end_position:
+                        bytes: 114
+                        line: 5
+                        character: 18
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 131
+                      line: 5
+                      character: 35
+                    end_position:
+                      bytes: 132
+                      line: 5
+                      character: 36
+                    token_type:
+                      type: Symbol
+                      symbol: "}"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 132
+                        line: 5
+                        character: 36
+                      end_position:
+                        bytes: 133
+                        line: 5
+                        character: 36
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+            fields:
+              pairs:
+                - End:
+                    key:
+                      IndexSignature:
+                        brackets:
+                          tokens:
+                            - leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 114
+                                  line: 5
+                                  character: 18
+                                end_position:
+                                  bytes: 115
+                                  line: 5
+                                  character: 19
+                                token_type:
+                                  type: Symbol
+                                  symbol: "["
+                              trailing_trivia: []
+                            - leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 121
+                                  line: 5
+                                  character: 25
+                                end_position:
+                                  bytes: 122
+                                  line: 5
+                                  character: 26
+                                token_type:
+                                  type: Symbol
+                                  symbol: "]"
+                              trailing_trivia: []
+                        inner:
+                          Basic:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 115
+                                line: 5
+                                character: 19
+                              end_position:
+                                bytes: 121
+                                line: 5
+                                character: 25
+                              token_type:
+                                type: Identifier
+                                identifier: string
+                            trailing_trivia: []
+                    colon:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 122
+                          line: 5
+                          character: 26
+                        end_position:
+                          bytes: 123
+                          line: 5
+                          character: 27
+                        token_type:
+                          type: Symbol
+                          symbol: ":"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 123
+                            line: 5
+                            character: 27
+                          end_position:
+                            bytes: 124
+                            line: 5
+                            character: 28
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                    value:
+                      Basic:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 124
+                            line: 5
+                            character: 28
+                          end_position:
+                            bytes: 130
+                            line: 5
+                            character: 34
+                          token_type:
+                            type: Identifier
+                            identifier: number
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 130
+                              line: 5
+                              character: 34
+                            end_position:
+                              bytes: 131
+                              line: 5
+                              character: 35
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+    - ~
+  - - TypeDeclaration:
+        type_token:
+          leading_trivia:
+            - start_position:
+                bytes: 133
+                line: 6
+                character: 1
+              end_position:
+                bytes: 134
+                line: 6
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 134
+              line: 7
+              character: 1
+            end_position:
+              bytes: 138
+              line: 7
+              character: 5
+            token_type:
+              type: Identifier
+              identifier: type
+          trailing_trivia:
+            - start_position:
+                bytes: 138
+                line: 7
+                character: 5
+              end_position:
+                bytes: 139
+                line: 7
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        base:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 139
+              line: 7
+              character: 6
+            end_position:
+              bytes: 148
+              line: 7
+              character: 15
+            token_type:
+              type: Identifier
+              identifier: Callback1
+          trailing_trivia:
+            - start_position:
+                bytes: 148
+                line: 7
+                character: 15
+              end_position:
+                bytes: 149
+                line: 7
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 149
+              line: 7
+              character: 16
+            end_position:
+              bytes: 150
+              line: 7
+              character: 17
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 150
+                line: 7
+                character: 17
+              end_position:
+                bytes: 151
+                line: 7
+                character: 18
+              token_type:
+                type: Whitespace
+                characters: " "
+        declare_as:
+          Callback:
+            parentheses:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 151
+                      line: 7
+                      character: 18
+                    end_position:
+                      bytes: 152
+                      line: 7
+                      character: 19
+                    token_type:
+                      type: Symbol
+                      symbol: (
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 158
+                      line: 7
+                      character: 25
+                    end_position:
+                      bytes: 159
+                      line: 7
+                      character: 26
+                    token_type:
+                      type: Symbol
+                      symbol: )
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 159
+                        line: 7
+                        character: 26
+                      end_position:
+                        bytes: 160
+                        line: 7
+                        character: 27
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            arguments:
+              pairs:
+                - End:
+                    name: ~
+                    type_info:
+                      Basic:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 152
+                            line: 7
+                            character: 19
+                          end_position:
+                            bytes: 158
+                            line: 7
+                            character: 25
+                          token_type:
+                            type: Identifier
+                            identifier: string
+                        trailing_trivia: []
+            arrow:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 160
+                  line: 7
+                  character: 27
+                end_position:
+                  bytes: 162
+                  line: 7
+                  character: 29
+                token_type:
+                  type: Symbol
+                  symbol: "->"
+              trailing_trivia:
+                - start_position:
+                    bytes: 162
+                    line: 7
+                    character: 29
+                  end_position:
+                    bytes: 163
+                    line: 7
+                    character: 30
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            return_type:
+              Basic:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 163
+                    line: 7
+                    character: 30
+                  end_position:
+                    bytes: 169
+                    line: 7
+                    character: 36
+                  token_type:
+                    type: Identifier
+                    identifier: number
+                trailing_trivia:
+                  - start_position:
+                      bytes: 169
+                      line: 7
+                      character: 36
+                    end_position:
+                      bytes: 170
+                      line: 7
+                      character: 36
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+    - ~
+  - - TypeDeclaration:
+        type_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 170
+              line: 8
+              character: 1
+            end_position:
+              bytes: 174
+              line: 8
+              character: 5
+            token_type:
+              type: Identifier
+              identifier: type
+          trailing_trivia:
+            - start_position:
+                bytes: 174
+                line: 8
+                character: 5
+              end_position:
+                bytes: 175
+                line: 8
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        base:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 175
+              line: 8
+              character: 6
+            end_position:
+              bytes: 184
+              line: 8
+              character: 15
+            token_type:
+              type: Identifier
+              identifier: Callback2
+          trailing_trivia:
+            - start_position:
+                bytes: 184
+                line: 8
+                character: 15
+              end_position:
+                bytes: 185
+                line: 8
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 185
+              line: 8
+              character: 16
+            end_position:
+              bytes: 186
+              line: 8
+              character: 17
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 186
+                line: 8
+                character: 17
+              end_position:
+                bytes: 187
+                line: 8
+                character: 18
+              token_type:
+                type: Whitespace
+                characters: " "
+        declare_as:
+          Callback:
+            parentheses:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 187
+                      line: 8
+                      character: 18
+                    end_position:
+                      bytes: 188
+                      line: 8
+                      character: 19
+                    token_type:
+                      type: Symbol
+                      symbol: (
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 202
+                      line: 8
+                      character: 33
+                    end_position:
+                      bytes: 203
+                      line: 8
+                      character: 34
+                    token_type:
+                      type: Symbol
+                      symbol: )
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 203
+                        line: 8
+                        character: 34
+                      end_position:
+                        bytes: 204
+                        line: 8
+                        character: 35
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            arguments:
+              pairs:
+                - Punctuated:
+                    - name: ~
+                      type_info:
+                        Basic:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 188
+                              line: 8
+                              character: 19
+                            end_position:
+                              bytes: 194
+                              line: 8
+                              character: 25
+                            token_type:
+                              type: Identifier
+                              identifier: string
+                          trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 194
+                          line: 8
+                          character: 25
+                        end_position:
+                          bytes: 195
+                          line: 8
+                          character: 26
+                        token_type:
+                          type: Symbol
+                          symbol: ","
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 195
+                            line: 8
+                            character: 26
+                          end_position:
+                            bytes: 196
+                            line: 8
+                            character: 27
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                - End:
+                    name: ~
+                    type_info:
+                      Basic:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 196
+                            line: 8
+                            character: 27
+                          end_position:
+                            bytes: 202
+                            line: 8
+                            character: 33
+                          token_type:
+                            type: Identifier
+                            identifier: string
+                        trailing_trivia: []
+            arrow:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 204
+                  line: 8
+                  character: 35
+                end_position:
+                  bytes: 206
+                  line: 8
+                  character: 37
+                token_type:
+                  type: Symbol
+                  symbol: "->"
+              trailing_trivia:
+                - start_position:
+                    bytes: 206
+                    line: 8
+                    character: 37
+                  end_position:
+                    bytes: 207
+                    line: 8
+                    character: 38
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            return_type:
+              Basic:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 207
+                    line: 8
+                    character: 38
+                  end_position:
+                    bytes: 213
+                    line: 8
+                    character: 44
+                  token_type:
+                    type: Identifier
+                    identifier: number
+                trailing_trivia:
+                  - start_position:
+                      bytes: 213
+                      line: 8
+                      character: 44
+                    end_position:
+                      bytes: 214
+                      line: 8
+                      character: 44
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+    - ~
+  - - TypeDeclaration:
+        type_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 214
+              line: 9
+              character: 1
+            end_position:
+              bytes: 218
+              line: 9
+              character: 5
+            token_type:
+              type: Identifier
+              identifier: type
+          trailing_trivia:
+            - start_position:
+                bytes: 218
+                line: 9
+                character: 5
+              end_position:
+                bytes: 219
+                line: 9
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        base:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 219
+              line: 9
+              character: 6
+            end_position:
+              bytes: 228
+              line: 9
+              character: 15
+            token_type:
+              type: Identifier
+              identifier: Callback3
+          trailing_trivia:
+            - start_position:
+                bytes: 228
+                line: 9
+                character: 15
+              end_position:
+                bytes: 229
+                line: 9
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 229
+              line: 9
+              character: 16
+            end_position:
+              bytes: 230
+              line: 9
+              character: 17
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 230
+                line: 9
+                character: 17
+              end_position:
+                bytes: 231
+                line: 9
+                character: 18
+              token_type:
+                type: Whitespace
+                characters: " "
+        declare_as:
+          Callback:
+            parentheses:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 231
+                      line: 9
+                      character: 18
+                    end_position:
+                      bytes: 232
+                      line: 9
+                      character: 19
+                    token_type:
+                      type: Symbol
+                      symbol: (
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 246
+                      line: 9
+                      character: 33
+                    end_position:
+                      bytes: 247
+                      line: 9
+                      character: 34
+                    token_type:
+                      type: Symbol
+                      symbol: )
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 247
+                        line: 9
+                        character: 34
+                      end_position:
+                        bytes: 248
+                        line: 9
+                        character: 35
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            arguments:
+              pairs:
+                - Punctuated:
+                    - name: ~
+                      type_info:
+                        Basic:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 232
+                              line: 9
+                              character: 19
+                            end_position:
+                              bytes: 238
+                              line: 9
+                              character: 25
+                            token_type:
+                              type: Identifier
+                              identifier: string
+                          trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 238
+                          line: 9
+                          character: 25
+                        end_position:
+                          bytes: 239
+                          line: 9
+                          character: 26
+                        token_type:
+                          type: Symbol
+                          symbol: ","
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 239
+                            line: 9
+                            character: 26
+                          end_position:
+                            bytes: 240
+                            line: 9
+                            character: 27
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                - End:
+                    name: ~
+                    type_info:
+                      Basic:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 240
+                            line: 9
+                            character: 27
+                          end_position:
+                            bytes: 246
+                            line: 9
+                            character: 33
+                          token_type:
+                            type: Identifier
+                            identifier: string
+                        trailing_trivia: []
+            arrow:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 248
+                  line: 9
+                  character: 35
+                end_position:
+                  bytes: 250
+                  line: 9
+                  character: 37
+                token_type:
+                  type: Symbol
+                  symbol: "->"
+              trailing_trivia:
+                - start_position:
+                    bytes: 250
+                    line: 9
+                    character: 37
+                  end_position:
+                    bytes: 251
+                    line: 9
+                    character: 38
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            return_type:
+              Tuple:
+                parentheses:
+                  tokens:
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 251
+                          line: 9
+                          character: 38
+                        end_position:
+                          bytes: 252
+                          line: 9
+                          character: 39
+                        token_type:
+                          type: Symbol
+                          symbol: (
+                      trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 263
+                          line: 9
+                          character: 50
+                        end_position:
+                          bytes: 264
+                          line: 9
+                          character: 51
+                        token_type:
+                          type: Symbol
+                          symbol: )
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 264
+                            line: 9
+                            character: 51
+                          end_position:
+                            bytes: 265
+                            line: 9
+                            character: 51
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+                types:
+                  pairs:
+                    - Punctuated:
+                        - Basic:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 252
+                                line: 9
+                                character: 39
+                              end_position:
+                                bytes: 258
+                                line: 9
+                                character: 45
+                              token_type:
+                                type: Identifier
+                                identifier: string
+                            trailing_trivia: []
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 258
+                              line: 9
+                              character: 45
+                            end_position:
+                              bytes: 259
+                              line: 9
+                              character: 46
+                            token_type:
+                              type: Symbol
+                              symbol: ","
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 259
+                                line: 9
+                                character: 46
+                              end_position:
+                                bytes: 260
+                                line: 9
+                                character: 47
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                    - End:
+                        Basic:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 260
+                              line: 9
+                              character: 47
+                            end_position:
+                              bytes: 263
+                              line: 9
+                              character: 50
+                            token_type:
+                              type: Symbol
+                              symbol: nil
+                          trailing_trivia: []
+    - ~
+  - - TypeDeclaration:
+        type_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 265
+              line: 10
+              character: 1
+            end_position:
+              bytes: 269
+              line: 10
+              character: 5
+            token_type:
+              type: Identifier
+              identifier: type
+          trailing_trivia:
+            - start_position:
+                bytes: 269
+                line: 10
+                character: 5
+              end_position:
+                bytes: 270
+                line: 10
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        base:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 270
+              line: 10
+              character: 6
+            end_position:
+              bytes: 279
+              line: 10
+              character: 15
+            token_type:
+              type: Identifier
+              identifier: Callback4
+          trailing_trivia:
+            - start_position:
+                bytes: 279
+                line: 10
+                character: 15
+              end_position:
+                bytes: 280
+                line: 10
+                character: 16
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 280
+              line: 10
+              character: 16
+            end_position:
+              bytes: 281
+              line: 10
+              character: 17
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 281
+                line: 10
+                character: 17
+              end_position:
+                bytes: 282
+                line: 10
+                character: 18
+              token_type:
+                type: Whitespace
+                characters: " "
+        declare_as:
+          Callback:
+            parentheses:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 282
+                      line: 10
+                      character: 18
+                    end_position:
+                      bytes: 283
+                      line: 10
+                      character: 19
+                    token_type:
+                      type: Symbol
+                      symbol: (
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 289
+                      line: 10
+                      character: 25
+                    end_position:
+                      bytes: 290
+                      line: 10
+                      character: 26
+                    token_type:
+                      type: Symbol
+                      symbol: )
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 290
+                        line: 10
+                        character: 26
+                      end_position:
+                        bytes: 291
+                        line: 10
+                        character: 27
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            arguments:
+              pairs:
+                - End:
+                    name: ~
+                    type_info:
+                      Basic:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 283
+                            line: 10
+                            character: 19
+                          end_position:
+                            bytes: 289
+                            line: 10
+                            character: 25
+                          token_type:
+                            type: Identifier
+                            identifier: string
+                        trailing_trivia: []
+            arrow:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 291
+                  line: 10
+                  character: 27
+                end_position:
+                  bytes: 293
+                  line: 10
+                  character: 29
+                token_type:
+                  type: Symbol
+                  symbol: "->"
+              trailing_trivia:
+                - start_position:
+                    bytes: 293
+                    line: 10
+                    character: 29
+                  end_position:
+                    bytes: 294
+                    line: 10
+                    character: 30
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            return_type:
+              Callback:
+                parentheses:
+                  tokens:
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 294
+                          line: 10
+                          character: 30
+                        end_position:
+                          bytes: 295
+                          line: 10
+                          character: 31
+                        token_type:
+                          type: Symbol
+                          symbol: (
+                      trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 301
+                          line: 10
+                          character: 37
+                        end_position:
+                          bytes: 302
+                          line: 10
+                          character: 38
+                        token_type:
+                          type: Symbol
+                          symbol: )
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 302
+                            line: 10
+                            character: 38
+                          end_position:
+                            bytes: 303
+                            line: 10
+                            character: 39
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                arguments:
+                  pairs:
+                    - End:
+                        name: ~
+                        type_info:
+                          Basic:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 295
+                                line: 10
+                                character: 31
+                              end_position:
+                                bytes: 301
+                                line: 10
+                                character: 37
+                              token_type:
+                                type: Identifier
+                                identifier: string
+                            trailing_trivia: []
+                arrow:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 303
+                      line: 10
+                      character: 39
+                    end_position:
+                      bytes: 305
+                      line: 10
+                      character: 41
+                    token_type:
+                      type: Symbol
+                      symbol: "->"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 305
+                        line: 10
+                        character: 41
+                      end_position:
+                        bytes: 306
+                        line: 10
+                        character: 42
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+                return_type:
+                  Basic:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 306
+                        line: 10
+                        character: 42
+                      end_position:
+                        bytes: 309
+                        line: 10
+                        character: 45
+                      token_type:
+                        type: Symbol
+                        symbol: nil
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 309
+                          line: 10
+                          character: 45
+                        end_position:
+                          bytes: 310
+                          line: 10
+                          character: 45
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+    - ~
+  - - TypeDeclaration:
+        type_token:
+          leading_trivia:
+            - start_position:
+                bytes: 310
+                line: 11
+                character: 1
+              end_position:
+                bytes: 311
+                line: 11
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 311
+              line: 12
+              character: 1
+            end_position:
+              bytes: 315
+              line: 12
+              character: 5
+            token_type:
+              type: Identifier
+              identifier: type
+          trailing_trivia:
+            - start_position:
+                bytes: 315
+                line: 12
+                character: 5
+              end_position:
+                bytes: 316
+                line: 12
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        base:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 316
+              line: 12
+              character: 6
+            end_position:
+              bytes: 319
+              line: 12
+              character: 9
+            token_type:
+              type: Identifier
+              identifier: Foo
+          trailing_trivia:
+            - start_position:
+                bytes: 319
+                line: 12
+                character: 9
+              end_position:
+                bytes: 320
+                line: 12
+                character: 10
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 320
+              line: 12
+              character: 10
+            end_position:
+              bytes: 321
+              line: 12
+              character: 11
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 321
+                line: 12
+                character: 11
+              end_position:
+                bytes: 322
+                line: 12
+                character: 12
+              token_type:
+                type: Whitespace
+                characters: " "
+        declare_as:
+          Table:
+            braces:
+              tokens:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 322
+                      line: 12
+                      character: 12
+                    end_position:
+                      bytes: 323
+                      line: 12
+                      character: 13
+                    token_type:
+                      type: Symbol
+                      symbol: "{"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 323
+                        line: 12
+                        character: 13
+                      end_position:
+                        bytes: 324
+                        line: 12
+                        character: 13
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 352
+                      line: 15
+                      character: 1
+                    end_position:
+                      bytes: 353
+                      line: 15
+                      character: 2
+                    token_type:
+                      type: Symbol
+                      symbol: "}"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 353
+                        line: 15
+                        character: 2
+                      end_position:
+                        bytes: 354
+                        line: 15
+                        character: 2
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+            fields:
+              pairs:
+                - Punctuated:
+                    - key:
+                        Name:
+                          leading_trivia:
+                            - start_position:
+                                bytes: 324
+                                line: 13
+                                character: 1
+                              end_position:
+                                bytes: 325
+                                line: 13
+                                character: 2
+                              token_type:
+                                type: Whitespace
+                                characters: "\t"
+                          token:
+                            start_position:
+                              bytes: 325
+                              line: 13
+                              character: 2
+                            end_position:
+                              bytes: 328
+                              line: 13
+                              character: 5
+                            token_type:
+                              type: Identifier
+                              identifier: bar
+                          trailing_trivia: []
+                      colon:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 328
+                            line: 13
+                            character: 5
+                          end_position:
+                            bytes: 329
+                            line: 13
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: ":"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 329
+                              line: 13
+                              character: 6
+                            end_position:
+                              bytes: 330
+                              line: 13
+                              character: 7
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      value:
+                        Basic:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 330
+                              line: 13
+                              character: 7
+                            end_position:
+                              bytes: 336
+                              line: 13
+                              character: 13
+                            token_type:
+                              type: Identifier
+                              identifier: number
+                          trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 336
+                          line: 13
+                          character: 13
+                        end_position:
+                          bytes: 337
+                          line: 13
+                          character: 14
+                        token_type:
+                          type: Symbol
+                          symbol: ","
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 337
+                            line: 13
+                            character: 14
+                          end_position:
+                            bytes: 338
+                            line: 13
+                            character: 14
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+                - Punctuated:
+                    - key:
+                        Name:
+                          leading_trivia:
+                            - start_position:
+                                bytes: 338
+                                line: 14
+                                character: 1
+                              end_position:
+                                bytes: 339
+                                line: 14
+                                character: 2
+                              token_type:
+                                type: Whitespace
+                                characters: "\t"
+                          token:
+                            start_position:
+                              bytes: 339
+                              line: 14
+                              character: 2
+                            end_position:
+                              bytes: 342
+                              line: 14
+                              character: 5
+                            token_type:
+                              type: Identifier
+                              identifier: baz
+                          trailing_trivia: []
+                      colon:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 342
+                            line: 14
+                            character: 5
+                          end_position:
+                            bytes: 343
+                            line: 14
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: ":"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 343
+                              line: 14
+                              character: 6
+                            end_position:
+                              bytes: 344
+                              line: 14
+                              character: 7
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      value:
+                        Basic:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 344
+                              line: 14
+                              character: 7
+                            end_position:
+                              bytes: 350
+                              line: 14
+                              character: 13
+                            token_type:
+                              type: Identifier
+                              identifier: number
+                          trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 350
+                          line: 14
+                          character: 13
+                        end_position:
+                          bytes: 351
+                          line: 14
+                          character: 14
+                        token_type:
+                          type: Symbol
+                          symbol: ","
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 351
+                            line: 14
+                            character: 14
+                          end_position:
+                            bytes: 352
+                            line: 14
+                            character: 14
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 354
+                line: 16
+                character: 1
+              end_position:
+                bytes: 355
+                line: 16
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 355
+              line: 17
+              character: 1
+            end_position:
+              bytes: 360
+              line: 17
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 360
+                line: 17
+                character: 6
+              end_position:
+                bytes: 361
+                line: 17
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        type_specifiers:
+          - punctuation:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 365
+                  line: 17
+                  character: 11
+                end_position:
+                  bytes: 366
+                  line: 17
+                  character: 12
+                token_type:
+                  type: Symbol
+                  symbol: ":"
+              trailing_trivia:
+                - start_position:
+                    bytes: 366
+                    line: 17
+                    character: 12
+                  end_position:
+                    bytes: 367
+                    line: 17
+                    character: 13
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            type_info:
+              Basic:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 367
+                    line: 17
+                    character: 13
+                  end_position:
+                    bytes: 373
+                    line: 17
+                    character: 19
+                  token_type:
+                    type: Identifier
+                    identifier: number
+                trailing_trivia:
+                  - start_position:
+                      bytes: 373
+                      line: 17
+                      character: 19
+                    end_position:
+                      bytes: 374
+                      line: 17
+                      character: 20
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 361
+                    line: 17
+                    character: 7
+                  end_position:
+                    bytes: 365
+                    line: 17
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: foo0
+                trailing_trivia: []
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 374
+              line: 17
+              character: 20
+            end_position:
+              bytes: 375
+              line: 17
+              character: 21
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 375
+                line: 17
+                character: 21
+              end_position:
+                bytes: 376
+                line: 17
+                character: 22
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 376
+                      line: 17
+                      character: 22
+                    end_position:
+                      bytes: 377
+                      line: 17
+                      character: 23
+                    token_type:
+                      type: Number
+                      text: "3"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 377
+                        line: 17
+                        character: 23
+                      end_position:
+                        bytes: 378
+                        line: 17
+                        character: 23
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 378
+              line: 18
+              character: 1
+            end_position:
+              bytes: 383
+              line: 18
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 383
+                line: 18
+                character: 6
+              end_position:
+                bytes: 384
+                line: 18
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        type_specifiers:
+          - punctuation:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 389
+                  line: 18
+                  character: 12
+                end_position:
+                  bytes: 390
+                  line: 18
+                  character: 13
+                token_type:
+                  type: Symbol
+                  symbol: ":"
+              trailing_trivia:
+                - start_position:
+                    bytes: 390
+                    line: 18
+                    character: 13
+                  end_position:
+                    bytes: 391
+                    line: 18
+                    character: 14
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            type_info:
+              Optional:
+                base:
+                  Basic:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 391
+                        line: 18
+                        character: 14
+                      end_position:
+                        bytes: 397
+                        line: 18
+                        character: 20
+                      token_type:
+                        type: Identifier
+                        identifier: number
+                    trailing_trivia: []
+                question_mark:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 397
+                      line: 18
+                      character: 20
+                    end_position:
+                      bytes: 398
+                      line: 18
+                      character: 21
+                    token_type:
+                      type: Symbol
+                      symbol: "?"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 398
+                        line: 18
+                        character: 21
+                      end_position:
+                        bytes: 399
+                        line: 18
+                        character: 21
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 384
+                    line: 18
+                    character: 7
+                  end_position:
+                    bytes: 389
+                    line: 18
+                    character: 12
+                  token_type:
+                    type: Identifier
+                    identifier: _foo1
+                trailing_trivia: []
+        equal_token: ~
+        expr_list:
+          pairs: []
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 399
+              line: 19
+              character: 1
+            end_position:
+              bytes: 404
+              line: 19
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 404
+                line: 19
+                character: 6
+              end_position:
+                bytes: 405
+                line: 19
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 405
+                    line: 19
+                    character: 7
+                  end_position:
+                    bytes: 410
+                    line: 19
+                    character: 12
+                  token_type:
+                    type: Identifier
+                    identifier: _bar0
+                trailing_trivia:
+                  - start_position:
+                      bytes: 410
+                      line: 19
+                      character: 12
+                    end_position:
+                      bytes: 411
+                      line: 19
+                      character: 13
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 411
+              line: 19
+              character: 13
+            end_position:
+              bytes: 412
+              line: 19
+              character: 14
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 412
+                line: 19
+                character: 14
+              end_position:
+                bytes: 413
+                line: 19
+                character: 15
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                TypeAssertion:
+                  expression:
+                    Var:
+                      Name:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 413
+                            line: 19
+                            character: 15
+                          end_position:
+                            bytes: 417
+                            line: 19
+                            character: 19
+                          token_type:
+                            type: Identifier
+                            identifier: foo0
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 417
+                              line: 19
+                              character: 19
+                            end_position:
+                              bytes: 418
+                              line: 19
+                              character: 20
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  type_assertion:
+                    assertion_op:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 418
+                          line: 19
+                          character: 20
+                        end_position:
+                          bytes: 420
+                          line: 19
+                          character: 22
+                        token_type:
+                          type: Symbol
+                          symbol: "::"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 420
+                            line: 19
+                            character: 22
+                          end_position:
+                            bytes: 421
+                            line: 19
+                            character: 23
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                    cast_to:
+                      Basic:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 421
+                            line: 19
+                            character: 23
+                          end_position:
+                            bytes: 427
+                            line: 19
+                            character: 29
+                          token_type:
+                            type: Identifier
+                            identifier: number
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 427
+                              line: 19
+                              character: 29
+                            end_position:
+                              bytes: 428
+                              line: 19
+                              character: 29
+                            token_type:
+                              type: Whitespace
+                              characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 428
+              line: 20
+              character: 1
+            end_position:
+              bytes: 433
+              line: 20
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 433
+                line: 20
+                character: 6
+              end_position:
+                bytes: 434
+                line: 20
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        type_specifiers:
+          - punctuation:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 439
+                  line: 20
+                  character: 12
+                end_position:
+                  bytes: 440
+                  line: 20
+                  character: 13
+                token_type:
+                  type: Symbol
+                  symbol: ":"
+              trailing_trivia:
+                - start_position:
+                    bytes: 440
+                    line: 20
+                    character: 13
+                  end_position:
+                    bytes: 441
+                    line: 20
+                    character: 14
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            type_info:
+              Basic:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 441
+                    line: 20
+                    character: 14
+                  end_position:
+                    bytes: 447
+                    line: 20
+                    character: 20
+                  token_type:
+                    type: Identifier
+                    identifier: string
+                trailing_trivia: []
+          - punctuation:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 454
+                  line: 20
+                  character: 27
+                end_position:
+                  bytes: 455
+                  line: 20
+                  character: 28
+                token_type:
+                  type: Symbol
+                  symbol: ":"
+              trailing_trivia:
+                - start_position:
+                    bytes: 455
+                    line: 20
+                    character: 28
+                  end_position:
+                    bytes: 456
+                    line: 20
+                    character: 29
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            type_info:
+              Basic:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 456
+                    line: 20
+                    character: 29
+                  end_position:
+                    bytes: 462
+                    line: 20
+                    character: 35
+                  token_type:
+                    type: Identifier
+                    identifier: string
+                trailing_trivia:
+                  - start_position:
+                      bytes: 462
+                      line: 20
+                      character: 35
+                    end_position:
+                      bytes: 463
+                      line: 20
+                      character: 35
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+        name_list:
+          pairs:
+            - Punctuated:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 434
+                      line: 20
+                      character: 7
+                    end_position:
+                      bytes: 439
+                      line: 20
+                      character: 12
+                    token_type:
+                      type: Identifier
+                      identifier: _foo4
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 447
+                      line: 20
+                      character: 20
+                    end_position:
+                      bytes: 448
+                      line: 20
+                      character: 21
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 448
+                        line: 20
+                        character: 21
+                      end_position:
+                        bytes: 449
+                        line: 20
+                        character: 22
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 449
+                    line: 20
+                    character: 22
+                  end_position:
+                    bytes: 454
+                    line: 20
+                    character: 27
+                  token_type:
+                    type: Identifier
+                    identifier: _bar1
+                trailing_trivia: []
+        equal_token: ~
+        expr_list:
+          pairs: []
+    - ~
+  - - FunctionDeclaration:
+        function_token:
+          leading_trivia:
+            - start_position:
+                bytes: 463
+                line: 21
+                character: 1
+              end_position:
+                bytes: 464
+                line: 21
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 464
+              line: 22
+              character: 1
+            end_position:
+              bytes: 472
+              line: 22
+              character: 9
+            token_type:
+              type: Symbol
+              symbol: function
+          trailing_trivia:
+            - start_position:
+                bytes: 472
+                line: 22
+                character: 9
+              end_position:
+                bytes: 473
+                line: 22
+                character: 10
+              token_type:
+                type: Whitespace
+                characters: " "
+        name:
+          names:
+            pairs:
+              - End:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 473
+                      line: 22
+                      character: 10
+                    end_position:
+                      bytes: 477
+                      line: 22
+                      character: 14
+                    token_type:
+                      type: Identifier
+                      identifier: _fn0
+                  trailing_trivia: []
+          colon_name: ~
+        body:
+          parameters_parentheses:
+            tokens:
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 477
+                    line: 22
+                    character: 14
+                  end_position:
+                    bytes: 478
+                    line: 22
+                    character: 15
+                  token_type:
+                    type: Symbol
+                    symbol: (
+                trailing_trivia: []
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 491
+                    line: 22
+                    character: 28
+                  end_position:
+                    bytes: 492
+                    line: 22
+                    character: 29
+                  token_type:
+                    type: Symbol
+                    symbol: )
+                trailing_trivia: []
+          parameters:
+            pairs:
+              - End:
+                  name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 478
+                        line: 22
+                        character: 15
+                      end_position:
+                        bytes: 483
+                        line: 22
+                        character: 20
+                      token_type:
+                        type: Identifier
+                        identifier: param
+                    trailing_trivia: []
+          type_specifiers:
+            - punctuation:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 483
+                    line: 22
+                    character: 20
+                  end_position:
+                    bytes: 484
+                    line: 22
+                    character: 21
+                  token_type:
+                    type: Symbol
+                    symbol: ":"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 484
+                      line: 22
+                      character: 21
+                    end_position:
+                      bytes: 485
+                      line: 22
+                      character: 22
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              type_info:
+                Basic:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 485
+                      line: 22
+                      character: 22
+                    end_position:
+                      bytes: 491
+                      line: 22
+                      character: 28
+                    token_type:
+                      type: Identifier
+                      identifier: string
+                  trailing_trivia: []
+          return_type:
+            punctuation:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 492
+                  line: 22
+                  character: 29
+                end_position:
+                  bytes: 493
+                  line: 22
+                  character: 30
+                token_type:
+                  type: Symbol
+                  symbol: ":"
+              trailing_trivia:
+                - start_position:
+                    bytes: 493
+                    line: 22
+                    character: 30
+                  end_position:
+                    bytes: 494
+                    line: 22
+                    character: 31
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            type_info:
+              Basic:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 494
+                    line: 22
+                    character: 31
+                  end_position:
+                    bytes: 500
+                    line: 22
+                    character: 37
+                  token_type:
+                    type: Identifier
+                    identifier: string
+                trailing_trivia:
+                  - start_position:
+                      bytes: 500
+                      line: 22
+                      character: 37
+                    end_position:
+                      bytes: 501
+                      line: 22
+                      character: 37
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+          block:
+            stmts: []
+            last_stmt:
+              - Return:
+                  token:
+                    leading_trivia:
+                      - start_position:
+                          bytes: 501
+                          line: 23
+                          character: 1
+                        end_position:
+                          bytes: 502
+                          line: 23
+                          character: 2
+                        token_type:
+                          type: Whitespace
+                          characters: "\t"
+                    token:
+                      start_position:
+                        bytes: 502
+                        line: 23
+                        character: 2
+                      end_position:
+                        bytes: 508
+                        line: 23
+                        character: 8
+                      token_type:
+                        type: Symbol
+                        symbol: return
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 508
+                          line: 23
+                          character: 8
+                        end_position:
+                          bytes: 509
+                          line: 23
+                          character: 9
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+                  returns:
+                    pairs:
+                      - End:
+                          Var:
+                            Name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 509
+                                  line: 23
+                                  character: 9
+                                end_position:
+                                  bytes: 514
+                                  line: 23
+                                  character: 14
+                                token_type:
+                                  type: Identifier
+                                  identifier: param
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 514
+                                    line: 23
+                                    character: 14
+                                  end_position:
+                                    bytes: 515
+                                    line: 23
+                                    character: 14
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\n"
+              - ~
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 515
+                line: 24
+                character: 1
+              end_position:
+                bytes: 518
+                line: 24
+                character: 4
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia:
+              - start_position:
+                  bytes: 518
+                  line: 24
+                  character: 4
+                end_position:
+                  bytes: 519
+                  line: 24
+                  character: 4
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - FunctionDeclaration:
+        function_token:
+          leading_trivia:
+            - start_position:
+                bytes: 519
+                line: 25
+                character: 1
+              end_position:
+                bytes: 520
+                line: 25
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 520
+              line: 26
+              character: 1
+            end_position:
+              bytes: 528
+              line: 26
+              character: 9
+            token_type:
+              type: Symbol
+              symbol: function
+          trailing_trivia:
+            - start_position:
+                bytes: 528
+                line: 26
+                character: 9
+              end_position:
+                bytes: 529
+                line: 26
+                character: 10
+              token_type:
+                type: Whitespace
+                characters: " "
+        name:
+          names:
+            pairs:
+              - End:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 529
+                      line: 26
+                      character: 10
+                    end_position:
+                      bytes: 533
+                      line: 26
+                      character: 14
+                    token_type:
+                      type: Identifier
+                      identifier: _fn2
+                  trailing_trivia: []
+          colon_name: ~
+        body:
+          parameters_parentheses:
+            tokens:
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 533
+                    line: 26
+                    character: 14
+                  end_position:
+                    bytes: 534
+                    line: 26
+                    character: 15
+                  token_type:
+                    type: Symbol
+                    symbol: (
+                trailing_trivia: []
+              - leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 554
+                    line: 26
+                    character: 35
+                  end_position:
+                    bytes: 555
+                    line: 26
+                    character: 36
+                  token_type:
+                    type: Symbol
+                    symbol: )
+                trailing_trivia:
+                  - start_position:
+                      bytes: 555
+                      line: 26
+                      character: 36
+                    end_position:
+                      bytes: 556
+                      line: 26
+                      character: 37
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+          parameters:
+            pairs:
+              - Punctuated:
+                  - name:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 534
+                          line: 26
+                          character: 15
+                        end_position:
+                          bytes: 535
+                          line: 26
+                          character: 16
+                        token_type:
+                          type: Identifier
+                          identifier: a
+                      trailing_trivia: []
+                  - leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 543
+                        line: 26
+                        character: 24
+                      end_position:
+                        bytes: 544
+                        line: 26
+                        character: 25
+                      token_type:
+                        type: Symbol
+                        symbol: ","
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 544
+                          line: 26
+                          character: 25
+                        end_position:
+                          bytes: 545
+                          line: 26
+                          character: 26
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+              - End:
+                  name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 545
+                        line: 26
+                        character: 26
+                      end_position:
+                        bytes: 546
+                        line: 26
+                        character: 27
+                      token_type:
+                        type: Identifier
+                        identifier: b
+                    trailing_trivia: []
+          type_specifiers:
+            - punctuation:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 535
+                    line: 26
+                    character: 16
+                  end_position:
+                    bytes: 536
+                    line: 26
+                    character: 17
+                  token_type:
+                    type: Symbol
+                    symbol: ":"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 536
+                      line: 26
+                      character: 17
+                    end_position:
+                      bytes: 537
+                      line: 26
+                      character: 18
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              type_info:
+                Basic:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 537
+                      line: 26
+                      character: 18
+                    end_position:
+                      bytes: 543
+                      line: 26
+                      character: 24
+                    token_type:
+                      type: Identifier
+                      identifier: string
+                  trailing_trivia: []
+            - punctuation:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 546
+                    line: 26
+                    character: 27
+                  end_position:
+                    bytes: 547
+                    line: 26
+                    character: 28
+                  token_type:
+                    type: Symbol
+                    symbol: ":"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 547
+                      line: 26
+                      character: 28
+                    end_position:
+                      bytes: 548
+                      line: 26
+                      character: 29
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              type_info:
+                Basic:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 548
+                      line: 26
+                      character: 29
+                    end_position:
+                      bytes: 554
+                      line: 26
+                      character: 35
+                    token_type:
+                      type: Identifier
+                      identifier: string
+                  trailing_trivia: []
+          block:
+            stmts: []
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 556
+                line: 26
+                character: 37
+              end_position:
+                bytes: 559
+                line: 26
+                character: 40
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia:
+              - start_position:
+                  bytes: 559
+                  line: 26
+                  character: 40
+                end_position:
+                  bytes: 560
+                  line: 26
+                  character: 40
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
+  - - LocalAssignment:
+        local_token:
+          leading_trivia:
+            - start_position:
+                bytes: 560
+                line: 27
+                character: 1
+              end_position:
+                bytes: 561
+                line: 27
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 561
+              line: 28
+              character: 1
+            end_position:
+              bytes: 566
+              line: 28
+              character: 6
+            token_type:
+              type: Symbol
+              symbol: local
+          trailing_trivia:
+            - start_position:
+                bytes: 566
+                line: 28
+                character: 6
+              end_position:
+                bytes: 567
+                line: 28
+                character: 7
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 567
+                    line: 28
+                    character: 7
+                  end_position:
+                    bytes: 571
+                    line: 28
+                    character: 11
+                  token_type:
+                    type: Identifier
+                    identifier: _fn3
+                trailing_trivia:
+                  - start_position:
+                      bytes: 571
+                      line: 28
+                      character: 11
+                    end_position:
+                      bytes: 572
+                      line: 28
+                      character: 12
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 572
+              line: 28
+              character: 12
+            end_position:
+              bytes: 573
+              line: 28
+              character: 13
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 573
+                line: 28
+                character: 13
+              end_position:
+                bytes: 574
+                line: 28
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: " "
+        expr_list:
+          pairs:
+            - End:
+                Function:
+                  - leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 574
+                        line: 28
+                        character: 14
+                      end_position:
+                        bytes: 582
+                        line: 28
+                        character: 22
+                      token_type:
+                        type: Symbol
+                        symbol: function
+                    trailing_trivia: []
+                  - parameters_parentheses:
+                      tokens:
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 582
+                              line: 28
+                              character: 22
+                            end_position:
+                              bytes: 583
+                              line: 28
+                              character: 23
+                            token_type:
+                              type: Symbol
+                              symbol: (
+                          trailing_trivia: []
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 583
+                              line: 28
+                              character: 23
+                            end_position:
+                              bytes: 584
+                              line: 28
+                              character: 24
+                            token_type:
+                              type: Symbol
+                              symbol: )
+                          trailing_trivia: []
+                    parameters:
+                      pairs: []
+                    type_specifiers: []
+                    return_type:
+                      punctuation:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 584
+                            line: 28
+                            character: 24
+                          end_position:
+                            bytes: 585
+                            line: 28
+                            character: 25
+                          token_type:
+                            type: Symbol
+                            symbol: ":"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 585
+                              line: 28
+                              character: 25
+                            end_position:
+                              bytes: 586
+                              line: 28
+                              character: 26
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      type_info:
+                        Optional:
+                          base:
+                            Basic:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 586
+                                  line: 28
+                                  character: 26
+                                end_position:
+                                  bytes: 592
+                                  line: 28
+                                  character: 32
+                                token_type:
+                                  type: Identifier
+                                  identifier: number
+                              trailing_trivia: []
+                          question_mark:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 592
+                                line: 28
+                                character: 32
+                              end_position:
+                                bytes: 593
+                                line: 28
+                                character: 33
+                              token_type:
+                                type: Symbol
+                                symbol: "?"
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 593
+                                  line: 28
+                                  character: 33
+                                end_position:
+                                  bytes: 594
+                                  line: 28
+                                  character: 33
+                                token_type:
+                                  type: Whitespace
+                                  characters: "\n"
+                    block:
+                      stmts: []
+                      last_stmt:
+                        - Return:
+                            token:
+                              leading_trivia:
+                                - start_position:
+                                    bytes: 594
+                                    line: 29
+                                    character: 1
+                                  end_position:
+                                    bytes: 595
+                                    line: 29
+                                    character: 2
+                                  token_type:
+                                    type: Whitespace
+                                    characters: "\t"
+                              token:
+                                start_position:
+                                  bytes: 595
+                                  line: 29
+                                  character: 2
+                                end_position:
+                                  bytes: 601
+                                  line: 29
+                                  character: 8
+                                token_type:
+                                  type: Symbol
+                                  symbol: return
+                              trailing_trivia:
+                                - start_position:
+                                    bytes: 601
+                                    line: 29
+                                    character: 8
+                                  end_position:
+                                    bytes: 602
+                                    line: 29
+                                    character: 9
+                                  token_type:
+                                    type: Whitespace
+                                    characters: " "
+                            returns:
+                              pairs:
+                                - End:
+                                    Number:
+                                      leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 602
+                                          line: 29
+                                          character: 9
+                                        end_position:
+                                          bytes: 603
+                                          line: 29
+                                          character: 10
+                                        token_type:
+                                          type: Number
+                                          text: "3"
+                                      trailing_trivia:
+                                        - start_position:
+                                            bytes: 603
+                                            line: 29
+                                            character: 10
+                                          end_position:
+                                            bytes: 604
+                                            line: 29
+                                            character: 10
+                                          token_type:
+                                            type: Whitespace
+                                            characters: "\n"
+                        - ~
+                    end_token:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 604
+                          line: 30
+                          character: 1
+                        end_position:
+                          bytes: 607
+                          line: 30
+                          character: 4
+                        token_type:
+                          type: Symbol
+                          symbol: end
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 607
+                            line: 30
+                            character: 4
+                          end_position:
+                            bytes: 608
+                            line: 30
+                            character: 4
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..5a7f78387858afaa3c7b098bca6bbcaa04ec59f5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types/source.lua
@@ -0,0 +1,30 @@
+--!strict
+local _fn3
+type Object = { x: number, y: number }
+type Typeof = typeof(2 + 2 + _fn3())
+type Element = { [string]: number }
+
+type Callback1 = (string) -> number
+type Callback2 = (string, string) -> number
+type Callback3 = (string, string) -> (string, nil)
+type Callback4 = (string) -> (string) -> nil
+
+type Foo = {
+	bar: number,
+	baz: number,
+}
+
+local foo0: number = 3
+local _foo1: number?
+local _bar0 = foo0 :: number
+local _foo4: string, _bar1: string
+
+function _fn0(param: string): string
+	return param
+end
+
+function _fn2(a: string, b: string) end
+
+local _fn3 = function(): number?
+	return 3
+end
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d8097659cdfa24d7d4ba105f2d6e6174264a2507
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types/tokens.snap
@@ -0,0 +1,2996 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/roblox_cases/pass/types
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 9
+    line: 1
+    character: 10
+  token_type:
+    type: SingleLineComment
+    comment: "!strict"
+- 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: 20
+    line: 2
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: _fn3
+- start_position:
+    bytes: 20
+    line: 2
+    character: 11
+  end_position:
+    bytes: 21
+    line: 2
+    character: 11
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 21
+    line: 3
+    character: 1
+  end_position:
+    bytes: 25
+    line: 3
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: type
+- start_position:
+    bytes: 25
+    line: 3
+    character: 5
+  end_position:
+    bytes: 26
+    line: 3
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 26
+    line: 3
+    character: 6
+  end_position:
+    bytes: 32
+    line: 3
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: Object
+- start_position:
+    bytes: 32
+    line: 3
+    character: 12
+  end_position:
+    bytes: 33
+    line: 3
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 33
+    line: 3
+    character: 13
+  end_position:
+    bytes: 34
+    line: 3
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 34
+    line: 3
+    character: 14
+  end_position:
+    bytes: 35
+    line: 3
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 35
+    line: 3
+    character: 15
+  end_position:
+    bytes: 36
+    line: 3
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 36
+    line: 3
+    character: 16
+  end_position:
+    bytes: 37
+    line: 3
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 37
+    line: 3
+    character: 17
+  end_position:
+    bytes: 38
+    line: 3
+    character: 18
+  token_type:
+    type: Identifier
+    identifier: x
+- start_position:
+    bytes: 38
+    line: 3
+    character: 18
+  end_position:
+    bytes: 39
+    line: 3
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 39
+    line: 3
+    character: 19
+  end_position:
+    bytes: 40
+    line: 3
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 40
+    line: 3
+    character: 20
+  end_position:
+    bytes: 46
+    line: 3
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 46
+    line: 3
+    character: 26
+  end_position:
+    bytes: 47
+    line: 3
+    character: 27
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 47
+    line: 3
+    character: 27
+  end_position:
+    bytes: 48
+    line: 3
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 48
+    line: 3
+    character: 28
+  end_position:
+    bytes: 49
+    line: 3
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 49
+    line: 3
+    character: 29
+  end_position:
+    bytes: 50
+    line: 3
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 50
+    line: 3
+    character: 30
+  end_position:
+    bytes: 51
+    line: 3
+    character: 31
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 51
+    line: 3
+    character: 31
+  end_position:
+    bytes: 57
+    line: 3
+    character: 37
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 57
+    line: 3
+    character: 37
+  end_position:
+    bytes: 58
+    line: 3
+    character: 38
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 58
+    line: 3
+    character: 38
+  end_position:
+    bytes: 59
+    line: 3
+    character: 39
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 59
+    line: 3
+    character: 39
+  end_position:
+    bytes: 60
+    line: 3
+    character: 39
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 60
+    line: 4
+    character: 1
+  end_position:
+    bytes: 64
+    line: 4
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: type
+- start_position:
+    bytes: 64
+    line: 4
+    character: 5
+  end_position:
+    bytes: 65
+    line: 4
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 65
+    line: 4
+    character: 6
+  end_position:
+    bytes: 71
+    line: 4
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: Typeof
+- start_position:
+    bytes: 71
+    line: 4
+    character: 12
+  end_position:
+    bytes: 72
+    line: 4
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 72
+    line: 4
+    character: 13
+  end_position:
+    bytes: 73
+    line: 4
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 73
+    line: 4
+    character: 14
+  end_position:
+    bytes: 74
+    line: 4
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 74
+    line: 4
+    character: 15
+  end_position:
+    bytes: 80
+    line: 4
+    character: 21
+  token_type:
+    type: Identifier
+    identifier: typeof
+- start_position:
+    bytes: 80
+    line: 4
+    character: 21
+  end_position:
+    bytes: 81
+    line: 4
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 81
+    line: 4
+    character: 22
+  end_position:
+    bytes: 82
+    line: 4
+    character: 23
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 82
+    line: 4
+    character: 23
+  end_position:
+    bytes: 83
+    line: 4
+    character: 24
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 83
+    line: 4
+    character: 24
+  end_position:
+    bytes: 84
+    line: 4
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 84
+    line: 4
+    character: 25
+  end_position:
+    bytes: 85
+    line: 4
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 85
+    line: 4
+    character: 26
+  end_position:
+    bytes: 86
+    line: 4
+    character: 27
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 86
+    line: 4
+    character: 27
+  end_position:
+    bytes: 87
+    line: 4
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 87
+    line: 4
+    character: 28
+  end_position:
+    bytes: 88
+    line: 4
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: +
+- start_position:
+    bytes: 88
+    line: 4
+    character: 29
+  end_position:
+    bytes: 89
+    line: 4
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 89
+    line: 4
+    character: 30
+  end_position:
+    bytes: 93
+    line: 4
+    character: 34
+  token_type:
+    type: Identifier
+    identifier: _fn3
+- start_position:
+    bytes: 93
+    line: 4
+    character: 34
+  end_position:
+    bytes: 94
+    line: 4
+    character: 35
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 94
+    line: 4
+    character: 35
+  end_position:
+    bytes: 95
+    line: 4
+    character: 36
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 95
+    line: 4
+    character: 36
+  end_position:
+    bytes: 96
+    line: 4
+    character: 37
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 96
+    line: 4
+    character: 37
+  end_position:
+    bytes: 97
+    line: 4
+    character: 37
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 97
+    line: 5
+    character: 1
+  end_position:
+    bytes: 101
+    line: 5
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: type
+- start_position:
+    bytes: 101
+    line: 5
+    character: 5
+  end_position:
+    bytes: 102
+    line: 5
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 102
+    line: 5
+    character: 6
+  end_position:
+    bytes: 109
+    line: 5
+    character: 13
+  token_type:
+    type: Identifier
+    identifier: Element
+- start_position:
+    bytes: 109
+    line: 5
+    character: 13
+  end_position:
+    bytes: 110
+    line: 5
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 110
+    line: 5
+    character: 14
+  end_position:
+    bytes: 111
+    line: 5
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 111
+    line: 5
+    character: 15
+  end_position:
+    bytes: 112
+    line: 5
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 112
+    line: 5
+    character: 16
+  end_position:
+    bytes: 113
+    line: 5
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 113
+    line: 5
+    character: 17
+  end_position:
+    bytes: 114
+    line: 5
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 114
+    line: 5
+    character: 18
+  end_position:
+    bytes: 115
+    line: 5
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: "["
+- start_position:
+    bytes: 115
+    line: 5
+    character: 19
+  end_position:
+    bytes: 121
+    line: 5
+    character: 25
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 121
+    line: 5
+    character: 25
+  end_position:
+    bytes: 122
+    line: 5
+    character: 26
+  token_type:
+    type: Symbol
+    symbol: "]"
+- start_position:
+    bytes: 122
+    line: 5
+    character: 26
+  end_position:
+    bytes: 123
+    line: 5
+    character: 27
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 123
+    line: 5
+    character: 27
+  end_position:
+    bytes: 124
+    line: 5
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 124
+    line: 5
+    character: 28
+  end_position:
+    bytes: 130
+    line: 5
+    character: 34
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 130
+    line: 5
+    character: 34
+  end_position:
+    bytes: 131
+    line: 5
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 131
+    line: 5
+    character: 35
+  end_position:
+    bytes: 132
+    line: 5
+    character: 36
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 132
+    line: 5
+    character: 36
+  end_position:
+    bytes: 133
+    line: 5
+    character: 36
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 133
+    line: 6
+    character: 1
+  end_position:
+    bytes: 134
+    line: 6
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 134
+    line: 7
+    character: 1
+  end_position:
+    bytes: 138
+    line: 7
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: type
+- start_position:
+    bytes: 138
+    line: 7
+    character: 5
+  end_position:
+    bytes: 139
+    line: 7
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 139
+    line: 7
+    character: 6
+  end_position:
+    bytes: 148
+    line: 7
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: Callback1
+- start_position:
+    bytes: 148
+    line: 7
+    character: 15
+  end_position:
+    bytes: 149
+    line: 7
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 149
+    line: 7
+    character: 16
+  end_position:
+    bytes: 150
+    line: 7
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 150
+    line: 7
+    character: 17
+  end_position:
+    bytes: 151
+    line: 7
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 151
+    line: 7
+    character: 18
+  end_position:
+    bytes: 152
+    line: 7
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 152
+    line: 7
+    character: 19
+  end_position:
+    bytes: 158
+    line: 7
+    character: 25
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 158
+    line: 7
+    character: 25
+  end_position:
+    bytes: 159
+    line: 7
+    character: 26
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 159
+    line: 7
+    character: 26
+  end_position:
+    bytes: 160
+    line: 7
+    character: 27
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 160
+    line: 7
+    character: 27
+  end_position:
+    bytes: 162
+    line: 7
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: "->"
+- start_position:
+    bytes: 162
+    line: 7
+    character: 29
+  end_position:
+    bytes: 163
+    line: 7
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 163
+    line: 7
+    character: 30
+  end_position:
+    bytes: 169
+    line: 7
+    character: 36
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 169
+    line: 7
+    character: 36
+  end_position:
+    bytes: 170
+    line: 7
+    character: 36
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 170
+    line: 8
+    character: 1
+  end_position:
+    bytes: 174
+    line: 8
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: type
+- start_position:
+    bytes: 174
+    line: 8
+    character: 5
+  end_position:
+    bytes: 175
+    line: 8
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 175
+    line: 8
+    character: 6
+  end_position:
+    bytes: 184
+    line: 8
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: Callback2
+- start_position:
+    bytes: 184
+    line: 8
+    character: 15
+  end_position:
+    bytes: 185
+    line: 8
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 185
+    line: 8
+    character: 16
+  end_position:
+    bytes: 186
+    line: 8
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 186
+    line: 8
+    character: 17
+  end_position:
+    bytes: 187
+    line: 8
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 187
+    line: 8
+    character: 18
+  end_position:
+    bytes: 188
+    line: 8
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 188
+    line: 8
+    character: 19
+  end_position:
+    bytes: 194
+    line: 8
+    character: 25
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 194
+    line: 8
+    character: 25
+  end_position:
+    bytes: 195
+    line: 8
+    character: 26
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 195
+    line: 8
+    character: 26
+  end_position:
+    bytes: 196
+    line: 8
+    character: 27
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 196
+    line: 8
+    character: 27
+  end_position:
+    bytes: 202
+    line: 8
+    character: 33
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 202
+    line: 8
+    character: 33
+  end_position:
+    bytes: 203
+    line: 8
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 203
+    line: 8
+    character: 34
+  end_position:
+    bytes: 204
+    line: 8
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 204
+    line: 8
+    character: 35
+  end_position:
+    bytes: 206
+    line: 8
+    character: 37
+  token_type:
+    type: Symbol
+    symbol: "->"
+- start_position:
+    bytes: 206
+    line: 8
+    character: 37
+  end_position:
+    bytes: 207
+    line: 8
+    character: 38
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 207
+    line: 8
+    character: 38
+  end_position:
+    bytes: 213
+    line: 8
+    character: 44
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 213
+    line: 8
+    character: 44
+  end_position:
+    bytes: 214
+    line: 8
+    character: 44
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 214
+    line: 9
+    character: 1
+  end_position:
+    bytes: 218
+    line: 9
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: type
+- start_position:
+    bytes: 218
+    line: 9
+    character: 5
+  end_position:
+    bytes: 219
+    line: 9
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 219
+    line: 9
+    character: 6
+  end_position:
+    bytes: 228
+    line: 9
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: Callback3
+- start_position:
+    bytes: 228
+    line: 9
+    character: 15
+  end_position:
+    bytes: 229
+    line: 9
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 229
+    line: 9
+    character: 16
+  end_position:
+    bytes: 230
+    line: 9
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 230
+    line: 9
+    character: 17
+  end_position:
+    bytes: 231
+    line: 9
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 231
+    line: 9
+    character: 18
+  end_position:
+    bytes: 232
+    line: 9
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 232
+    line: 9
+    character: 19
+  end_position:
+    bytes: 238
+    line: 9
+    character: 25
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 238
+    line: 9
+    character: 25
+  end_position:
+    bytes: 239
+    line: 9
+    character: 26
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 239
+    line: 9
+    character: 26
+  end_position:
+    bytes: 240
+    line: 9
+    character: 27
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 240
+    line: 9
+    character: 27
+  end_position:
+    bytes: 246
+    line: 9
+    character: 33
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 246
+    line: 9
+    character: 33
+  end_position:
+    bytes: 247
+    line: 9
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 247
+    line: 9
+    character: 34
+  end_position:
+    bytes: 248
+    line: 9
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 248
+    line: 9
+    character: 35
+  end_position:
+    bytes: 250
+    line: 9
+    character: 37
+  token_type:
+    type: Symbol
+    symbol: "->"
+- start_position:
+    bytes: 250
+    line: 9
+    character: 37
+  end_position:
+    bytes: 251
+    line: 9
+    character: 38
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 251
+    line: 9
+    character: 38
+  end_position:
+    bytes: 252
+    line: 9
+    character: 39
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 252
+    line: 9
+    character: 39
+  end_position:
+    bytes: 258
+    line: 9
+    character: 45
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 258
+    line: 9
+    character: 45
+  end_position:
+    bytes: 259
+    line: 9
+    character: 46
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 259
+    line: 9
+    character: 46
+  end_position:
+    bytes: 260
+    line: 9
+    character: 47
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 260
+    line: 9
+    character: 47
+  end_position:
+    bytes: 263
+    line: 9
+    character: 50
+  token_type:
+    type: Symbol
+    symbol: nil
+- start_position:
+    bytes: 263
+    line: 9
+    character: 50
+  end_position:
+    bytes: 264
+    line: 9
+    character: 51
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 264
+    line: 9
+    character: 51
+  end_position:
+    bytes: 265
+    line: 9
+    character: 51
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 265
+    line: 10
+    character: 1
+  end_position:
+    bytes: 269
+    line: 10
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: type
+- start_position:
+    bytes: 269
+    line: 10
+    character: 5
+  end_position:
+    bytes: 270
+    line: 10
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 270
+    line: 10
+    character: 6
+  end_position:
+    bytes: 279
+    line: 10
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: Callback4
+- start_position:
+    bytes: 279
+    line: 10
+    character: 15
+  end_position:
+    bytes: 280
+    line: 10
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 280
+    line: 10
+    character: 16
+  end_position:
+    bytes: 281
+    line: 10
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 281
+    line: 10
+    character: 17
+  end_position:
+    bytes: 282
+    line: 10
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 282
+    line: 10
+    character: 18
+  end_position:
+    bytes: 283
+    line: 10
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 283
+    line: 10
+    character: 19
+  end_position:
+    bytes: 289
+    line: 10
+    character: 25
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 289
+    line: 10
+    character: 25
+  end_position:
+    bytes: 290
+    line: 10
+    character: 26
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 290
+    line: 10
+    character: 26
+  end_position:
+    bytes: 291
+    line: 10
+    character: 27
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 291
+    line: 10
+    character: 27
+  end_position:
+    bytes: 293
+    line: 10
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: "->"
+- start_position:
+    bytes: 293
+    line: 10
+    character: 29
+  end_position:
+    bytes: 294
+    line: 10
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 294
+    line: 10
+    character: 30
+  end_position:
+    bytes: 295
+    line: 10
+    character: 31
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 295
+    line: 10
+    character: 31
+  end_position:
+    bytes: 301
+    line: 10
+    character: 37
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 301
+    line: 10
+    character: 37
+  end_position:
+    bytes: 302
+    line: 10
+    character: 38
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 302
+    line: 10
+    character: 38
+  end_position:
+    bytes: 303
+    line: 10
+    character: 39
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 303
+    line: 10
+    character: 39
+  end_position:
+    bytes: 305
+    line: 10
+    character: 41
+  token_type:
+    type: Symbol
+    symbol: "->"
+- start_position:
+    bytes: 305
+    line: 10
+    character: 41
+  end_position:
+    bytes: 306
+    line: 10
+    character: 42
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 306
+    line: 10
+    character: 42
+  end_position:
+    bytes: 309
+    line: 10
+    character: 45
+  token_type:
+    type: Symbol
+    symbol: nil
+- start_position:
+    bytes: 309
+    line: 10
+    character: 45
+  end_position:
+    bytes: 310
+    line: 10
+    character: 45
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 310
+    line: 11
+    character: 1
+  end_position:
+    bytes: 311
+    line: 11
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 311
+    line: 12
+    character: 1
+  end_position:
+    bytes: 315
+    line: 12
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: type
+- start_position:
+    bytes: 315
+    line: 12
+    character: 5
+  end_position:
+    bytes: 316
+    line: 12
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 316
+    line: 12
+    character: 6
+  end_position:
+    bytes: 319
+    line: 12
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: Foo
+- start_position:
+    bytes: 319
+    line: 12
+    character: 9
+  end_position:
+    bytes: 320
+    line: 12
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 320
+    line: 12
+    character: 10
+  end_position:
+    bytes: 321
+    line: 12
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 321
+    line: 12
+    character: 11
+  end_position:
+    bytes: 322
+    line: 12
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 322
+    line: 12
+    character: 12
+  end_position:
+    bytes: 323
+    line: 12
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 323
+    line: 12
+    character: 13
+  end_position:
+    bytes: 324
+    line: 12
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 324
+    line: 13
+    character: 1
+  end_position:
+    bytes: 325
+    line: 13
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 325
+    line: 13
+    character: 2
+  end_position:
+    bytes: 328
+    line: 13
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 328
+    line: 13
+    character: 5
+  end_position:
+    bytes: 329
+    line: 13
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 329
+    line: 13
+    character: 6
+  end_position:
+    bytes: 330
+    line: 13
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 330
+    line: 13
+    character: 7
+  end_position:
+    bytes: 336
+    line: 13
+    character: 13
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 336
+    line: 13
+    character: 13
+  end_position:
+    bytes: 337
+    line: 13
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 337
+    line: 13
+    character: 14
+  end_position:
+    bytes: 338
+    line: 13
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 338
+    line: 14
+    character: 1
+  end_position:
+    bytes: 339
+    line: 14
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 339
+    line: 14
+    character: 2
+  end_position:
+    bytes: 342
+    line: 14
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 342
+    line: 14
+    character: 5
+  end_position:
+    bytes: 343
+    line: 14
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 343
+    line: 14
+    character: 6
+  end_position:
+    bytes: 344
+    line: 14
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 344
+    line: 14
+    character: 7
+  end_position:
+    bytes: 350
+    line: 14
+    character: 13
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 350
+    line: 14
+    character: 13
+  end_position:
+    bytes: 351
+    line: 14
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 351
+    line: 14
+    character: 14
+  end_position:
+    bytes: 352
+    line: 14
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 352
+    line: 15
+    character: 1
+  end_position:
+    bytes: 353
+    line: 15
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 353
+    line: 15
+    character: 2
+  end_position:
+    bytes: 354
+    line: 15
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 354
+    line: 16
+    character: 1
+  end_position:
+    bytes: 355
+    line: 16
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 355
+    line: 17
+    character: 1
+  end_position:
+    bytes: 360
+    line: 17
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 360
+    line: 17
+    character: 6
+  end_position:
+    bytes: 361
+    line: 17
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 361
+    line: 17
+    character: 7
+  end_position:
+    bytes: 365
+    line: 17
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: foo0
+- start_position:
+    bytes: 365
+    line: 17
+    character: 11
+  end_position:
+    bytes: 366
+    line: 17
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 366
+    line: 17
+    character: 12
+  end_position:
+    bytes: 367
+    line: 17
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 367
+    line: 17
+    character: 13
+  end_position:
+    bytes: 373
+    line: 17
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 373
+    line: 17
+    character: 19
+  end_position:
+    bytes: 374
+    line: 17
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 374
+    line: 17
+    character: 20
+  end_position:
+    bytes: 375
+    line: 17
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 375
+    line: 17
+    character: 21
+  end_position:
+    bytes: 376
+    line: 17
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 376
+    line: 17
+    character: 22
+  end_position:
+    bytes: 377
+    line: 17
+    character: 23
+  token_type:
+    type: Number
+    text: "3"
+- start_position:
+    bytes: 377
+    line: 17
+    character: 23
+  end_position:
+    bytes: 378
+    line: 17
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 378
+    line: 18
+    character: 1
+  end_position:
+    bytes: 383
+    line: 18
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 383
+    line: 18
+    character: 6
+  end_position:
+    bytes: 384
+    line: 18
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 384
+    line: 18
+    character: 7
+  end_position:
+    bytes: 389
+    line: 18
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: _foo1
+- start_position:
+    bytes: 389
+    line: 18
+    character: 12
+  end_position:
+    bytes: 390
+    line: 18
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 390
+    line: 18
+    character: 13
+  end_position:
+    bytes: 391
+    line: 18
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 391
+    line: 18
+    character: 14
+  end_position:
+    bytes: 397
+    line: 18
+    character: 20
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 397
+    line: 18
+    character: 20
+  end_position:
+    bytes: 398
+    line: 18
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: "?"
+- start_position:
+    bytes: 398
+    line: 18
+    character: 21
+  end_position:
+    bytes: 399
+    line: 18
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 399
+    line: 19
+    character: 1
+  end_position:
+    bytes: 404
+    line: 19
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 404
+    line: 19
+    character: 6
+  end_position:
+    bytes: 405
+    line: 19
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 405
+    line: 19
+    character: 7
+  end_position:
+    bytes: 410
+    line: 19
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: _bar0
+- start_position:
+    bytes: 410
+    line: 19
+    character: 12
+  end_position:
+    bytes: 411
+    line: 19
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 411
+    line: 19
+    character: 13
+  end_position:
+    bytes: 412
+    line: 19
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 412
+    line: 19
+    character: 14
+  end_position:
+    bytes: 413
+    line: 19
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 413
+    line: 19
+    character: 15
+  end_position:
+    bytes: 417
+    line: 19
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: foo0
+- start_position:
+    bytes: 417
+    line: 19
+    character: 19
+  end_position:
+    bytes: 418
+    line: 19
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 418
+    line: 19
+    character: 20
+  end_position:
+    bytes: 420
+    line: 19
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: "::"
+- start_position:
+    bytes: 420
+    line: 19
+    character: 22
+  end_position:
+    bytes: 421
+    line: 19
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 421
+    line: 19
+    character: 23
+  end_position:
+    bytes: 427
+    line: 19
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 427
+    line: 19
+    character: 29
+  end_position:
+    bytes: 428
+    line: 19
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 428
+    line: 20
+    character: 1
+  end_position:
+    bytes: 433
+    line: 20
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 433
+    line: 20
+    character: 6
+  end_position:
+    bytes: 434
+    line: 20
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 434
+    line: 20
+    character: 7
+  end_position:
+    bytes: 439
+    line: 20
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: _foo4
+- start_position:
+    bytes: 439
+    line: 20
+    character: 12
+  end_position:
+    bytes: 440
+    line: 20
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 440
+    line: 20
+    character: 13
+  end_position:
+    bytes: 441
+    line: 20
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 441
+    line: 20
+    character: 14
+  end_position:
+    bytes: 447
+    line: 20
+    character: 20
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 447
+    line: 20
+    character: 20
+  end_position:
+    bytes: 448
+    line: 20
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 448
+    line: 20
+    character: 21
+  end_position:
+    bytes: 449
+    line: 20
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 449
+    line: 20
+    character: 22
+  end_position:
+    bytes: 454
+    line: 20
+    character: 27
+  token_type:
+    type: Identifier
+    identifier: _bar1
+- start_position:
+    bytes: 454
+    line: 20
+    character: 27
+  end_position:
+    bytes: 455
+    line: 20
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 455
+    line: 20
+    character: 28
+  end_position:
+    bytes: 456
+    line: 20
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 456
+    line: 20
+    character: 29
+  end_position:
+    bytes: 462
+    line: 20
+    character: 35
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 462
+    line: 20
+    character: 35
+  end_position:
+    bytes: 463
+    line: 20
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 463
+    line: 21
+    character: 1
+  end_position:
+    bytes: 464
+    line: 21
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 464
+    line: 22
+    character: 1
+  end_position:
+    bytes: 472
+    line: 22
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: function
+- start_position:
+    bytes: 472
+    line: 22
+    character: 9
+  end_position:
+    bytes: 473
+    line: 22
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 473
+    line: 22
+    character: 10
+  end_position:
+    bytes: 477
+    line: 22
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: _fn0
+- start_position:
+    bytes: 477
+    line: 22
+    character: 14
+  end_position:
+    bytes: 478
+    line: 22
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 478
+    line: 22
+    character: 15
+  end_position:
+    bytes: 483
+    line: 22
+    character: 20
+  token_type:
+    type: Identifier
+    identifier: param
+- start_position:
+    bytes: 483
+    line: 22
+    character: 20
+  end_position:
+    bytes: 484
+    line: 22
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 484
+    line: 22
+    character: 21
+  end_position:
+    bytes: 485
+    line: 22
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 485
+    line: 22
+    character: 22
+  end_position:
+    bytes: 491
+    line: 22
+    character: 28
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 491
+    line: 22
+    character: 28
+  end_position:
+    bytes: 492
+    line: 22
+    character: 29
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 492
+    line: 22
+    character: 29
+  end_position:
+    bytes: 493
+    line: 22
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 493
+    line: 22
+    character: 30
+  end_position:
+    bytes: 494
+    line: 22
+    character: 31
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 494
+    line: 22
+    character: 31
+  end_position:
+    bytes: 500
+    line: 22
+    character: 37
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 500
+    line: 22
+    character: 37
+  end_position:
+    bytes: 501
+    line: 22
+    character: 37
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 501
+    line: 23
+    character: 1
+  end_position:
+    bytes: 502
+    line: 23
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 502
+    line: 23
+    character: 2
+  end_position:
+    bytes: 508
+    line: 23
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 508
+    line: 23
+    character: 8
+  end_position:
+    bytes: 509
+    line: 23
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 509
+    line: 23
+    character: 9
+  end_position:
+    bytes: 514
+    line: 23
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: param
+- start_position:
+    bytes: 514
+    line: 23
+    character: 14
+  end_position:
+    bytes: 515
+    line: 23
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 515
+    line: 24
+    character: 1
+  end_position:
+    bytes: 518
+    line: 24
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 518
+    line: 24
+    character: 4
+  end_position:
+    bytes: 519
+    line: 24
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 519
+    line: 25
+    character: 1
+  end_position:
+    bytes: 520
+    line: 25
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 520
+    line: 26
+    character: 1
+  end_position:
+    bytes: 528
+    line: 26
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: function
+- start_position:
+    bytes: 528
+    line: 26
+    character: 9
+  end_position:
+    bytes: 529
+    line: 26
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 529
+    line: 26
+    character: 10
+  end_position:
+    bytes: 533
+    line: 26
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: _fn2
+- start_position:
+    bytes: 533
+    line: 26
+    character: 14
+  end_position:
+    bytes: 534
+    line: 26
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 534
+    line: 26
+    character: 15
+  end_position:
+    bytes: 535
+    line: 26
+    character: 16
+  token_type:
+    type: Identifier
+    identifier: a
+- start_position:
+    bytes: 535
+    line: 26
+    character: 16
+  end_position:
+    bytes: 536
+    line: 26
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 536
+    line: 26
+    character: 17
+  end_position:
+    bytes: 537
+    line: 26
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 537
+    line: 26
+    character: 18
+  end_position:
+    bytes: 543
+    line: 26
+    character: 24
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 543
+    line: 26
+    character: 24
+  end_position:
+    bytes: 544
+    line: 26
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 544
+    line: 26
+    character: 25
+  end_position:
+    bytes: 545
+    line: 26
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 545
+    line: 26
+    character: 26
+  end_position:
+    bytes: 546
+    line: 26
+    character: 27
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 546
+    line: 26
+    character: 27
+  end_position:
+    bytes: 547
+    line: 26
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 547
+    line: 26
+    character: 28
+  end_position:
+    bytes: 548
+    line: 26
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 548
+    line: 26
+    character: 29
+  end_position:
+    bytes: 554
+    line: 26
+    character: 35
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 554
+    line: 26
+    character: 35
+  end_position:
+    bytes: 555
+    line: 26
+    character: 36
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 555
+    line: 26
+    character: 36
+  end_position:
+    bytes: 556
+    line: 26
+    character: 37
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 556
+    line: 26
+    character: 37
+  end_position:
+    bytes: 559
+    line: 26
+    character: 40
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 559
+    line: 26
+    character: 40
+  end_position:
+    bytes: 560
+    line: 26
+    character: 40
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 560
+    line: 27
+    character: 1
+  end_position:
+    bytes: 561
+    line: 27
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 561
+    line: 28
+    character: 1
+  end_position:
+    bytes: 566
+    line: 28
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: local
+- start_position:
+    bytes: 566
+    line: 28
+    character: 6
+  end_position:
+    bytes: 567
+    line: 28
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 567
+    line: 28
+    character: 7
+  end_position:
+    bytes: 571
+    line: 28
+    character: 11
+  token_type:
+    type: Identifier
+    identifier: _fn3
+- start_position:
+    bytes: 571
+    line: 28
+    character: 11
+  end_position:
+    bytes: 572
+    line: 28
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 572
+    line: 28
+    character: 12
+  end_position:
+    bytes: 573
+    line: 28
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 573
+    line: 28
+    character: 13
+  end_position:
+    bytes: 574
+    line: 28
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 574
+    line: 28
+    character: 14
+  end_position:
+    bytes: 582
+    line: 28
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: function
+- start_position:
+    bytes: 582
+    line: 28
+    character: 22
+  end_position:
+    bytes: 583
+    line: 28
+    character: 23
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 583
+    line: 28
+    character: 23
+  end_position:
+    bytes: 584
+    line: 28
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 584
+    line: 28
+    character: 24
+  end_position:
+    bytes: 585
+    line: 28
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 585
+    line: 28
+    character: 25
+  end_position:
+    bytes: 586
+    line: 28
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 586
+    line: 28
+    character: 26
+  end_position:
+    bytes: 592
+    line: 28
+    character: 32
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 592
+    line: 28
+    character: 32
+  end_position:
+    bytes: 593
+    line: 28
+    character: 33
+  token_type:
+    type: Symbol
+    symbol: "?"
+- start_position:
+    bytes: 593
+    line: 28
+    character: 33
+  end_position:
+    bytes: 594
+    line: 28
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 594
+    line: 29
+    character: 1
+  end_position:
+    bytes: 595
+    line: 29
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 595
+    line: 29
+    character: 2
+  end_position:
+    bytes: 601
+    line: 29
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 601
+    line: 29
+    character: 8
+  end_position:
+    bytes: 602
+    line: 29
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 602
+    line: 29
+    character: 9
+  end_position:
+    bytes: 603
+    line: 29
+    character: 10
+  token_type:
+    type: Number
+    text: "3"
+- start_position:
+    bytes: 603
+    line: 29
+    character: 10
+  end_position:
+    bytes: 604
+    line: 29
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 604
+    line: 30
+    character: 1
+  end_position:
+    bytes: 607
+    line: 30
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 607
+    line: 30
+    character: 4
+  end_position:
+    bytes: 608
+    line: 30
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 608
+    line: 31
+    character: 1
+  end_position:
+    bytes: 608
+    line: 31
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_chained_optionals/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_chained_optionals/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..571b14414d2b8904c09890b554ea3800a11392d8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_chained_optionals/ast.snap
@@ -0,0 +1,655 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/roblox_cases/pass/types_chained_optionals
+---
+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: " "
+        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/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_chained_optionals/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_chained_optionals/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0809eac6534258c3e682f19f6323304df3f07bb8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_chained_optionals/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_chained_optionals/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..30a578174dfc2eb856cfc4e8521e89f9424bf064
--- /dev/null
+++ b/src/Rust/vvs_parser/src/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/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_loops/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_loops/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..09e4dc03bdf21f57b721a53731c6eea34189515f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_loops/ast.snap
@@ -0,0 +1,605 @@
+---
+source: full-moon/tests/pass_cases.rs
+assertion_line: 52
+expression: ast.nodes()
+input_file: full-moon/tests/roblox_cases/pass/types_loops
+---
+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:
+            - Punctuated:
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 4
+                      line: 1
+                      character: 5
+                    end_position:
+                      bytes: 5
+                      line: 1
+                      character: 6
+                    token_type:
+                      type: Identifier
+                      identifier: i
+                  trailing_trivia: []
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 5
+                      line: 1
+                      character: 6
+                    end_position:
+                      bytes: 6
+                      line: 1
+                      character: 7
+                    token_type:
+                      type: Symbol
+                      symbol: ","
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 6
+                        line: 1
+                        character: 7
+                      end_position:
+                        bytes: 7
+                        line: 1
+                        character: 8
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 7
+                    line: 1
+                    character: 8
+                  end_position:
+                    bytes: 8
+                    line: 1
+                    character: 9
+                  token_type:
+                    type: Identifier
+                    identifier: v
+                trailing_trivia: []
+        in_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 17
+              line: 1
+              character: 18
+            end_position:
+              bytes: 19
+              line: 1
+              character: 20
+            token_type:
+              type: Symbol
+              symbol: in
+          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:
+                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: 26
+                                      line: 1
+                                      character: 27
+                                    end_position:
+                                      bytes: 27
+                                      line: 1
+                                      character: 28
+                                    token_type:
+                                      type: Symbol
+                                      symbol: )
+                                  trailing_trivia:
+                                    - start_position:
+                                        bytes: 27
+                                        line: 1
+                                        character: 28
+                                      end_position:
+                                        bytes: 28
+                                        line: 1
+                                        character: 29
+                                      token_type:
+                                        type: Whitespace
+                                        characters: " "
+                            arguments:
+                              pairs: []
+        do_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 28
+              line: 1
+              character: 29
+            end_position:
+              bytes: 30
+              line: 1
+              character: 31
+            token_type:
+              type: Symbol
+              symbol: do
+          trailing_trivia:
+            - start_position:
+                bytes: 30
+                line: 1
+                character: 31
+              end_position:
+                bytes: 31
+                line: 1
+                character: 31
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        block:
+          stmts: []
+        end_token:
+          leading_trivia:
+            - start_position:
+                bytes: 31
+                line: 2
+                character: 1
+              end_position:
+                bytes: 32
+                line: 2
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 32
+              line: 3
+              character: 1
+            end_position:
+              bytes: 35
+              line: 3
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 35
+                line: 3
+                character: 4
+              end_position:
+                bytes: 36
+                line: 3
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        type_specifiers:
+          - ~
+          - punctuation:
+              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: " "
+            type_info:
+              Basic:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 10
+                    line: 1
+                    character: 11
+                  end_position:
+                    bytes: 16
+                    line: 1
+                    character: 17
+                  token_type:
+                    type: Identifier
+                    identifier: string
+                trailing_trivia:
+                  - start_position:
+                      bytes: 16
+                      line: 1
+                      character: 17
+                    end_position:
+                      bytes: 17
+                      line: 1
+                      character: 18
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+    - ~
+  - - NumericFor:
+        for_token:
+          leading_trivia:
+            - start_position:
+                bytes: 36
+                line: 4
+                character: 1
+              end_position:
+                bytes: 37
+                line: 4
+                character: 1
+              token_type:
+                type: Whitespace
+                characters: "\n"
+          token:
+            start_position:
+              bytes: 37
+              line: 5
+              character: 1
+            end_position:
+              bytes: 40
+              line: 5
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: for
+          trailing_trivia:
+            - start_position:
+                bytes: 40
+                line: 5
+                character: 4
+              end_position:
+                bytes: 41
+                line: 5
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        index_variable:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 41
+              line: 5
+              character: 5
+            end_position:
+              bytes: 42
+              line: 5
+              character: 6
+            token_type:
+              type: Identifier
+              identifier: i
+          trailing_trivia: []
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 51
+              line: 5
+              character: 15
+            end_position:
+              bytes: 52
+              line: 5
+              character: 16
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 52
+                line: 5
+                character: 16
+              end_position:
+                bytes: 53
+                line: 5
+                character: 17
+              token_type:
+                type: Whitespace
+                characters: " "
+        start:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 53
+                line: 5
+                character: 17
+              end_position:
+                bytes: 54
+                line: 5
+                character: 18
+              token_type:
+                type: Number
+                text: "1"
+            trailing_trivia: []
+        start_end_comma:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 54
+              line: 5
+              character: 18
+            end_position:
+              bytes: 55
+              line: 5
+              character: 19
+            token_type:
+              type: Symbol
+              symbol: ","
+          trailing_trivia:
+            - start_position:
+                bytes: 55
+                line: 5
+                character: 19
+              end_position:
+                bytes: 56
+                line: 5
+                character: 20
+              token_type:
+                type: Whitespace
+                characters: " "
+        end:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 56
+                line: 5
+                character: 20
+              end_position:
+                bytes: 58
+                line: 5
+                character: 22
+              token_type:
+                type: Number
+                text: "10"
+            trailing_trivia: []
+        end_step_comma:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 58
+              line: 5
+              character: 22
+            end_position:
+              bytes: 59
+              line: 5
+              character: 23
+            token_type:
+              type: Symbol
+              symbol: ","
+          trailing_trivia:
+            - start_position:
+                bytes: 59
+                line: 5
+                character: 23
+              end_position:
+                bytes: 60
+                line: 5
+                character: 24
+              token_type:
+                type: Whitespace
+                characters: " "
+        step:
+          Number:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 60
+                line: 5
+                character: 24
+              end_position:
+                bytes: 61
+                line: 5
+                character: 25
+              token_type:
+                type: Number
+                text: "2"
+            trailing_trivia:
+              - start_position:
+                  bytes: 61
+                  line: 5
+                  character: 25
+                end_position:
+                  bytes: 62
+                  line: 5
+                  character: 26
+                token_type:
+                  type: Whitespace
+                  characters: " "
+        do_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 62
+              line: 5
+              character: 26
+            end_position:
+              bytes: 64
+              line: 5
+              character: 28
+            token_type:
+              type: Symbol
+              symbol: do
+          trailing_trivia:
+            - start_position:
+                bytes: 64
+                line: 5
+                character: 28
+              end_position:
+                bytes: 65
+                line: 5
+                character: 28
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        block:
+          stmts: []
+        end_token:
+          leading_trivia:
+            - start_position:
+                bytes: 65
+                line: 6
+                character: 1
+              end_position:
+                bytes: 70
+                line: 6
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: "    \n"
+          token:
+            start_position:
+              bytes: 70
+              line: 7
+              character: 1
+            end_position:
+              bytes: 73
+              line: 7
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia: []
+        type_specifier:
+          punctuation:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 42
+                line: 5
+                character: 6
+              end_position:
+                bytes: 43
+                line: 5
+                character: 7
+              token_type:
+                type: Symbol
+                symbol: ":"
+            trailing_trivia:
+              - start_position:
+                  bytes: 43
+                  line: 5
+                  character: 7
+                end_position:
+                  bytes: 44
+                  line: 5
+                  character: 8
+                token_type:
+                  type: Whitespace
+                  characters: " "
+          type_info:
+            Basic:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 44
+                  line: 5
+                  character: 8
+                end_position:
+                  bytes: 50
+                  line: 5
+                  character: 14
+                token_type:
+                  type: Identifier
+                  identifier: number
+              trailing_trivia:
+                - start_position:
+                    bytes: 50
+                    line: 5
+                    character: 14
+                  end_position:
+                    bytes: 51
+                    line: 5
+                    character: 15
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+    - ~
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_loops/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_loops/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..cd3905656fb7f04ba8925a393de9c31b37d94f0c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_loops/source.lua
@@ -0,0 +1,7 @@
+for i, v: string in pairs() do
+
+end
+
+for i: number = 1, 10, 2 do
+    
+end
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_loops/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_loops/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..84b58afe8b64d5f5e3561b8f972b0a98a05adad4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_loops/tokens.snap
@@ -0,0 +1,490 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+input_file: full-moon/tests/roblox_cases/pass/types_loops
+
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- 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: Identifier
+    identifier: i
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: v
+- 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: Identifier
+    identifier: string
+- 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: 19
+    line: 1
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: in
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 25
+    line: 1
+    character: 26
+  token_type:
+    type: Identifier
+    identifier: pairs
+- 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: Symbol
+    symbol: )
+- start_position:
+    bytes: 27
+    line: 1
+    character: 28
+  end_position:
+    bytes: 28
+    line: 1
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 28
+    line: 1
+    character: 29
+  end_position:
+    bytes: 30
+    line: 1
+    character: 31
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 30
+    line: 1
+    character: 31
+  end_position:
+    bytes: 31
+    line: 1
+    character: 31
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 31
+    line: 2
+    character: 1
+  end_position:
+    bytes: 32
+    line: 2
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 32
+    line: 3
+    character: 1
+  end_position:
+    bytes: 35
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 35
+    line: 3
+    character: 4
+  end_position:
+    bytes: 36
+    line: 3
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 36
+    line: 4
+    character: 1
+  end_position:
+    bytes: 37
+    line: 4
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 37
+    line: 5
+    character: 1
+  end_position:
+    bytes: 40
+    line: 5
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: for
+- start_position:
+    bytes: 40
+    line: 5
+    character: 4
+  end_position:
+    bytes: 41
+    line: 5
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 41
+    line: 5
+    character: 5
+  end_position:
+    bytes: 42
+    line: 5
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: i
+- start_position:
+    bytes: 42
+    line: 5
+    character: 6
+  end_position:
+    bytes: 43
+    line: 5
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 43
+    line: 5
+    character: 7
+  end_position:
+    bytes: 44
+    line: 5
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 44
+    line: 5
+    character: 8
+  end_position:
+    bytes: 50
+    line: 5
+    character: 14
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 50
+    line: 5
+    character: 14
+  end_position:
+    bytes: 51
+    line: 5
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 51
+    line: 5
+    character: 15
+  end_position:
+    bytes: 52
+    line: 5
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 52
+    line: 5
+    character: 16
+  end_position:
+    bytes: 53
+    line: 5
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 53
+    line: 5
+    character: 17
+  end_position:
+    bytes: 54
+    line: 5
+    character: 18
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 54
+    line: 5
+    character: 18
+  end_position:
+    bytes: 55
+    line: 5
+    character: 19
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 55
+    line: 5
+    character: 19
+  end_position:
+    bytes: 56
+    line: 5
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 56
+    line: 5
+    character: 20
+  end_position:
+    bytes: 58
+    line: 5
+    character: 22
+  token_type:
+    type: Number
+    text: "10"
+- start_position:
+    bytes: 58
+    line: 5
+    character: 22
+  end_position:
+    bytes: 59
+    line: 5
+    character: 23
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 59
+    line: 5
+    character: 23
+  end_position:
+    bytes: 60
+    line: 5
+    character: 24
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 60
+    line: 5
+    character: 24
+  end_position:
+    bytes: 61
+    line: 5
+    character: 25
+  token_type:
+    type: Number
+    text: "2"
+- start_position:
+    bytes: 61
+    line: 5
+    character: 25
+  end_position:
+    bytes: 62
+    line: 5
+    character: 26
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 62
+    line: 5
+    character: 26
+  end_position:
+    bytes: 64
+    line: 5
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 64
+    line: 5
+    character: 28
+  end_position:
+    bytes: 65
+    line: 5
+    character: 28
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 65
+    line: 6
+    character: 1
+  end_position:
+    bytes: 70
+    line: 6
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    \n"
+- start_position:
+    bytes: 70
+    line: 7
+    character: 1
+  end_position:
+    bytes: 73
+    line: 7
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 73
+    line: 7
+    character: 4
+  end_position:
+    bytes: 73
+    line: 7
+    character: 4
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_nested_array/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_nested_array/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8030101cfaaa22092b8927b1f05a1d52eeb3122e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_nested_array/ast.snap
@@ -0,0 +1,532 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/roblox_cases/pass/types_nested_array
+---
+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: " "
+        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:
+          Array:
+            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: 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"
+            type_info:
+              Array:
+                braces:
+                  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:
+                        - start_position:
+                            bytes: 14
+                            line: 1
+                            character: 15
+                          end_position:
+                            bytes: 15
+                            line: 1
+                            character: 16
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                    - 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: " "
+                type_info:
+                  Basic:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 15
+                        line: 1
+                        character: 16
+                      end_position:
+                        bytes: 21
+                        line: 1
+                        character: 22
+                      token_type:
+                        type: Identifier
+                        identifier: string
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 21
+                          line: 1
+                          character: 22
+                        end_position:
+                          bytes: 22
+                          line: 1
+                          character: 23
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+    - ~
+  - - TypeDeclaration:
+        type_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 26
+              line: 2
+              character: 1
+            end_position:
+              bytes: 30
+              line: 2
+              character: 5
+            token_type:
+              type: Identifier
+              identifier: type
+          trailing_trivia:
+            - start_position:
+                bytes: 30
+                line: 2
+                character: 5
+              end_position:
+                bytes: 31
+                line: 2
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        base:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 31
+              line: 2
+              character: 6
+            end_position:
+              bytes: 34
+              line: 2
+              character: 9
+            token_type:
+              type: Identifier
+              identifier: Foo
+          trailing_trivia:
+            - start_position:
+                bytes: 34
+                line: 2
+                character: 9
+              end_position:
+                bytes: 35
+                line: 2
+                character: 10
+              token_type:
+                type: Whitespace
+                characters: " "
+        equal_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 35
+              line: 2
+              character: 10
+            end_position:
+              bytes: 36
+              line: 2
+              character: 11
+            token_type:
+              type: Symbol
+              symbol: "="
+          trailing_trivia:
+            - start_position:
+                bytes: 36
+                line: 2
+                character: 11
+              end_position:
+                bytes: 37
+                line: 2
+                character: 12
+              token_type:
+                type: Whitespace
+                characters: " "
+        declare_as:
+          Array:
+            braces:
+              tokens:
+                - 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: 14
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 67
+                      line: 2
+                      character: 42
+                    end_position:
+                      bytes: 68
+                      line: 2
+                      character: 43
+                    token_type:
+                      type: Symbol
+                      symbol: "}"
+                  trailing_trivia: []
+            type_info:
+              Table:
+                braces:
+                  tokens:
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 39
+                          line: 2
+                          character: 14
+                        end_position:
+                          bytes: 40
+                          line: 2
+                          character: 15
+                        token_type:
+                          type: Symbol
+                          symbol: "{"
+                      trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 65
+                          line: 2
+                          character: 40
+                        end_position:
+                          bytes: 66
+                          line: 2
+                          character: 41
+                        token_type:
+                          type: Symbol
+                          symbol: "}"
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 66
+                            line: 2
+                            character: 41
+                          end_position:
+                            bytes: 67
+                            line: 2
+                            character: 42
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                fields:
+                  pairs:
+                    - Punctuated:
+                        - key:
+                            Name:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 40
+                                  line: 2
+                                  character: 15
+                                end_position:
+                                  bytes: 44
+                                  line: 2
+                                  character: 19
+                                token_type:
+                                  type: Identifier
+                                  identifier: Name
+                              trailing_trivia: []
+                          colon:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 44
+                                line: 2
+                                character: 19
+                              end_position:
+                                bytes: 45
+                                line: 2
+                                character: 20
+                              token_type:
+                                type: Symbol
+                                symbol: ":"
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 45
+                                  line: 2
+                                  character: 20
+                                end_position:
+                                  bytes: 46
+                                  line: 2
+                                  character: 21
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                          value:
+                            Basic:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 46
+                                  line: 2
+                                  character: 21
+                                end_position:
+                                  bytes: 52
+                                  line: 2
+                                  character: 27
+                                token_type:
+                                  type: Identifier
+                                  identifier: string
+                              trailing_trivia: []
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 52
+                              line: 2
+                              character: 27
+                            end_position:
+                              bytes: 53
+                              line: 2
+                              character: 28
+                            token_type:
+                              type: Symbol
+                              symbol: ","
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 53
+                                line: 2
+                                character: 28
+                              end_position:
+                                bytes: 54
+                                line: 2
+                                character: 29
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                    - End:
+                        key:
+                          Name:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 54
+                                line: 2
+                                character: 29
+                              end_position:
+                                bytes: 57
+                                line: 2
+                                character: 32
+                              token_type:
+                                type: Identifier
+                                identifier: Foo
+                            trailing_trivia: []
+                        colon:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 57
+                              line: 2
+                              character: 32
+                            end_position:
+                              bytes: 58
+                              line: 2
+                              character: 33
+                            token_type:
+                              type: Symbol
+                              symbol: ":"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 58
+                                line: 2
+                                character: 33
+                              end_position:
+                                bytes: 59
+                                line: 2
+                                character: 34
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                        value:
+                          Basic:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 59
+                                line: 2
+                                character: 34
+                              end_position:
+                                bytes: 65
+                                line: 2
+                                character: 40
+                              token_type:
+                                type: Identifier
+                                identifier: number
+                            trailing_trivia: []
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_nested_array/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_nested_array/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..a479e797e53add700159b98ed1896f98aa628e28
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_nested_array/source.lua
@@ -0,0 +1,2 @@
+type Foo = { { string } }
+type Foo = { {Name: string, Foo: number} }
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_nested_array/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_nested_array/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b7bc4f7a556b8cfbc93b1a8631d31392bed41352
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_nested_array/tokens.snap
@@ -0,0 +1,434 @@
+---
+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: 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: 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: 21
+    line: 1
+    character: 22
+  token_type:
+    type: Identifier
+    identifier: string
+- 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: 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: 26
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 26
+    line: 2
+    character: 1
+  end_position:
+    bytes: 30
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: type
+- start_position:
+    bytes: 30
+    line: 2
+    character: 5
+  end_position:
+    bytes: 31
+    line: 2
+    character: 6
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 31
+    line: 2
+    character: 6
+  end_position:
+    bytes: 34
+    line: 2
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: Foo
+- start_position:
+    bytes: 34
+    line: 2
+    character: 9
+  end_position:
+    bytes: 35
+    line: 2
+    character: 10
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 35
+    line: 2
+    character: 10
+  end_position:
+    bytes: 36
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 36
+    line: 2
+    character: 11
+  end_position:
+    bytes: 37
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- 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: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 39
+    line: 2
+    character: 14
+  end_position:
+    bytes: 40
+    line: 2
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 40
+    line: 2
+    character: 15
+  end_position:
+    bytes: 44
+    line: 2
+    character: 19
+  token_type:
+    type: Identifier
+    identifier: Name
+- start_position:
+    bytes: 44
+    line: 2
+    character: 19
+  end_position:
+    bytes: 45
+    line: 2
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 45
+    line: 2
+    character: 20
+  end_position:
+    bytes: 46
+    line: 2
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 46
+    line: 2
+    character: 21
+  end_position:
+    bytes: 52
+    line: 2
+    character: 27
+  token_type:
+    type: Identifier
+    identifier: string
+- start_position:
+    bytes: 52
+    line: 2
+    character: 27
+  end_position:
+    bytes: 53
+    line: 2
+    character: 28
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 53
+    line: 2
+    character: 28
+  end_position:
+    bytes: 54
+    line: 2
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 54
+    line: 2
+    character: 29
+  end_position:
+    bytes: 57
+    line: 2
+    character: 32
+  token_type:
+    type: Identifier
+    identifier: Foo
+- start_position:
+    bytes: 57
+    line: 2
+    character: 32
+  end_position:
+    bytes: 58
+    line: 2
+    character: 33
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 58
+    line: 2
+    character: 33
+  end_position:
+    bytes: 59
+    line: 2
+    character: 34
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 59
+    line: 2
+    character: 34
+  end_position:
+    bytes: 65
+    line: 2
+    character: 40
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 65
+    line: 2
+    character: 40
+  end_position:
+    bytes: 66
+    line: 2
+    character: 41
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 66
+    line: 2
+    character: 41
+  end_position:
+    bytes: 67
+    line: 2
+    character: 42
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 67
+    line: 2
+    character: 42
+  end_position:
+    bytes: 68
+    line: 2
+    character: 43
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 68
+    line: 2
+    character: 43
+  end_position:
+    bytes: 68
+    line: 2
+    character: 43
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_semicolon_delimeter/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_semicolon_delimeter/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..917421f1e862f78bd5833443b37b180ebe73dca8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_semicolon_delimeter/ast.snap
@@ -0,0 +1,321 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/roblox_cases/pass/types_semicolon_delimeter
+---
+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: " "
+        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: 13
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+                - leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 41
+                      line: 4
+                      character: 1
+                    end_position:
+                      bytes: 42
+                      line: 4
+                      character: 2
+                    token_type:
+                      type: Symbol
+                      symbol: "}"
+                  trailing_trivia: []
+            fields:
+              pairs:
+                - Punctuated:
+                    - key:
+                        Name:
+                          leading_trivia:
+                            - start_position:
+                                bytes: 13
+                                line: 2
+                                character: 1
+                              end_position:
+                                bytes: 14
+                                line: 2
+                                character: 2
+                              token_type:
+                                type: Whitespace
+                                characters: "\t"
+                          token:
+                            start_position:
+                              bytes: 14
+                              line: 2
+                              character: 2
+                            end_position:
+                              bytes: 17
+                              line: 2
+                              character: 5
+                            token_type:
+                              type: Identifier
+                              identifier: bar
+                          trailing_trivia: []
+                      colon:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 17
+                            line: 2
+                            character: 5
+                          end_position:
+                            bytes: 18
+                            line: 2
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: ":"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 18
+                              line: 2
+                              character: 6
+                            end_position:
+                              bytes: 19
+                              line: 2
+                              character: 7
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      value:
+                        Basic:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 19
+                              line: 2
+                              character: 7
+                            end_position:
+                              bytes: 25
+                              line: 2
+                              character: 13
+                            token_type:
+                              type: Identifier
+                              identifier: number
+                          trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 25
+                          line: 2
+                          character: 13
+                        end_position:
+                          bytes: 26
+                          line: 2
+                          character: 14
+                        token_type:
+                          type: Symbol
+                          symbol: ;
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 26
+                            line: 2
+                            character: 14
+                          end_position:
+                            bytes: 27
+                            line: 2
+                            character: 14
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+                - Punctuated:
+                    - key:
+                        Name:
+                          leading_trivia:
+                            - start_position:
+                                bytes: 27
+                                line: 3
+                                character: 1
+                              end_position:
+                                bytes: 28
+                                line: 3
+                                character: 2
+                              token_type:
+                                type: Whitespace
+                                characters: "\t"
+                          token:
+                            start_position:
+                              bytes: 28
+                              line: 3
+                              character: 2
+                            end_position:
+                              bytes: 31
+                              line: 3
+                              character: 5
+                            token_type:
+                              type: Identifier
+                              identifier: baz
+                          trailing_trivia: []
+                      colon:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 31
+                            line: 3
+                            character: 5
+                          end_position:
+                            bytes: 32
+                            line: 3
+                            character: 6
+                          token_type:
+                            type: Symbol
+                            symbol: ":"
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 32
+                              line: 3
+                              character: 6
+                            end_position:
+                              bytes: 33
+                              line: 3
+                              character: 7
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                      value:
+                        Basic:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 33
+                              line: 3
+                              character: 7
+                            end_position:
+                              bytes: 39
+                              line: 3
+                              character: 13
+                            token_type:
+                              type: Identifier
+                              identifier: number
+                          trailing_trivia: []
+                    - leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 39
+                          line: 3
+                          character: 13
+                        end_position:
+                          bytes: 40
+                          line: 3
+                          character: 14
+                        token_type:
+                          type: Symbol
+                          symbol: ;
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 40
+                            line: 3
+                            character: 14
+                          end_position:
+                            bytes: 41
+                            line: 3
+                            character: 14
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_semicolon_delimeter/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_semicolon_delimeter/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..48a69f27ab9278207c7ffcd6b22aa06d244ce4ea
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_semicolon_delimeter/source.lua
@@ -0,0 +1,4 @@
+type Foo = {
+	bar: number;
+	baz: number;
+}
\ No newline at end of file
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_semicolon_delimeter/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_semicolon_delimeter/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..38cffb0941ad3866e913597cdf2c00d382d99141
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/types_semicolon_delimeter/tokens.snap
@@ -0,0 +1,269 @@
+---
+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: 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: 13
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 13
+    line: 2
+    character: 1
+  end_position:
+    bytes: 14
+    line: 2
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 14
+    line: 2
+    character: 2
+  end_position:
+    bytes: 17
+    line: 2
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: bar
+- start_position:
+    bytes: 17
+    line: 2
+    character: 5
+  end_position:
+    bytes: 18
+    line: 2
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 18
+    line: 2
+    character: 6
+  end_position:
+    bytes: 19
+    line: 2
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 19
+    line: 2
+    character: 7
+  end_position:
+    bytes: 25
+    line: 2
+    character: 13
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 25
+    line: 2
+    character: 13
+  end_position:
+    bytes: 26
+    line: 2
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: ;
+- start_position:
+    bytes: 26
+    line: 2
+    character: 14
+  end_position:
+    bytes: 27
+    line: 2
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 27
+    line: 3
+    character: 1
+  end_position:
+    bytes: 28
+    line: 3
+    character: 2
+  token_type:
+    type: Whitespace
+    characters: "\t"
+- start_position:
+    bytes: 28
+    line: 3
+    character: 2
+  end_position:
+    bytes: 31
+    line: 3
+    character: 5
+  token_type:
+    type: Identifier
+    identifier: baz
+- start_position:
+    bytes: 31
+    line: 3
+    character: 5
+  end_position:
+    bytes: 32
+    line: 3
+    character: 6
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 32
+    line: 3
+    character: 6
+  end_position:
+    bytes: 33
+    line: 3
+    character: 7
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 33
+    line: 3
+    character: 7
+  end_position:
+    bytes: 39
+    line: 3
+    character: 13
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 39
+    line: 3
+    character: 13
+  end_position:
+    bytes: 40
+    line: 3
+    character: 14
+  token_type:
+    type: Symbol
+    symbol: ;
+- start_position:
+    bytes: 40
+    line: 3
+    character: 14
+  end_position:
+    bytes: 41
+    line: 3
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 41
+    line: 4
+    character: 1
+  end_position:
+    bytes: 42
+    line: 4
+    character: 2
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 42
+    line: 4
+    character: 2
+  end_position:
+    bytes: 42
+    line: 4
+    character: 2
+  token_type:
+    type: Eof
+
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/z-escape-string/ast.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/z-escape-string/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6f787e5d6218fcb681b9b92b600cd8a6ff9471a6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/z-escape-string/ast.snap
@@ -0,0 +1,181 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: ast.nodes()
+---
+stmts:
+  - - FunctionCall:
+        prefix:
+          Name:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 0
+                line: 1
+                character: 1
+              end_position:
+                bytes: 5
+                line: 1
+                character: 6
+              token_type:
+                type: Identifier
+                identifier: print
+            trailing_trivia: []
+        suffixes:
+          - Call:
+              AnonymousCall:
+                Parentheses:
+                  parentheses:
+                    tokens:
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 5
+                            line: 1
+                            character: 6
+                          end_position:
+                            bytes: 6
+                            line: 1
+                            character: 7
+                          token_type:
+                            type: Symbol
+                            symbol: (
+                        trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 29
+                            line: 2
+                            character: 12
+                          end_position:
+                            bytes: 30
+                            line: 2
+                            character: 13
+                          token_type:
+                            type: Symbol
+                            symbol: )
+                        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:
+                          String:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 6
+                                line: 1
+                                character: 7
+                              end_position:
+                                bytes: 29
+                                line: 2
+                                character: 12
+                              token_type:
+                                type: StringLiteral
+                                literal: "testing \\z\n\t   twelve"
+                                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/src/Rust/vvs_parser/src/tests/roblox_cases/pass/z-escape-string/source.lua b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/z-escape-string/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..3167d6c9333526ec55f3b7eda0195b0e88b0da28
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/z-escape-string/source.lua
@@ -0,0 +1,5 @@
+print("testing \z
+	   twelve")
+
+print("Hello \
+	World")
diff --git a/src/Rust/vvs_parser/src/tests/roblox_cases/pass/z-escape-string/tokens.snap b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/z-escape-string/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..42a20cf64cee1f2e8a24acafccd50735a10a2980
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/roblox_cases/pass/z-escape-string/tokens.snap
@@ -0,0 +1,138 @@
+---
+source: full-moon/tests/pass_cases.rs
+expression: tokens
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 5
+    line: 1
+    character: 6
+  token_type:
+    type: Identifier
+    identifier: print
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: (
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 29
+    line: 2
+    character: 12
+  token_type:
+    type: StringLiteral
+    literal: "testing \\z\n\t   twelve"
+    quote_type: Double
+- start_position:
+    bytes: 29
+    line: 2
+    character: 12
+  end_position:
+    bytes: 30
+    line: 2
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 30
+    line: 2
+    character: 13
+  end_position:
+    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
+
diff --git a/src/Rust/vvs_parser/src/tests/visitors.rs b/src/Rust/vvs_parser/src/tests/visitors.rs
new file mode 100644
index 0000000000000000000000000000000000000000..838b32ed17e568437aa2b2faf3030ea8cfa6714f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/visitors.rs
@@ -0,0 +1,164 @@
+use crate::{
+    ast,
+    prelude::parser::parse_lua_tree as parse,
+    tokenizer::*,
+    visitors::{Visitor, VisitorMut},
+};
+
+#[test]
+fn test_visitor() {
+    struct FunctionCallVisitor {
+        called: Vec<String>,
+    }
+
+    impl Visitor for FunctionCallVisitor {
+        fn visit_function_call(&mut self, call: &ast::FunctionCall) {
+            match call.prefix() {
+                ast::Prefix::Name(token) => {
+                    self.called.push(token.to_string());
+                }
+
+                _ => unreachable!(),
+            }
+        }
+    }
+
+    let code = parse("foo(bar())").unwrap();
+    let mut visitor = FunctionCallVisitor { called: Vec::new() };
+
+    visitor.visit_ast(&code);
+
+    assert_eq!(visitor.called, vec!["foo", "bar"]);
+}
+
+#[test]
+fn test_visitor_mut() {
+    struct SnakeNamer;
+
+    impl VisitorMut for SnakeNamer {
+        fn visit_local_assignment(&mut self, assignment: ast::LocalAssignment) -> ast::LocalAssignment {
+            let name_list = assignment
+                .names()
+                .pairs()
+                .map(|name| {
+                    name.to_owned().map(|value| {
+                        value.with_token(Token::new(TokenType::Identifier {
+                            identifier: value.token().to_string().replace('s', "sss").into(),
+                        }))
+                    })
+                })
+                .collect();
+
+            assignment.with_names(name_list)
+        }
+    }
+
+    let code = parse("local dogs, snakes = 1").unwrap();
+    let code = SnakeNamer.visit_ast(code);
+    assert_eq!(format!("{code}"), "local dogsss, sssnakesss = 1");
+
+    struct PositionValidator;
+
+    impl Visitor for PositionValidator {
+        fn visit_local_assignment(&mut self, assignment: &ast::LocalAssignment) {
+            for name in assignment.names() {
+                assert_eq!(name.end_position().bytes() - name.start_position().bytes(), name.token().to_string().len());
+            }
+        }
+    }
+
+    let code = code.update_positions();
+    PositionValidator.visit_ast(&code);
+}
+
+#[test]
+fn test_visit_token() {
+    #[derive(Default)]
+    struct CommentVisitor {
+        comments: Vec<String>,
+    }
+
+    impl Visitor for CommentVisitor {
+        fn visit_single_line_comment(&mut self, token: &Token) {
+            self.comments.push(token.to_string());
+        }
+    }
+
+    let mut visitor = CommentVisitor::default();
+
+    let code = parse(
+        r#"
+    -- bla bla bla
+    --[[
+        multi line comment
+    ]]
+
+    -- comment here
+    local x = 1
+    -- and here
+    "#,
+    )
+    .unwrap();
+
+    visitor.visit_ast(&code);
+    assert_eq!(visitor.comments, vec!["-- bla bla bla", "-- comment here", "-- and here"]);
+}
+
+#[test]
+fn test_end_visit() {
+    #[derive(Default)]
+    struct LogVisitor {
+        instructions: usize,
+        if_start_at: usize,
+        if_end_at: usize,
+        called_at: usize,
+    }
+
+    impl Visitor for LogVisitor {
+        fn visit_if(&mut self, _: &ast::If) {
+            self.instructions += 1;
+            self.if_start_at = self.instructions
+        }
+
+        fn visit_if_end(&mut self, _: &ast::If) {
+            self.instructions += 1;
+            self.if_end_at = self.instructions;
+        }
+
+        fn visit_call(&mut self, _: &ast::Call) {
+            self.instructions += 1;
+            self.called_at = self.instructions;
+        }
+    }
+
+    let mut visitor = LogVisitor::default();
+    visitor.visit_ast(
+        &parse(
+            r#"
+    if true then
+        call()
+    end
+    "#,
+        )
+        .unwrap(),
+    );
+
+    assert_eq!(visitor.if_start_at, 1);
+    assert_eq!(visitor.called_at, 2);
+    assert_eq!(visitor.if_end_at, 3);
+}
+
+#[test]
+fn test_unary_visitor_regression() {
+    struct TestVisitor(bool);
+
+    impl Visitor for TestVisitor {
+        fn visit_un_op(&mut self, _: &ast::UnOp) {
+            self.0 = true;
+        }
+    }
+
+    let mut visitor = TestVisitor(false);
+    visitor.visit_ast(&parse("local x = #{}").unwrap());
+    assert!(visitor.0, "Unary operation was not visited");
+}
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f1086135d4e9d45e1c919bc53ca1b46c3cc56073
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/ast.snap
@@ -0,0 +1,21 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.ast()
+input_file: vvs_parser/tests/vivy_cases/fail/parser/job
+---
+nodes:
+  stmts: []
+eof:
+  leading_trivia: []
+  token:
+    start_position:
+      bytes: 14
+      line: 2
+      character: 1
+    end_position:
+      bytes: 14
+      line: 2
+      character: 1
+    token_type:
+      type: Eof
+  trailing_trivia: []
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d95027ad42ce250ec1dcb4cd99f2a6d06807bf80
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/ast_to_string.snap
@@ -0,0 +1,6 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: "vvs_parser::print(&ast)"
+input_file: vvs_parser/tests/vivy_cases/fail/parser/job
+---
+""
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/error_display.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a5166952a242cb194fc6458b65f748555408dad7
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/error_display.snap
@@ -0,0 +1,10 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: "String::from_utf8(output.into_inner()).unwrap()"
+input_file: vvs_parser/tests/vivy_cases/fail/parser/job
+---
+error[ast]: invalid name for a job, can't be ponctuated or have columns
+  ┌─ source.lua:1:1
+  │
+1 │ job x.y() end
+  │ ^^^
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/errors.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f04aec5a1a412075239264bb8d938cdbdb3b2cfe
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/errors.snap
@@ -0,0 +1,19 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.errors()
+input_file: vvs_parser/tests/vivy_cases/fail/parser/job
+---
+- AstError:
+    token:
+      start_position:
+        bytes: 0
+        line: 1
+        character: 1
+      end_position:
+        bytes: 3
+        line: 1
+        character: 4
+      token_type:
+        type: Symbol
+        symbol: job
+    additional: "invalid name for a job, can't be ponctuated or have columns"
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..618768b8006870fc5c3aafb364fd3d2cb0282664
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/source.lua
@@ -0,0 +1 @@
+job x.y() end
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..77d1ec72232e8ad6a0838f56f037d9eaa2b75f25
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/job/tokens.snap
@@ -0,0 +1,125 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/fail/parser/job
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: job
+- 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: Identifier
+    identifier: x
+- start_position:
+    bytes: 5
+    line: 1
+    character: 6
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Identifier
+    identifier: y
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Symbol
+    symbol: (
+- 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: Symbol
+    symbol: end
+- 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: 14
+    line: 2
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..cdf8616bcaedc29ebcb8a6f8f87645dc0809e29d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/ast.snap
@@ -0,0 +1,169 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.ast()
+input_file: vvs_parser/tests/vivy_cases/fail/parser/main_after_returns
+---
+nodes:
+  stmts:
+    - - FunctionCall:
+          prefix:
+            Name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 51
+                  line: 3
+                  character: 19
+                end_position:
+                  bytes: 52
+                  line: 3
+                  character: 20
+                token_type:
+                  type: Identifier
+                  identifier: a
+              trailing_trivia: []
+          suffixes:
+            - Index:
+                Dot:
+                  dot:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 52
+                        line: 3
+                        character: 20
+                      end_position:
+                        bytes: 53
+                        line: 3
+                        character: 21
+                      token_type:
+                        type: Symbol
+                        symbol: "."
+                    trailing_trivia: []
+                  name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 53
+                        line: 3
+                        character: 21
+                      end_position:
+                        bytes: 54
+                        line: 3
+                        character: 22
+                      token_type:
+                        type: Identifier
+                        identifier: b
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 54
+                          line: 3
+                          character: 22
+                        end_position:
+                          bytes: 55
+                          line: 3
+                          character: 23
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+            - Call:
+                AnonymousCall:
+                  TableConstructor:
+                    braces:
+                      tokens:
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 55
+                              line: 3
+                              character: 23
+                            end_position:
+                              bytes: 56
+                              line: 3
+                              character: 24
+                            token_type:
+                              type: Symbol
+                              symbol: "{"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 56
+                                line: 3
+                                character: 24
+                              end_position:
+                                bytes: 57
+                                line: 3
+                                character: 25
+                              token_type:
+                                type: Whitespace
+                                characters: " "
+                        - leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 64
+                              line: 3
+                              character: 32
+                            end_position:
+                              bytes: 65
+                              line: 3
+                              character: 33
+                            token_type:
+                              type: Symbol
+                              symbol: "}"
+                          trailing_trivia:
+                            - start_position:
+                                bytes: 65
+                                line: 3
+                                character: 33
+                              end_position:
+                                bytes: 66
+                                line: 3
+                                character: 33
+                              token_type:
+                                type: Whitespace
+                                characters: "\n"
+                    fields:
+                      pairs:
+                        - End:
+                            NoKey:
+                              String:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 57
+                                    line: 3
+                                    character: 25
+                                  end_position:
+                                    bytes: 63
+                                    line: 3
+                                    character: 31
+                                  token_type:
+                                    type: StringLiteral
+                                    literal: init
+                                    quote_type: Double
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 63
+                                      line: 3
+                                      character: 31
+                                    end_position:
+                                      bytes: 64
+                                      line: 3
+                                      character: 32
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+      - ~
+eof:
+  leading_trivia: []
+  token:
+    start_position:
+      bytes: 70
+      line: 5
+      character: 1
+    end_position:
+      bytes: 70
+      line: 5
+      character: 1
+    token_type:
+      type: Eof
+  trailing_trivia: []
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..d7ff39c53eb6fbffec6cd5259c867911b71c13d5
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/ast_to_string.snap
@@ -0,0 +1,6 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: "vvs_parser::print(&ast)"
+input_file: vvs_parser/tests/vivy_cases/fail/parser/main_after_returns
+---
+"a.b { \"init\" }\n"
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/error_display.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9dadcef5ce6a82a34056b5a5dd89377aa9053fcb
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/error_display.snap
@@ -0,0 +1,16 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: "String::from_utf8(output.into_inner()).unwrap()"
+input_file: vvs_parser/tests/vivy_cases/fail/parser/main_after_returns
+---
+error[ast]: expected no more assignations after the return token
+  ┌─ source.lua:3:5
+  │
+3 │     "something" = a.b { "init" }
+  │     ^^^^^^^^^^^
+
+error[ast]: unexpected token, this needs to be a statement
+  ┌─ source.lua:3:5
+  │
+3 │     "something" = a.b { "init" }
+  │     ^^^^^^^^^^^
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/errors.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..233876e129c4cee008c864a9f23c18675f4187b1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/errors.snap
@@ -0,0 +1,35 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.errors()
+input_file: vvs_parser/tests/vivy_cases/fail/parser/main_after_returns
+---
+- AstError:
+    token:
+      start_position:
+        bytes: 37
+        line: 3
+        character: 5
+      end_position:
+        bytes: 48
+        line: 3
+        character: 16
+      token_type:
+        type: StringLiteral
+        literal: something
+        quote_type: Double
+    additional: expected no more assignations after the return token
+- AstError:
+    token:
+      start_position:
+        bytes: 37
+        line: 3
+        character: 5
+      end_position:
+        bytes: 48
+        line: 3
+        character: 16
+      token_type:
+        type: StringLiteral
+        literal: something
+        quote_type: Double
+    additional: "unexpected token, this needs to be a statement"
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..d72b488f6be48637f8b769bc6f31c99a27d0d249
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/source.lua
@@ -0,0 +1,4 @@
+main "init" do
+    return "init"
+    "something" = a.b { "init" }
+end
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ab44c98cd0aaea593eb5caa1fc20d6c7394c1f28
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/main_after_returns/tokens.snap
@@ -0,0 +1,327 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/fail/parser/main_after_returns
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: main
+- 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: StringLiteral
+    literal: init
+    quote_type: Double
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 14
+    line: 1
+    character: 15
+  end_position:
+    bytes: 15
+    line: 1
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 2
+    character: 1
+  end_position:
+    bytes: 19
+    line: 2
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 19
+    line: 2
+    character: 5
+  end_position:
+    bytes: 25
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 25
+    line: 2
+    character: 11
+  end_position:
+    bytes: 26
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 26
+    line: 2
+    character: 12
+  end_position:
+    bytes: 32
+    line: 2
+    character: 18
+  token_type:
+    type: StringLiteral
+    literal: init
+    quote_type: Double
+- start_position:
+    bytes: 32
+    line: 2
+    character: 18
+  end_position:
+    bytes: 33
+    line: 2
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 33
+    line: 3
+    character: 1
+  end_position:
+    bytes: 37
+    line: 3
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 37
+    line: 3
+    character: 5
+  end_position:
+    bytes: 48
+    line: 3
+    character: 16
+  token_type:
+    type: StringLiteral
+    literal: something
+    quote_type: Double
+- start_position:
+    bytes: 48
+    line: 3
+    character: 16
+  end_position:
+    bytes: 49
+    line: 3
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 49
+    line: 3
+    character: 17
+  end_position:
+    bytes: 50
+    line: 3
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 50
+    line: 3
+    character: 18
+  end_position:
+    bytes: 51
+    line: 3
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 51
+    line: 3
+    character: 19
+  end_position:
+    bytes: 52
+    line: 3
+    character: 20
+  token_type:
+    type: Identifier
+    identifier: a
+- start_position:
+    bytes: 52
+    line: 3
+    character: 20
+  end_position:
+    bytes: 53
+    line: 3
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 53
+    line: 3
+    character: 21
+  end_position:
+    bytes: 54
+    line: 3
+    character: 22
+  token_type:
+    type: Identifier
+    identifier: b
+- start_position:
+    bytes: 54
+    line: 3
+    character: 22
+  end_position:
+    bytes: 55
+    line: 3
+    character: 23
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 55
+    line: 3
+    character: 23
+  end_position:
+    bytes: 56
+    line: 3
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 56
+    line: 3
+    character: 24
+  end_position:
+    bytes: 57
+    line: 3
+    character: 25
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 57
+    line: 3
+    character: 25
+  end_position:
+    bytes: 63
+    line: 3
+    character: 31
+  token_type:
+    type: StringLiteral
+    literal: init
+    quote_type: Double
+- start_position:
+    bytes: 63
+    line: 3
+    character: 31
+  end_position:
+    bytes: 64
+    line: 3
+    character: 32
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 64
+    line: 3
+    character: 32
+  end_position:
+    bytes: 65
+    line: 3
+    character: 33
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 65
+    line: 3
+    character: 33
+  end_position:
+    bytes: 66
+    line: 3
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 66
+    line: 4
+    character: 1
+  end_position:
+    bytes: 69
+    line: 4
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 69
+    line: 4
+    character: 4
+  end_position:
+    bytes: 70
+    line: 4
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 70
+    line: 5
+    character: 1
+  end_position:
+    bytes: 70
+    line: 5
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..68fa43d1e982816f2d9bc85055a591d860afd670
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/ast.snap
@@ -0,0 +1,21 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.ast()
+input_file: vvs_parser/tests/vivy_cases/fail/parser/option_decl_1
+---
+nodes:
+  stmts: []
+eof:
+  leading_trivia: []
+  token:
+    start_position:
+      bytes: 9
+      line: 2
+      character: 1
+    end_position:
+      bytes: 9
+      line: 2
+      character: 1
+    token_type:
+      type: Eof
+  trailing_trivia: []
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c603e68ae8b3d78b634081221bd40a91263aab4f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/ast_to_string.snap
@@ -0,0 +1,6 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: "vvs_parser::print(&ast)"
+input_file: vvs_parser/tests/vivy_cases/fail/parser/option_decl_1
+---
+""
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/error_display.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..983823754580b575a18991836b4fbd1b3220ea02
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/error_display.snap
@@ -0,0 +1,16 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: "String::from_utf8(output.into_inner()).unwrap()"
+input_file: vvs_parser/tests/vivy_cases/fail/parser/option_decl_1
+---
+error[ast]: invalid option specifier statement
+  ┌─ source.lua:1:1
+  │
+1 │ option a
+  │ ^^^^^^
+
+error[ast]: expected ',' to continue option list or '=' to assign default values to the list
+  ┌─ source.lua:2:1
+  │
+2 │ 
+  │ ^
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/errors.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4f6ddb4e9a028e325883b4569eed848752ad7456
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/errors.snap
@@ -0,0 +1,32 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.errors()
+input_file: vvs_parser/tests/vivy_cases/fail/parser/option_decl_1
+---
+- AstError:
+    token:
+      start_position:
+        bytes: 0
+        line: 1
+        character: 1
+      end_position:
+        bytes: 6
+        line: 1
+        character: 7
+      token_type:
+        type: Symbol
+        symbol: option
+    additional: invalid option specifier statement
+- AstError:
+    token:
+      start_position:
+        bytes: 9
+        line: 2
+        character: 1
+      end_position:
+        bytes: 9
+        line: 2
+        character: 1
+      token_type:
+        type: Eof
+    additional: "expected ',' to continue option list or '=' to assign default values to the list"
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..b90250c6f4a9e1ce67f43474f369adbb98c71dd6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/source.lua
@@ -0,0 +1 @@
+option a
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..9f7d957ad9d48109feb7a1d5bf6b164b0b8ce467
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_1/tokens.snap
@@ -0,0 +1,59 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/fail/parser/option_decl_1
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: option
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 8
+    line: 1
+    character: 9
+  token_type:
+    type: Identifier
+    identifier: a
+- 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/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..059a13e8d80614a7e00a577437e1a6a9380f9174
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/ast.snap
@@ -0,0 +1,107 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.ast()
+input_file: vvs_parser/tests/vivy_cases/fail/parser/option_decl_2
+---
+nodes:
+  stmts:
+    - - Assignment:
+          var_list:
+            pairs:
+              - End:
+                  Name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 12
+                        line: 1
+                        character: 13
+                      end_position:
+                        bytes: 16
+                        line: 1
+                        character: 17
+                      token_type:
+                        type: Identifier
+                        identifier: tata
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 16
+                          line: 1
+                          character: 17
+                        end_position:
+                          bytes: 17
+                          line: 1
+                          character: 18
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+          equal_token:
+            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: " "
+          expr_list:
+            pairs:
+              - End:
+                  Number:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 19
+                        line: 1
+                        character: 20
+                      end_position:
+                        bytes: 20
+                        line: 1
+                        character: 21
+                      token_type:
+                        type: Number
+                        text: "1"
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 20
+                          line: 1
+                          character: 21
+                        end_position:
+                          bytes: 21
+                          line: 1
+                          character: 21
+                        token_type:
+                          type: Whitespace
+                          characters: "\n"
+      - ~
+eof:
+  leading_trivia: []
+  token:
+    start_position:
+      bytes: 21
+      line: 2
+      character: 1
+    end_position:
+      bytes: 21
+      line: 2
+      character: 1
+    token_type:
+      type: Eof
+  trailing_trivia: []
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/ast_to_string.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/ast_to_string.snap
new file mode 100644
index 0000000000000000000000000000000000000000..ee6801e9f16c0f477b9b7cd2e73013f3324f5fbc
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/ast_to_string.snap
@@ -0,0 +1,6 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: "vvs_parser::print(&ast)"
+input_file: vvs_parser/tests/vivy_cases/fail/parser/option_decl_2
+---
+"tata = 1\n"
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/error_display.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/error_display.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8765e4ba769e1f84a2c15ed4880238d2c5ac5219
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/error_display.snap
@@ -0,0 +1,22 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: "String::from_utf8(output.into_inner()).unwrap()"
+input_file: vvs_parser/tests/vivy_cases/fail/parser/option_decl_2
+---
+error[ast]: invalid option specifier statement
+  ┌─ source.lua:1:1
+  │
+1 │ option toto.tata = 1
+  │ ^^^^^^
+
+error[ast]: expected ',' to continue option list or '=' to assign default values to the list
+  ┌─ source.lua:1:12
+  │
+1 │ option toto.tata = 1
+  │            ^
+
+error[ast]: unexpected token, this needs to be a statement
+  ┌─ source.lua:1:12
+  │
+1 │ option toto.tata = 1
+  │            ^
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/errors.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/errors.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3ebe248192601c14e8dc9e5fce4cc946398c07f8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/errors.snap
@@ -0,0 +1,47 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: result.errors()
+input_file: vvs_parser/tests/vivy_cases/fail/parser/option_decl_2
+---
+- AstError:
+    token:
+      start_position:
+        bytes: 0
+        line: 1
+        character: 1
+      end_position:
+        bytes: 6
+        line: 1
+        character: 7
+      token_type:
+        type: Symbol
+        symbol: option
+    additional: invalid option specifier statement
+- 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 ',' to continue option list or '=' to assign default values to the list"
+- AstError:
+    token:
+      start_position:
+        bytes: 11
+        line: 1
+        character: 12
+      end_position:
+        bytes: 12
+        line: 1
+        character: 13
+      token_type:
+        type: Symbol
+        symbol: "."
+    additional: "unexpected token, this needs to be a statement"
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..eb3a72dca8c25a38d7f83903b47d05eeed0279b1
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/source.lua
@@ -0,0 +1 @@
+option toto.tata = 1
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f9281e8190f0846377036a93a5602249e991e55a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/fail/parser/option_decl_2/tokens.snap
@@ -0,0 +1,125 @@
+---
+source: vvs_parser/tests/fail_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/fail/parser/option_decl_2
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: option
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: toto
+- 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: tata
+- 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: 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: 20
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 20
+    line: 1
+    character: 21
+  end_position:
+    bytes: 21
+    line: 1
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 21
+    line: 2
+    character: 1
+  end_position:
+    bytes: 21
+    line: 2
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/import/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/import/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..c225f36eff95091e670323edc7da1cf8aeb68490
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/import/ast.snap
@@ -0,0 +1,62 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+assertion_line: 44
+expression: ast.nodes()
+input_file: vvs_parser/tests/vivy/pass/import
+---
+stmts:
+  - - Import:
+        import_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: import
+          trailing_trivia:
+            - start_position:
+                bytes: 6
+                line: 1
+                character: 7
+              end_position:
+                bytes: 7
+                line: 1
+                character: 8
+              token_type:
+                type: Whitespace
+                characters: " "
+        name:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 7
+              line: 1
+              character: 8
+            end_position:
+              bytes: 13
+              line: 1
+              character: 14
+            token_type:
+              type: StringLiteral
+              literal: math
+              quote_type: Double
+          trailing_trivia:
+            - start_position:
+                bytes: 13
+                line: 1
+                character: 14
+              end_position:
+                bytes: 14
+                line: 1
+                character: 14
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/import/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/import/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..468fc97f46b605683e4c67a8a63e46d1b757433f
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/import/source.lua
@@ -0,0 +1 @@
+import "math"
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/import/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/import/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..f029aafc12f0ed7790219b33ceab7e88d97e1217
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/import/tokens.snap
@@ -0,0 +1,60 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy/pass/import
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: import
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 13
+    line: 1
+    character: 14
+  token_type:
+    type: StringLiteral
+    literal: math
+    quote_type: Double
+- 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: 14
+    line: 2
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..2138fc2774ab75bc6b13f09d2d5d7b5fc6a17295
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job/ast.snap
@@ -0,0 +1,126 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/vivy_cases/pass/job
+---
+stmts:
+  - - JobDeclaration:
+        function_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: job
+          trailing_trivia:
+            - start_position:
+                bytes: 3
+                line: 1
+                character: 4
+              end_position:
+                bytes: 4
+                line: 1
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        name:
+          names:
+            pairs:
+              - End:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 4
+                      line: 1
+                      character: 5
+                    end_position:
+                      bytes: 10
+                      line: 1
+                      character: 11
+                    token_type:
+                      type: Identifier
+                      identifier: retime
+                  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:
+                  - start_position:
+                      bytes: 12
+                      line: 1
+                      character: 13
+                    end_position:
+                      bytes: 13
+                      line: 1
+                      character: 14
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+          parameters:
+            pairs: []
+          type_specifiers: []
+          block:
+            stmts: []
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 13
+                line: 1
+                character: 14
+              end_position:
+                bytes: 16
+                line: 1
+                character: 17
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia:
+              - start_position:
+                  bytes: 16
+                  line: 1
+                  character: 17
+                end_position:
+                  bytes: 17
+                  line: 1
+                  character: 17
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..34231ae6d00a2995bdae3be7873940e9a634890d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job/source.lua
@@ -0,0 +1 @@
+job retime() end
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8ee54e754994e7f9f35d2fc2208e050c9743a66d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job/tokens.snap
@@ -0,0 +1,103 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy/pass/job
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: job
+- 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: Identifier
+    identifier: retime
+- 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: 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: 16
+    line: 1
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 16
+    line: 1
+    character: 17
+  end_position:
+    bytes: 17
+    line: 1
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 17
+    line: 2
+    character: 1
+  end_position:
+    bytes: 17
+    line: 2
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job_yield/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job_yield/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..b629273e5e221649e3280526cbe191c6e52d7812
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job_yield/ast.snap
@@ -0,0 +1,963 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/vivy_cases/pass/job_yield
+---
+stmts:
+  - - JobDeclaration:
+        function_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: job
+          trailing_trivia:
+            - start_position:
+                bytes: 3
+                line: 1
+                character: 4
+              end_position:
+                bytes: 4
+                line: 1
+                character: 5
+              token_type:
+                type: Whitespace
+                characters: " "
+        name:
+          names:
+            pairs:
+              - End:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 4
+                      line: 1
+                      character: 5
+                    end_position:
+                      bytes: 14
+                      line: 1
+                      character: 15
+                    token_type:
+                      type: Identifier
+                      identifier: syl_modulo
+                  trailing_trivia: []
+          colon_name: ~
+        body:
+          parameters_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: 51
+                    line: 1
+                    character: 52
+                  end_position:
+                    bytes: 52
+                    line: 1
+                    character: 53
+                  token_type:
+                    type: Symbol
+                    symbol: )
+                trailing_trivia: []
+          parameters:
+            pairs:
+              - Punctuated:
+                  - name:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 15
+                          line: 1
+                          character: 16
+                        end_position:
+                          bytes: 20
+                          line: 1
+                          character: 21
+                        token_type:
+                          type: Identifier
+                          identifier: every
+                      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: " "
+              - Punctuated:
+                  - name:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 30
+                          line: 1
+                          character: 31
+                        end_position:
+                          bytes: 34
+                          line: 1
+                          character: 35
+                        token_type:
+                          type: Identifier
+                          identifier: disp
+                      trailing_trivia: []
+                  - leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 42
+                        line: 1
+                        character: 43
+                      end_position:
+                        bytes: 43
+                        line: 1
+                        character: 44
+                      token_type:
+                        type: Symbol
+                        symbol: ","
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 43
+                          line: 1
+                          character: 44
+                        end_position:
+                          bytes: 44
+                          line: 1
+                          character: 45
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+              - End:
+                  name:
+                    leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 44
+                        line: 1
+                        character: 45
+                      end_position:
+                        bytes: 45
+                        line: 1
+                        character: 46
+                      token_type:
+                        type: Identifier
+                        identifier: l
+                    trailing_trivia: []
+          type_specifiers:
+            - punctuation:
+                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: " "
+              type_info:
+                Basic:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 22
+                      line: 1
+                      character: 23
+                    end_position:
+                      bytes: 28
+                      line: 1
+                      character: 29
+                    token_type:
+                      type: Identifier
+                      identifier: number
+                  trailing_trivia: []
+            - punctuation:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 34
+                    line: 1
+                    character: 35
+                  end_position:
+                    bytes: 35
+                    line: 1
+                    character: 36
+                  token_type:
+                    type: Symbol
+                    symbol: ":"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 35
+                      line: 1
+                      character: 36
+                    end_position:
+                      bytes: 36
+                      line: 1
+                      character: 37
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              type_info:
+                Basic:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 36
+                      line: 1
+                      character: 37
+                    end_position:
+                      bytes: 42
+                      line: 1
+                      character: 43
+                    token_type:
+                      type: Identifier
+                      identifier: number
+                  trailing_trivia: []
+            - punctuation:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 45
+                    line: 1
+                    character: 46
+                  end_position:
+                    bytes: 46
+                    line: 1
+                    character: 47
+                  token_type:
+                    type: Symbol
+                    symbol: ":"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 46
+                      line: 1
+                      character: 47
+                    end_position:
+                      bytes: 47
+                      line: 1
+                      character: 48
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              type_info:
+                Basic:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 47
+                      line: 1
+                      character: 48
+                    end_position:
+                      bytes: 51
+                      line: 1
+                      character: 52
+                    token_type:
+                      type: Identifier
+                      identifier: line
+                  trailing_trivia: []
+          return_type:
+            punctuation:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 52
+                  line: 1
+                  character: 53
+                end_position:
+                  bytes: 53
+                  line: 1
+                  character: 54
+                token_type:
+                  type: Symbol
+                  symbol: ":"
+              trailing_trivia:
+                - start_position:
+                    bytes: 53
+                    line: 1
+                    character: 54
+                  end_position:
+                    bytes: 54
+                    line: 1
+                    character: 55
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            type_info:
+              Basic:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 54
+                    line: 1
+                    character: 55
+                  end_position:
+                    bytes: 58
+                    line: 1
+                    character: 59
+                  token_type:
+                    type: Identifier
+                    identifier: line
+                trailing_trivia:
+                  - start_position:
+                      bytes: 58
+                      line: 1
+                      character: 59
+                    end_position:
+                      bytes: 59
+                      line: 1
+                      character: 59
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+          block:
+            stmts:
+              - - GenericFor:
+                    for_token:
+                      leading_trivia:
+                        - start_position:
+                            bytes: 59
+                            line: 2
+                            character: 1
+                          end_position:
+                            bytes: 63
+                            line: 2
+                            character: 5
+                          token_type:
+                            type: Whitespace
+                            characters: "    "
+                      token:
+                        start_position:
+                          bytes: 63
+                          line: 2
+                          character: 5
+                        end_position:
+                          bytes: 66
+                          line: 2
+                          character: 8
+                        token_type:
+                          type: Symbol
+                          symbol: for
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 66
+                            line: 2
+                            character: 8
+                          end_position:
+                            bytes: 67
+                            line: 2
+                            character: 9
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                    names:
+                      pairs:
+                        - Punctuated:
+                            - leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 67
+                                  line: 2
+                                  character: 9
+                                end_position:
+                                  bytes: 68
+                                  line: 2
+                                  character: 10
+                                token_type:
+                                  type: Identifier
+                                  identifier: i
+                              trailing_trivia: []
+                            - leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 68
+                                  line: 2
+                                  character: 10
+                                end_position:
+                                  bytes: 69
+                                  line: 2
+                                  character: 11
+                                token_type:
+                                  type: Symbol
+                                  symbol: ","
+                              trailing_trivia: []
+                        - End:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 69
+                                line: 2
+                                character: 11
+                              end_position:
+                                bytes: 70
+                                line: 2
+                                character: 12
+                              token_type:
+                                type: Identifier
+                                identifier: s
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 70
+                                  line: 2
+                                  character: 12
+                                end_position:
+                                  bytes: 71
+                                  line: 2
+                                  character: 13
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                    in_token:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 71
+                          line: 2
+                          character: 13
+                        end_position:
+                          bytes: 73
+                          line: 2
+                          character: 15
+                        token_type:
+                          type: Symbol
+                          symbol: in
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 73
+                            line: 2
+                            character: 15
+                          end_position:
+                            bytes: 74
+                            line: 2
+                            character: 16
+                          token_type:
+                            type: Whitespace
+                            characters: " "
+                    expr_list:
+                      pairs:
+                        - End:
+                            Var:
+                              Name:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 74
+                                    line: 2
+                                    character: 16
+                                  end_position:
+                                    bytes: 75
+                                    line: 2
+                                    character: 17
+                                  token_type:
+                                    type: Identifier
+                                    identifier: l
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 75
+                                      line: 2
+                                      character: 17
+                                    end_position:
+                                      bytes: 76
+                                      line: 2
+                                      character: 18
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                    do_token:
+                      leading_trivia: []
+                      token:
+                        start_position:
+                          bytes: 76
+                          line: 2
+                          character: 18
+                        end_position:
+                          bytes: 78
+                          line: 2
+                          character: 20
+                        token_type:
+                          type: Symbol
+                          symbol: do
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 78
+                            line: 2
+                            character: 20
+                          end_position:
+                            bytes: 79
+                            line: 2
+                            character: 20
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+                    block:
+                      stmts:
+                        - - If:
+                              if_token:
+                                leading_trivia:
+                                  - start_position:
+                                      bytes: 79
+                                      line: 3
+                                      character: 1
+                                    end_position:
+                                      bytes: 87
+                                      line: 3
+                                      character: 9
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "        "
+                                token:
+                                  start_position:
+                                    bytes: 87
+                                    line: 3
+                                    character: 9
+                                  end_position:
+                                    bytes: 89
+                                    line: 3
+                                    character: 11
+                                  token_type:
+                                    type: Symbol
+                                    symbol: if
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 89
+                                      line: 3
+                                      character: 11
+                                    end_position:
+                                      bytes: 90
+                                      line: 3
+                                      character: 12
+                                    token_type:
+                                      type: Whitespace
+                                      characters: " "
+                              condition:
+                                BinaryOperator:
+                                  lhs:
+                                    Parentheses:
+                                      contained:
+                                        tokens:
+                                          - 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: []
+                                          - 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:
+                                              - start_position:
+                                                  bytes: 101
+                                                  line: 3
+                                                  character: 23
+                                                end_position:
+                                                  bytes: 102
+                                                  line: 3
+                                                  character: 24
+                                                token_type:
+                                                  type: Whitespace
+                                                  characters: " "
+                                      expression:
+                                        BinaryOperator:
+                                          lhs:
+                                            Var:
+                                              Name:
+                                                leading_trivia: []
+                                                token:
+                                                  start_position:
+                                                    bytes: 91
+                                                    line: 3
+                                                    character: 13
+                                                  end_position:
+                                                    bytes: 92
+                                                    line: 3
+                                                    character: 14
+                                                  token_type:
+                                                    type: Identifier
+                                                    identifier: i
+                                                trailing_trivia:
+                                                  - start_position:
+                                                      bytes: 92
+                                                      line: 3
+                                                      character: 14
+                                                    end_position:
+                                                      bytes: 93
+                                                      line: 3
+                                                      character: 15
+                                                    token_type:
+                                                      type: Whitespace
+                                                      characters: " "
+                                          binop:
+                                            Percent:
+                                              leading_trivia: []
+                                              token:
+                                                start_position:
+                                                  bytes: 93
+                                                  line: 3
+                                                  character: 15
+                                                end_position:
+                                                  bytes: 94
+                                                  line: 3
+                                                  character: 16
+                                                token_type:
+                                                  type: Symbol
+                                                  symbol: "%"
+                                              trailing_trivia:
+                                                - start_position:
+                                                    bytes: 94
+                                                    line: 3
+                                                    character: 16
+                                                  end_position:
+                                                    bytes: 95
+                                                    line: 3
+                                                    character: 17
+                                                  token_type:
+                                                    type: Whitespace
+                                                    characters: " "
+                                          rhs:
+                                            Var:
+                                              Name:
+                                                leading_trivia: []
+                                                token:
+                                                  start_position:
+                                                    bytes: 95
+                                                    line: 3
+                                                    character: 17
+                                                  end_position:
+                                                    bytes: 100
+                                                    line: 3
+                                                    character: 22
+                                                  token_type:
+                                                    type: Identifier
+                                                    identifier: every
+                                                trailing_trivia: []
+                                  binop:
+                                    TwoEqual:
+                                      leading_trivia: []
+                                      token:
+                                        start_position:
+                                          bytes: 102
+                                          line: 3
+                                          character: 24
+                                        end_position:
+                                          bytes: 104
+                                          line: 3
+                                          character: 26
+                                        token_type:
+                                          type: Symbol
+                                          symbol: "=="
+                                      trailing_trivia:
+                                        - start_position:
+                                            bytes: 104
+                                            line: 3
+                                            character: 26
+                                          end_position:
+                                            bytes: 105
+                                            line: 3
+                                            character: 27
+                                          token_type:
+                                            type: Whitespace
+                                            characters: " "
+                                  rhs:
+                                    Var:
+                                      Name:
+                                        leading_trivia: []
+                                        token:
+                                          start_position:
+                                            bytes: 105
+                                            line: 3
+                                            character: 27
+                                          end_position:
+                                            bytes: 109
+                                            line: 3
+                                            character: 31
+                                          token_type:
+                                            type: Identifier
+                                            identifier: disp
+                                        trailing_trivia:
+                                          - start_position:
+                                              bytes: 109
+                                              line: 3
+                                              character: 31
+                                            end_position:
+                                              bytes: 110
+                                              line: 3
+                                              character: 32
+                                            token_type:
+                                              type: Whitespace
+                                              characters: " "
+                              then_token:
+                                leading_trivia: []
+                                token:
+                                  start_position:
+                                    bytes: 110
+                                    line: 3
+                                    character: 32
+                                  end_position:
+                                    bytes: 114
+                                    line: 3
+                                    character: 36
+                                  token_type:
+                                    type: Symbol
+                                    symbol: then
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 114
+                                      line: 3
+                                      character: 36
+                                    end_position:
+                                      bytes: 115
+                                      line: 3
+                                      character: 36
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "\n"
+                              block:
+                                stmts:
+                                  - - Yield:
+                                        token:
+                                          leading_trivia:
+                                            - start_position:
+                                                bytes: 115
+                                                line: 4
+                                                character: 1
+                                              end_position:
+                                                bytes: 127
+                                                line: 4
+                                                character: 13
+                                              token_type:
+                                                type: Whitespace
+                                                characters: "            "
+                                          token:
+                                            start_position:
+                                              bytes: 127
+                                              line: 4
+                                              character: 13
+                                            end_position:
+                                              bytes: 132
+                                              line: 4
+                                              character: 18
+                                            token_type:
+                                              type: Symbol
+                                              symbol: yield
+                                          trailing_trivia:
+                                            - start_position:
+                                                bytes: 132
+                                                line: 4
+                                                character: 18
+                                              end_position:
+                                                bytes: 133
+                                                line: 4
+                                                character: 19
+                                              token_type:
+                                                type: Whitespace
+                                                characters: " "
+                                        yielded:
+                                          pairs:
+                                            - End:
+                                                Var:
+                                                  Name:
+                                                    leading_trivia: []
+                                                    token:
+                                                      start_position:
+                                                        bytes: 133
+                                                        line: 4
+                                                        character: 19
+                                                      end_position:
+                                                        bytes: 134
+                                                        line: 4
+                                                        character: 20
+                                                      token_type:
+                                                        type: Identifier
+                                                        identifier: s
+                                                    trailing_trivia:
+                                                      - start_position:
+                                                          bytes: 134
+                                                          line: 4
+                                                          character: 20
+                                                        end_position:
+                                                          bytes: 135
+                                                          line: 4
+                                                          character: 20
+                                                        token_type:
+                                                          type: Whitespace
+                                                          characters: "\n"
+                                    - ~
+                              else_if: ~
+                              else_token: ~
+                              else: ~
+                              end_token:
+                                leading_trivia:
+                                  - start_position:
+                                      bytes: 135
+                                      line: 5
+                                      character: 1
+                                    end_position:
+                                      bytes: 143
+                                      line: 5
+                                      character: 9
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "        "
+                                token:
+                                  start_position:
+                                    bytes: 143
+                                    line: 5
+                                    character: 9
+                                  end_position:
+                                    bytes: 146
+                                    line: 5
+                                    character: 12
+                                  token_type:
+                                    type: Symbol
+                                    symbol: end
+                                trailing_trivia:
+                                  - start_position:
+                                      bytes: 146
+                                      line: 5
+                                      character: 12
+                                    end_position:
+                                      bytes: 147
+                                      line: 5
+                                      character: 12
+                                    token_type:
+                                      type: Whitespace
+                                      characters: "\n"
+                          - ~
+                    end_token:
+                      leading_trivia:
+                        - start_position:
+                            bytes: 147
+                            line: 6
+                            character: 1
+                          end_position:
+                            bytes: 151
+                            line: 6
+                            character: 5
+                          token_type:
+                            type: Whitespace
+                            characters: "    "
+                      token:
+                        start_position:
+                          bytes: 151
+                          line: 6
+                          character: 5
+                        end_position:
+                          bytes: 154
+                          line: 6
+                          character: 8
+                        token_type:
+                          type: Symbol
+                          symbol: end
+                      trailing_trivia:
+                        - start_position:
+                            bytes: 154
+                            line: 6
+                            character: 8
+                          end_position:
+                            bytes: 155
+                            line: 6
+                            character: 8
+                          token_type:
+                            type: Whitespace
+                            characters: "\n"
+                    type_specifiers:
+                      - ~
+                      - ~
+                - ~
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 155
+                line: 7
+                character: 1
+              end_position:
+                bytes: 158
+                line: 7
+                character: 4
+              token_type:
+                type: Symbol
+                symbol: end
+            trailing_trivia:
+              - start_position:
+                  bytes: 158
+                  line: 7
+                  character: 4
+                end_position:
+                  bytes: 159
+                  line: 7
+                  character: 4
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job_yield/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job_yield/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..0e319dc51c2c7bfa90423d9458d05375883c75b8
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job_yield/source.lua
@@ -0,0 +1,7 @@
+job syl_modulo(every: number, disp: number, l: line): line
+    for i,s in l do
+        if (i % every) == disp then
+            yield s
+        end
+    end
+end
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job_yield/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job_yield/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..03ccae978349ddf0d4608a26325d251c1b507227
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/job_yield/tokens.snap
@@ -0,0 +1,763 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/pass/job_yield
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 3
+    line: 1
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: job
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Identifier
+    identifier: syl_modulo
+- 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: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Identifier
+    identifier: every
+- 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: 28
+    line: 1
+    character: 29
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 28
+    line: 1
+    character: 29
+  end_position:
+    bytes: 29
+    line: 1
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 29
+    line: 1
+    character: 30
+  end_position:
+    bytes: 30
+    line: 1
+    character: 31
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 30
+    line: 1
+    character: 31
+  end_position:
+    bytes: 34
+    line: 1
+    character: 35
+  token_type:
+    type: Identifier
+    identifier: disp
+- start_position:
+    bytes: 34
+    line: 1
+    character: 35
+  end_position:
+    bytes: 35
+    line: 1
+    character: 36
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 35
+    line: 1
+    character: 36
+  end_position:
+    bytes: 36
+    line: 1
+    character: 37
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 36
+    line: 1
+    character: 37
+  end_position:
+    bytes: 42
+    line: 1
+    character: 43
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 42
+    line: 1
+    character: 43
+  end_position:
+    bytes: 43
+    line: 1
+    character: 44
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 43
+    line: 1
+    character: 44
+  end_position:
+    bytes: 44
+    line: 1
+    character: 45
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 44
+    line: 1
+    character: 45
+  end_position:
+    bytes: 45
+    line: 1
+    character: 46
+  token_type:
+    type: Identifier
+    identifier: l
+- start_position:
+    bytes: 45
+    line: 1
+    character: 46
+  end_position:
+    bytes: 46
+    line: 1
+    character: 47
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 46
+    line: 1
+    character: 47
+  end_position:
+    bytes: 47
+    line: 1
+    character: 48
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 47
+    line: 1
+    character: 48
+  end_position:
+    bytes: 51
+    line: 1
+    character: 52
+  token_type:
+    type: Identifier
+    identifier: line
+- start_position:
+    bytes: 51
+    line: 1
+    character: 52
+  end_position:
+    bytes: 52
+    line: 1
+    character: 53
+  token_type:
+    type: Symbol
+    symbol: )
+- start_position:
+    bytes: 52
+    line: 1
+    character: 53
+  end_position:
+    bytes: 53
+    line: 1
+    character: 54
+  token_type:
+    type: Symbol
+    symbol: ":"
+- start_position:
+    bytes: 53
+    line: 1
+    character: 54
+  end_position:
+    bytes: 54
+    line: 1
+    character: 55
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 54
+    line: 1
+    character: 55
+  end_position:
+    bytes: 58
+    line: 1
+    character: 59
+  token_type:
+    type: Identifier
+    identifier: line
+- start_position:
+    bytes: 58
+    line: 1
+    character: 59
+  end_position:
+    bytes: 59
+    line: 1
+    character: 59
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 59
+    line: 2
+    character: 1
+  end_position:
+    bytes: 63
+    line: 2
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 63
+    line: 2
+    character: 5
+  end_position:
+    bytes: 66
+    line: 2
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: for
+- start_position:
+    bytes: 66
+    line: 2
+    character: 8
+  end_position:
+    bytes: 67
+    line: 2
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 67
+    line: 2
+    character: 9
+  end_position:
+    bytes: 68
+    line: 2
+    character: 10
+  token_type:
+    type: Identifier
+    identifier: i
+- start_position:
+    bytes: 68
+    line: 2
+    character: 10
+  end_position:
+    bytes: 69
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 69
+    line: 2
+    character: 11
+  end_position:
+    bytes: 70
+    line: 2
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: s
+- start_position:
+    bytes: 70
+    line: 2
+    character: 12
+  end_position:
+    bytes: 71
+    line: 2
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 71
+    line: 2
+    character: 13
+  end_position:
+    bytes: 73
+    line: 2
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: in
+- start_position:
+    bytes: 73
+    line: 2
+    character: 15
+  end_position:
+    bytes: 74
+    line: 2
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 74
+    line: 2
+    character: 16
+  end_position:
+    bytes: 75
+    line: 2
+    character: 17
+  token_type:
+    type: Identifier
+    identifier: l
+- start_position:
+    bytes: 75
+    line: 2
+    character: 17
+  end_position:
+    bytes: 76
+    line: 2
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 76
+    line: 2
+    character: 18
+  end_position:
+    bytes: 78
+    line: 2
+    character: 20
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 78
+    line: 2
+    character: 20
+  end_position:
+    bytes: 79
+    line: 2
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 79
+    line: 3
+    character: 1
+  end_position:
+    bytes: 87
+    line: 3
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: "        "
+- start_position:
+    bytes: 87
+    line: 3
+    character: 9
+  end_position:
+    bytes: 89
+    line: 3
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: if
+- start_position:
+    bytes: 89
+    line: 3
+    character: 11
+  end_position:
+    bytes: 90
+    line: 3
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- 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: Identifier
+    identifier: i
+- start_position:
+    bytes: 92
+    line: 3
+    character: 14
+  end_position:
+    bytes: 93
+    line: 3
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 93
+    line: 3
+    character: 15
+  end_position:
+    bytes: 94
+    line: 3
+    character: 16
+  token_type:
+    type: Symbol
+    symbol: "%"
+- start_position:
+    bytes: 94
+    line: 3
+    character: 16
+  end_position:
+    bytes: 95
+    line: 3
+    character: 17
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 95
+    line: 3
+    character: 17
+  end_position:
+    bytes: 100
+    line: 3
+    character: 22
+  token_type:
+    type: Identifier
+    identifier: every
+- 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: Whitespace
+    characters: " "
+- start_position:
+    bytes: 102
+    line: 3
+    character: 24
+  end_position:
+    bytes: 104
+    line: 3
+    character: 26
+  token_type:
+    type: Symbol
+    symbol: "=="
+- start_position:
+    bytes: 104
+    line: 3
+    character: 26
+  end_position:
+    bytes: 105
+    line: 3
+    character: 27
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 105
+    line: 3
+    character: 27
+  end_position:
+    bytes: 109
+    line: 3
+    character: 31
+  token_type:
+    type: Identifier
+    identifier: disp
+- start_position:
+    bytes: 109
+    line: 3
+    character: 31
+  end_position:
+    bytes: 110
+    line: 3
+    character: 32
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 110
+    line: 3
+    character: 32
+  end_position:
+    bytes: 114
+    line: 3
+    character: 36
+  token_type:
+    type: Symbol
+    symbol: then
+- start_position:
+    bytes: 114
+    line: 3
+    character: 36
+  end_position:
+    bytes: 115
+    line: 3
+    character: 36
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 115
+    line: 4
+    character: 1
+  end_position:
+    bytes: 127
+    line: 4
+    character: 13
+  token_type:
+    type: Whitespace
+    characters: "            "
+- start_position:
+    bytes: 127
+    line: 4
+    character: 13
+  end_position:
+    bytes: 132
+    line: 4
+    character: 18
+  token_type:
+    type: Symbol
+    symbol: yield
+- start_position:
+    bytes: 132
+    line: 4
+    character: 18
+  end_position:
+    bytes: 133
+    line: 4
+    character: 19
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 133
+    line: 4
+    character: 19
+  end_position:
+    bytes: 134
+    line: 4
+    character: 20
+  token_type:
+    type: Identifier
+    identifier: s
+- start_position:
+    bytes: 134
+    line: 4
+    character: 20
+  end_position:
+    bytes: 135
+    line: 4
+    character: 20
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 135
+    line: 5
+    character: 1
+  end_position:
+    bytes: 143
+    line: 5
+    character: 9
+  token_type:
+    type: Whitespace
+    characters: "        "
+- start_position:
+    bytes: 143
+    line: 5
+    character: 9
+  end_position:
+    bytes: 146
+    line: 5
+    character: 12
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 146
+    line: 5
+    character: 12
+  end_position:
+    bytes: 147
+    line: 5
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 147
+    line: 6
+    character: 1
+  end_position:
+    bytes: 151
+    line: 6
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 151
+    line: 6
+    character: 5
+  end_position:
+    bytes: 154
+    line: 6
+    character: 8
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 154
+    line: 6
+    character: 8
+  end_position:
+    bytes: 155
+    line: 6
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 155
+    line: 7
+    character: 1
+  end_position:
+    bytes: 158
+    line: 7
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 158
+    line: 7
+    character: 4
+  end_position:
+    bytes: 159
+    line: 7
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 159
+    line: 8
+    character: 1
+  end_position:
+    bytes: 159
+    line: 8
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_busy/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_busy/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..98250ff9289fd101a0c06565bbb3084e1ee85922
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_busy/ast.snap
@@ -0,0 +1,1245 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/vivy_cases/pass/main_busy
+---
+stmts:
+  - - Main:
+        main_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 0
+              line: 1
+              character: 1
+            end_position:
+              bytes: 4
+              line: 1
+              character: 5
+            token_type:
+              type: Symbol
+              symbol: main
+          trailing_trivia:
+            - start_position:
+                bytes: 4
+                line: 1
+                character: 5
+              end_position:
+                bytes: 5
+                line: 1
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        initial_variable:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 5
+              line: 1
+              character: 6
+            end_position:
+              bytes: 11
+              line: 1
+              character: 12
+            token_type:
+              type: StringLiteral
+              literal: init
+              quote_type: Double
+          trailing_trivia:
+            - start_position:
+                bytes: 11
+                line: 1
+                character: 12
+              end_position:
+                bytes: 12
+                line: 1
+                character: 13
+              token_type:
+                type: Whitespace
+                characters: " "
+        begin_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: 15
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        assignements:
+          - variable:
+              leading_trivia:
+                - start_position:
+                    bytes: 15
+                    line: 2
+                    character: 1
+                  end_position:
+                    bytes: 19
+                    line: 2
+                    character: 5
+                  token_type:
+                    type: Whitespace
+                    characters: "    "
+              token:
+                start_position:
+                  bytes: 19
+                  line: 2
+                  character: 5
+                end_position:
+                  bytes: 27
+                  line: 2
+                  character: 13
+                token_type:
+                  type: StringLiteral
+                  literal: before
+                  quote_type: Double
+              trailing_trivia:
+                - start_position:
+                    bytes: 27
+                    line: 2
+                    character: 13
+                  end_position:
+                    bytes: 30
+                    line: 2
+                    character: 16
+                  token_type:
+                    type: Whitespace
+                    characters: "   "
+            assign_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 30
+                  line: 2
+                  character: 16
+                end_position:
+                  bytes: 31
+                  line: 2
+                  character: 17
+                token_type:
+                  type: Symbol
+                  symbol: "="
+              trailing_trivia:
+                - start_position:
+                    bytes: 31
+                    line: 2
+                    character: 17
+                  end_position:
+                    bytes: 32
+                    line: 2
+                    character: 18
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            module_name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 32
+                  line: 2
+                  character: 18
+                end_position:
+                  bytes: 38
+                  line: 2
+                  character: 24
+                token_type:
+                  type: Identifier
+                  identifier: retime
+              trailing_trivia: []
+            dot_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 38
+                  line: 2
+                  character: 24
+                end_position:
+                  bytes: 39
+                  line: 2
+                  character: 25
+                token_type:
+                  type: Symbol
+                  symbol: "."
+              trailing_trivia: []
+            job_name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 39
+                  line: 2
+                  character: 25
+                end_position:
+                  bytes: 44
+                  line: 2
+                  character: 30
+                token_type:
+                  type: Identifier
+                  identifier: start
+              trailing_trivia:
+                - start_position:
+                    bytes: 44
+                    line: 2
+                    character: 30
+                  end_position:
+                    bytes: 47
+                    line: 2
+                    character: 33
+                  token_type:
+                    type: Whitespace
+                    characters: "   "
+            call_list:
+              begin_token:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 47
+                    line: 2
+                    character: 33
+                  end_position:
+                    bytes: 48
+                    line: 2
+                    character: 34
+                  token_type:
+                    type: Symbol
+                    symbol: "{"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 48
+                      line: 2
+                      character: 34
+                    end_position:
+                      bytes: 49
+                      line: 2
+                      character: 35
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              items:
+                pairs:
+                  - End:
+                      Variable:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 49
+                            line: 2
+                            character: 35
+                          end_position:
+                            bytes: 55
+                            line: 2
+                            character: 41
+                          token_type:
+                            type: StringLiteral
+                            literal: init
+                            quote_type: Double
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 55
+                              line: 2
+                              character: 41
+                            end_position:
+                              bytes: 56
+                              line: 2
+                              character: 42
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+              end_token:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 56
+                    line: 2
+                    character: 42
+                  end_position:
+                    bytes: 57
+                    line: 2
+                    character: 43
+                  token_type:
+                    type: Symbol
+                    symbol: "}"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 57
+                      line: 2
+                      character: 43
+                    end_position:
+                      bytes: 58
+                      line: 2
+                      character: 43
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+          - variable:
+              leading_trivia:
+                - start_position:
+                    bytes: 58
+                    line: 3
+                    character: 1
+                  end_position:
+                    bytes: 62
+                    line: 3
+                    character: 5
+                  token_type:
+                    type: Whitespace
+                    characters: "    "
+              token:
+                start_position:
+                  bytes: 62
+                  line: 3
+                  character: 5
+                end_position:
+                  bytes: 69
+                  line: 3
+                  character: 12
+                token_type:
+                  type: StringLiteral
+                  literal: after
+                  quote_type: Double
+              trailing_trivia:
+                - start_position:
+                    bytes: 69
+                    line: 3
+                    character: 12
+                  end_position:
+                    bytes: 73
+                    line: 3
+                    character: 16
+                  token_type:
+                    type: Whitespace
+                    characters: "    "
+            assign_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 73
+                  line: 3
+                  character: 16
+                end_position:
+                  bytes: 74
+                  line: 3
+                  character: 17
+                token_type:
+                  type: Symbol
+                  symbol: "="
+              trailing_trivia:
+                - start_position:
+                    bytes: 74
+                    line: 3
+                    character: 17
+                  end_position:
+                    bytes: 75
+                    line: 3
+                    character: 18
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            module_name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 75
+                  line: 3
+                  character: 18
+                end_position:
+                  bytes: 81
+                  line: 3
+                  character: 24
+                token_type:
+                  type: Identifier
+                  identifier: retime
+              trailing_trivia: []
+            dot_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 81
+                  line: 3
+                  character: 24
+                end_position:
+                  bytes: 82
+                  line: 3
+                  character: 25
+                token_type:
+                  type: Symbol
+                  symbol: "."
+              trailing_trivia: []
+            job_name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 82
+                  line: 3
+                  character: 25
+                end_position:
+                  bytes: 88
+                  line: 3
+                  character: 31
+                token_type:
+                  type: Identifier
+                  identifier: finish
+              trailing_trivia:
+                - start_position:
+                    bytes: 88
+                    line: 3
+                    character: 31
+                  end_position:
+                    bytes: 90
+                    line: 3
+                    character: 33
+                  token_type:
+                    type: Whitespace
+                    characters: "  "
+            call_list:
+              begin_token:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 90
+                    line: 3
+                    character: 33
+                  end_position:
+                    bytes: 91
+                    line: 3
+                    character: 34
+                  token_type:
+                    type: Symbol
+                    symbol: "{"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 91
+                      line: 3
+                      character: 34
+                    end_position:
+                      bytes: 92
+                      line: 3
+                      character: 35
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              items:
+                pairs:
+                  - End:
+                      Variable:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 92
+                            line: 3
+                            character: 35
+                          end_position:
+                            bytes: 98
+                            line: 3
+                            character: 41
+                          token_type:
+                            type: StringLiteral
+                            literal: init
+                            quote_type: Double
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 98
+                              line: 3
+                              character: 41
+                            end_position:
+                              bytes: 99
+                              line: 3
+                              character: 42
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+              end_token:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 99
+                    line: 3
+                    character: 42
+                  end_position:
+                    bytes: 100
+                    line: 3
+                    character: 43
+                  token_type:
+                    type: Symbol
+                    symbol: "}"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 100
+                      line: 3
+                      character: 43
+                    end_position:
+                      bytes: 101
+                      line: 3
+                      character: 43
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+          - variable:
+              leading_trivia:
+                - start_position:
+                    bytes: 101
+                    line: 4
+                    character: 1
+                  end_position:
+                    bytes: 105
+                    line: 4
+                    character: 5
+                  token_type:
+                    type: Whitespace
+                    characters: "    "
+              token:
+                start_position:
+                  bytes: 105
+                  line: 4
+                  character: 5
+                end_position:
+                  bytes: 115
+                  line: 4
+                  character: 15
+                token_type:
+                  type: StringLiteral
+                  literal: outlined
+                  quote_type: Double
+              trailing_trivia:
+                - start_position:
+                    bytes: 115
+                    line: 4
+                    character: 15
+                  end_position:
+                    bytes: 116
+                    line: 4
+                    character: 16
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            assign_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 116
+                  line: 4
+                  character: 16
+                end_position:
+                  bytes: 117
+                  line: 4
+                  character: 17
+                token_type:
+                  type: Symbol
+                  symbol: "="
+              trailing_trivia:
+                - start_position:
+                    bytes: 117
+                    line: 4
+                    character: 17
+                  end_position:
+                    bytes: 118
+                    line: 4
+                    character: 18
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            module_name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 118
+                  line: 4
+                  character: 18
+                end_position:
+                  bytes: 123
+                  line: 4
+                  character: 23
+                token_type:
+                  type: Identifier
+                  identifier: utils
+              trailing_trivia: []
+            dot_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 123
+                  line: 4
+                  character: 23
+                end_position:
+                  bytes: 124
+                  line: 4
+                  character: 24
+                token_type:
+                  type: Symbol
+                  symbol: "."
+              trailing_trivia: []
+            job_name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 124
+                  line: 4
+                  character: 24
+                end_position:
+                  bytes: 131
+                  line: 4
+                  character: 31
+                token_type:
+                  type: Identifier
+                  identifier: outline
+              trailing_trivia:
+                - start_position:
+                    bytes: 131
+                    line: 4
+                    character: 31
+                  end_position:
+                    bytes: 133
+                    line: 4
+                    character: 33
+                  token_type:
+                    type: Whitespace
+                    characters: "  "
+            call_list:
+              begin_token:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 133
+                    line: 4
+                    character: 33
+                  end_position:
+                    bytes: 134
+                    line: 4
+                    character: 34
+                  token_type:
+                    type: Symbol
+                    symbol: "{"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 134
+                      line: 4
+                      character: 34
+                    end_position:
+                      bytes: 135
+                      line: 4
+                      character: 35
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              items:
+                pairs:
+                  - Punctuated:
+                      - Variable:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 135
+                              line: 4
+                              character: 35
+                            end_position:
+                              bytes: 143
+                              line: 4
+                              character: 43
+                            token_type:
+                              type: StringLiteral
+                              literal: before
+                              quote_type: Double
+                          trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 143
+                            line: 4
+                            character: 43
+                          end_position:
+                            bytes: 144
+                            line: 4
+                            character: 44
+                          token_type:
+                            type: Symbol
+                            symbol: ","
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 144
+                              line: 4
+                              character: 44
+                            end_position:
+                              bytes: 145
+                              line: 4
+                              character: 45
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  - Punctuated:
+                      - Variable:
+                          leading_trivia: []
+                          token:
+                            start_position:
+                              bytes: 145
+                              line: 4
+                              character: 45
+                            end_position:
+                              bytes: 151
+                              line: 4
+                              character: 51
+                            token_type:
+                              type: StringLiteral
+                              literal: init
+                              quote_type: Double
+                          trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 151
+                            line: 4
+                            character: 51
+                          end_position:
+                            bytes: 152
+                            line: 4
+                            character: 52
+                          token_type:
+                            type: Symbol
+                            symbol: ","
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 152
+                              line: 4
+                              character: 52
+                            end_position:
+                              bytes: 153
+                              line: 4
+                              character: 53
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  - End:
+                      Variable:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 153
+                            line: 4
+                            character: 53
+                          end_position:
+                            bytes: 160
+                            line: 4
+                            character: 60
+                          token_type:
+                            type: StringLiteral
+                            literal: after
+                            quote_type: Double
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 160
+                              line: 4
+                              character: 60
+                            end_position:
+                              bytes: 161
+                              line: 4
+                              character: 61
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+              end_token:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 161
+                    line: 4
+                    character: 61
+                  end_position:
+                    bytes: 162
+                    line: 4
+                    character: 62
+                  token_type:
+                    type: Symbol
+                    symbol: "}"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 162
+                      line: 4
+                      character: 62
+                    end_position:
+                      bytes: 163
+                      line: 4
+                      character: 62
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+          - variable:
+              leading_trivia:
+                - start_position:
+                    bytes: 163
+                    line: 5
+                    character: 1
+                  end_position:
+                    bytes: 164
+                    line: 5
+                    character: 1
+                  token_type:
+                    type: Whitespace
+                    characters: "\n"
+                - start_position:
+                    bytes: 164
+                    line: 6
+                    character: 1
+                  end_position:
+                    bytes: 168
+                    line: 6
+                    character: 5
+                  token_type:
+                    type: Whitespace
+                    characters: "    "
+                - start_position:
+                    bytes: 168
+                    line: 6
+                    character: 5
+                  end_position:
+                    bytes: 198
+                    line: 6
+                    character: 35
+                  token_type:
+                    type: SingleLineComment
+                    comment: " Here we tag some objects..."
+                - start_position:
+                    bytes: 198
+                    line: 6
+                    character: 35
+                  end_position:
+                    bytes: 199
+                    line: 6
+                    character: 35
+                  token_type:
+                    type: Whitespace
+                    characters: "\n"
+                - start_position:
+                    bytes: 199
+                    line: 7
+                    character: 1
+                  end_position:
+                    bytes: 203
+                    line: 7
+                    character: 5
+                  token_type:
+                    type: Whitespace
+                    characters: "    "
+              token:
+                start_position:
+                  bytes: 203
+                  line: 7
+                  character: 5
+                end_position:
+                  bytes: 211
+                  line: 7
+                  character: 13
+                token_type:
+                  type: StringLiteral
+                  literal: tagged
+                  quote_type: Double
+              trailing_trivia:
+                - start_position:
+                    bytes: 211
+                    line: 7
+                    character: 13
+                  end_position:
+                    bytes: 214
+                    line: 7
+                    character: 16
+                  token_type:
+                    type: Whitespace
+                    characters: "   "
+            assign_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 214
+                  line: 7
+                  character: 16
+                end_position:
+                  bytes: 215
+                  line: 7
+                  character: 17
+                token_type:
+                  type: Symbol
+                  symbol: "="
+              trailing_trivia:
+                - start_position:
+                    bytes: 215
+                    line: 7
+                    character: 17
+                  end_position:
+                    bytes: 216
+                    line: 7
+                    character: 18
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            module_name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 216
+                  line: 7
+                  character: 18
+                end_position:
+                  bytes: 219
+                  line: 7
+                  character: 21
+                token_type:
+                  type: Identifier
+                  identifier: tag
+              trailing_trivia: []
+            dot_token:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 219
+                  line: 7
+                  character: 21
+                end_position:
+                  bytes: 220
+                  line: 7
+                  character: 22
+                token_type:
+                  type: Symbol
+                  symbol: "."
+              trailing_trivia: []
+            job_name:
+              leading_trivia: []
+              token:
+                start_position:
+                  bytes: 220
+                  line: 7
+                  character: 22
+                end_position:
+                  bytes: 230
+                  line: 7
+                  character: 32
+                token_type:
+                  type: Identifier
+                  identifier: syl_modulo
+              trailing_trivia:
+                - start_position:
+                    bytes: 230
+                    line: 7
+                    character: 32
+                  end_position:
+                    bytes: 231
+                    line: 7
+                    character: 33
+                  token_type:
+                    type: Whitespace
+                    characters: " "
+            call_list:
+              begin_token:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 231
+                    line: 7
+                    character: 33
+                  end_position:
+                    bytes: 232
+                    line: 7
+                    character: 34
+                  token_type:
+                    type: Symbol
+                    symbol: "{"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 232
+                      line: 7
+                      character: 34
+                    end_position:
+                      bytes: 233
+                      line: 7
+                      character: 35
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+              items:
+                pairs:
+                  - Punctuated:
+                      - SetParameter:
+                          parameter:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 233
+                                line: 7
+                                character: 35
+                              end_position:
+                                bytes: 238
+                                line: 7
+                                character: 40
+                              token_type:
+                                type: Identifier
+                                identifier: every
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 238
+                                  line: 7
+                                  character: 40
+                                end_position:
+                                  bytes: 239
+                                  line: 7
+                                  character: 41
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                          equal_token:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 239
+                                line: 7
+                                character: 41
+                              end_position:
+                                bytes: 240
+                                line: 7
+                                character: 42
+                              token_type:
+                                type: Symbol
+                                symbol: "="
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 240
+                                  line: 7
+                                  character: 42
+                                end_position:
+                                  bytes: 241
+                                  line: 7
+                                  character: 43
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                          expression:
+                            Number:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 241
+                                  line: 7
+                                  character: 43
+                                end_position:
+                                  bytes: 242
+                                  line: 7
+                                  character: 44
+                                token_type:
+                                  type: Number
+                                  text: "3"
+                              trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 242
+                            line: 7
+                            character: 44
+                          end_position:
+                            bytes: 243
+                            line: 7
+                            character: 45
+                          token_type:
+                            type: Symbol
+                            symbol: ","
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 243
+                              line: 7
+                              character: 45
+                            end_position:
+                              bytes: 244
+                              line: 7
+                              character: 46
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  - Punctuated:
+                      - SetParameter:
+                          parameter:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 244
+                                line: 7
+                                character: 46
+                              end_position:
+                                bytes: 248
+                                line: 7
+                                character: 50
+                              token_type:
+                                type: Identifier
+                                identifier: disp
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 248
+                                  line: 7
+                                  character: 50
+                                end_position:
+                                  bytes: 249
+                                  line: 7
+                                  character: 51
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                          equal_token:
+                            leading_trivia: []
+                            token:
+                              start_position:
+                                bytes: 249
+                                line: 7
+                                character: 51
+                              end_position:
+                                bytes: 250
+                                line: 7
+                                character: 52
+                              token_type:
+                                type: Symbol
+                                symbol: "="
+                            trailing_trivia:
+                              - start_position:
+                                  bytes: 250
+                                  line: 7
+                                  character: 52
+                                end_position:
+                                  bytes: 251
+                                  line: 7
+                                  character: 53
+                                token_type:
+                                  type: Whitespace
+                                  characters: " "
+                          expression:
+                            Number:
+                              leading_trivia: []
+                              token:
+                                start_position:
+                                  bytes: 251
+                                  line: 7
+                                  character: 53
+                                end_position:
+                                  bytes: 252
+                                  line: 7
+                                  character: 54
+                                token_type:
+                                  type: Number
+                                  text: "1"
+                              trailing_trivia: []
+                      - leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 252
+                            line: 7
+                            character: 54
+                          end_position:
+                            bytes: 253
+                            line: 7
+                            character: 55
+                          token_type:
+                            type: Symbol
+                            symbol: ","
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 253
+                              line: 7
+                              character: 55
+                            end_position:
+                              bytes: 254
+                              line: 7
+                              character: 56
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+                  - End:
+                      Variable:
+                        leading_trivia: []
+                        token:
+                          start_position:
+                            bytes: 254
+                            line: 7
+                            character: 56
+                          end_position:
+                            bytes: 264
+                            line: 7
+                            character: 66
+                          token_type:
+                            type: StringLiteral
+                            literal: outlined
+                            quote_type: Double
+                        trailing_trivia:
+                          - start_position:
+                              bytes: 264
+                              line: 7
+                              character: 66
+                            end_position:
+                              bytes: 265
+                              line: 7
+                              character: 67
+                            token_type:
+                              type: Whitespace
+                              characters: " "
+              end_token:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 265
+                    line: 7
+                    character: 67
+                  end_position:
+                    bytes: 266
+                    line: 7
+                    character: 68
+                  token_type:
+                    type: Symbol
+                    symbol: "}"
+                trailing_trivia:
+                  - start_position:
+                      bytes: 266
+                      line: 7
+                      character: 68
+                    end_position:
+                      bytes: 267
+                      line: 7
+                      character: 68
+                    token_type:
+                      type: Whitespace
+                      characters: "\n"
+        write_stmt: ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 267
+              line: 8
+              character: 1
+            end_position:
+              bytes: 270
+              line: 8
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 270
+                line: 8
+                character: 4
+              end_position:
+                bytes: 271
+                line: 8
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_busy/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_busy/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..94cd169d5946cd586c2944b58cb649ef5cc557ae
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_busy/source.lua
@@ -0,0 +1,8 @@
+main "init" do
+    "before"   = retime.start   { "init" }
+    "after"    = retime.finish  { "init" }
+    "outlined" = utils.outline  { "before", "init", "after" }
+
+    -- Here we tag some objects...
+    "tagged"   = tag.syl_modulo { every = 3, disp = 1, "outlined" }
+end
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_busy/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_busy/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..032339db837420f327bf32b56b70410d63a1015d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_busy/tokens.snap
@@ -0,0 +1,1038 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/pass/main_busy
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: main
+- 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: StringLiteral
+    literal: init
+    quote_type: Double
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 14
+    line: 1
+    character: 15
+  end_position:
+    bytes: 15
+    line: 1
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 2
+    character: 1
+  end_position:
+    bytes: 19
+    line: 2
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 19
+    line: 2
+    character: 5
+  end_position:
+    bytes: 27
+    line: 2
+    character: 13
+  token_type:
+    type: StringLiteral
+    literal: before
+    quote_type: Double
+- start_position:
+    bytes: 27
+    line: 2
+    character: 13
+  end_position:
+    bytes: 30
+    line: 2
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "   "
+- start_position:
+    bytes: 30
+    line: 2
+    character: 16
+  end_position:
+    bytes: 31
+    line: 2
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 31
+    line: 2
+    character: 17
+  end_position:
+    bytes: 32
+    line: 2
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 32
+    line: 2
+    character: 18
+  end_position:
+    bytes: 38
+    line: 2
+    character: 24
+  token_type:
+    type: Identifier
+    identifier: retime
+- start_position:
+    bytes: 38
+    line: 2
+    character: 24
+  end_position:
+    bytes: 39
+    line: 2
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 39
+    line: 2
+    character: 25
+  end_position:
+    bytes: 44
+    line: 2
+    character: 30
+  token_type:
+    type: Identifier
+    identifier: start
+- start_position:
+    bytes: 44
+    line: 2
+    character: 30
+  end_position:
+    bytes: 47
+    line: 2
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: "   "
+- start_position:
+    bytes: 47
+    line: 2
+    character: 33
+  end_position:
+    bytes: 48
+    line: 2
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 48
+    line: 2
+    character: 34
+  end_position:
+    bytes: 49
+    line: 2
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 49
+    line: 2
+    character: 35
+  end_position:
+    bytes: 55
+    line: 2
+    character: 41
+  token_type:
+    type: StringLiteral
+    literal: init
+    quote_type: Double
+- start_position:
+    bytes: 55
+    line: 2
+    character: 41
+  end_position:
+    bytes: 56
+    line: 2
+    character: 42
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 56
+    line: 2
+    character: 42
+  end_position:
+    bytes: 57
+    line: 2
+    character: 43
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 57
+    line: 2
+    character: 43
+  end_position:
+    bytes: 58
+    line: 2
+    character: 43
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 58
+    line: 3
+    character: 1
+  end_position:
+    bytes: 62
+    line: 3
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 62
+    line: 3
+    character: 5
+  end_position:
+    bytes: 69
+    line: 3
+    character: 12
+  token_type:
+    type: StringLiteral
+    literal: after
+    quote_type: Double
+- start_position:
+    bytes: 69
+    line: 3
+    character: 12
+  end_position:
+    bytes: 73
+    line: 3
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 73
+    line: 3
+    character: 16
+  end_position:
+    bytes: 74
+    line: 3
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 74
+    line: 3
+    character: 17
+  end_position:
+    bytes: 75
+    line: 3
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 75
+    line: 3
+    character: 18
+  end_position:
+    bytes: 81
+    line: 3
+    character: 24
+  token_type:
+    type: Identifier
+    identifier: retime
+- start_position:
+    bytes: 81
+    line: 3
+    character: 24
+  end_position:
+    bytes: 82
+    line: 3
+    character: 25
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 82
+    line: 3
+    character: 25
+  end_position:
+    bytes: 88
+    line: 3
+    character: 31
+  token_type:
+    type: Identifier
+    identifier: finish
+- start_position:
+    bytes: 88
+    line: 3
+    character: 31
+  end_position:
+    bytes: 90
+    line: 3
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: "  "
+- start_position:
+    bytes: 90
+    line: 3
+    character: 33
+  end_position:
+    bytes: 91
+    line: 3
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 91
+    line: 3
+    character: 34
+  end_position:
+    bytes: 92
+    line: 3
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 92
+    line: 3
+    character: 35
+  end_position:
+    bytes: 98
+    line: 3
+    character: 41
+  token_type:
+    type: StringLiteral
+    literal: init
+    quote_type: Double
+- start_position:
+    bytes: 98
+    line: 3
+    character: 41
+  end_position:
+    bytes: 99
+    line: 3
+    character: 42
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 99
+    line: 3
+    character: 42
+  end_position:
+    bytes: 100
+    line: 3
+    character: 43
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 100
+    line: 3
+    character: 43
+  end_position:
+    bytes: 101
+    line: 3
+    character: 43
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 101
+    line: 4
+    character: 1
+  end_position:
+    bytes: 105
+    line: 4
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 105
+    line: 4
+    character: 5
+  end_position:
+    bytes: 115
+    line: 4
+    character: 15
+  token_type:
+    type: StringLiteral
+    literal: outlined
+    quote_type: Double
+- start_position:
+    bytes: 115
+    line: 4
+    character: 15
+  end_position:
+    bytes: 116
+    line: 4
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 116
+    line: 4
+    character: 16
+  end_position:
+    bytes: 117
+    line: 4
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 117
+    line: 4
+    character: 17
+  end_position:
+    bytes: 118
+    line: 4
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 118
+    line: 4
+    character: 18
+  end_position:
+    bytes: 123
+    line: 4
+    character: 23
+  token_type:
+    type: Identifier
+    identifier: utils
+- start_position:
+    bytes: 123
+    line: 4
+    character: 23
+  end_position:
+    bytes: 124
+    line: 4
+    character: 24
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 124
+    line: 4
+    character: 24
+  end_position:
+    bytes: 131
+    line: 4
+    character: 31
+  token_type:
+    type: Identifier
+    identifier: outline
+- start_position:
+    bytes: 131
+    line: 4
+    character: 31
+  end_position:
+    bytes: 133
+    line: 4
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: "  "
+- start_position:
+    bytes: 133
+    line: 4
+    character: 33
+  end_position:
+    bytes: 134
+    line: 4
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 134
+    line: 4
+    character: 34
+  end_position:
+    bytes: 135
+    line: 4
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 135
+    line: 4
+    character: 35
+  end_position:
+    bytes: 143
+    line: 4
+    character: 43
+  token_type:
+    type: StringLiteral
+    literal: before
+    quote_type: Double
+- start_position:
+    bytes: 143
+    line: 4
+    character: 43
+  end_position:
+    bytes: 144
+    line: 4
+    character: 44
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 144
+    line: 4
+    character: 44
+  end_position:
+    bytes: 145
+    line: 4
+    character: 45
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 145
+    line: 4
+    character: 45
+  end_position:
+    bytes: 151
+    line: 4
+    character: 51
+  token_type:
+    type: StringLiteral
+    literal: init
+    quote_type: Double
+- start_position:
+    bytes: 151
+    line: 4
+    character: 51
+  end_position:
+    bytes: 152
+    line: 4
+    character: 52
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 152
+    line: 4
+    character: 52
+  end_position:
+    bytes: 153
+    line: 4
+    character: 53
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 153
+    line: 4
+    character: 53
+  end_position:
+    bytes: 160
+    line: 4
+    character: 60
+  token_type:
+    type: StringLiteral
+    literal: after
+    quote_type: Double
+- start_position:
+    bytes: 160
+    line: 4
+    character: 60
+  end_position:
+    bytes: 161
+    line: 4
+    character: 61
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 161
+    line: 4
+    character: 61
+  end_position:
+    bytes: 162
+    line: 4
+    character: 62
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 162
+    line: 4
+    character: 62
+  end_position:
+    bytes: 163
+    line: 4
+    character: 62
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 163
+    line: 5
+    character: 1
+  end_position:
+    bytes: 164
+    line: 5
+    character: 1
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 164
+    line: 6
+    character: 1
+  end_position:
+    bytes: 168
+    line: 6
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 168
+    line: 6
+    character: 5
+  end_position:
+    bytes: 198
+    line: 6
+    character: 35
+  token_type:
+    type: SingleLineComment
+    comment: " Here we tag some objects..."
+- start_position:
+    bytes: 198
+    line: 6
+    character: 35
+  end_position:
+    bytes: 199
+    line: 6
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 199
+    line: 7
+    character: 1
+  end_position:
+    bytes: 203
+    line: 7
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 203
+    line: 7
+    character: 5
+  end_position:
+    bytes: 211
+    line: 7
+    character: 13
+  token_type:
+    type: StringLiteral
+    literal: tagged
+    quote_type: Double
+- start_position:
+    bytes: 211
+    line: 7
+    character: 13
+  end_position:
+    bytes: 214
+    line: 7
+    character: 16
+  token_type:
+    type: Whitespace
+    characters: "   "
+- start_position:
+    bytes: 214
+    line: 7
+    character: 16
+  end_position:
+    bytes: 215
+    line: 7
+    character: 17
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 215
+    line: 7
+    character: 17
+  end_position:
+    bytes: 216
+    line: 7
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 216
+    line: 7
+    character: 18
+  end_position:
+    bytes: 219
+    line: 7
+    character: 21
+  token_type:
+    type: Identifier
+    identifier: tag
+- start_position:
+    bytes: 219
+    line: 7
+    character: 21
+  end_position:
+    bytes: 220
+    line: 7
+    character: 22
+  token_type:
+    type: Symbol
+    symbol: "."
+- start_position:
+    bytes: 220
+    line: 7
+    character: 22
+  end_position:
+    bytes: 230
+    line: 7
+    character: 32
+  token_type:
+    type: Identifier
+    identifier: syl_modulo
+- start_position:
+    bytes: 230
+    line: 7
+    character: 32
+  end_position:
+    bytes: 231
+    line: 7
+    character: 33
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 231
+    line: 7
+    character: 33
+  end_position:
+    bytes: 232
+    line: 7
+    character: 34
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 232
+    line: 7
+    character: 34
+  end_position:
+    bytes: 233
+    line: 7
+    character: 35
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 233
+    line: 7
+    character: 35
+  end_position:
+    bytes: 238
+    line: 7
+    character: 40
+  token_type:
+    type: Identifier
+    identifier: every
+- start_position:
+    bytes: 238
+    line: 7
+    character: 40
+  end_position:
+    bytes: 239
+    line: 7
+    character: 41
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 239
+    line: 7
+    character: 41
+  end_position:
+    bytes: 240
+    line: 7
+    character: 42
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 240
+    line: 7
+    character: 42
+  end_position:
+    bytes: 241
+    line: 7
+    character: 43
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 241
+    line: 7
+    character: 43
+  end_position:
+    bytes: 242
+    line: 7
+    character: 44
+  token_type:
+    type: Number
+    text: "3"
+- start_position:
+    bytes: 242
+    line: 7
+    character: 44
+  end_position:
+    bytes: 243
+    line: 7
+    character: 45
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 243
+    line: 7
+    character: 45
+  end_position:
+    bytes: 244
+    line: 7
+    character: 46
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 244
+    line: 7
+    character: 46
+  end_position:
+    bytes: 248
+    line: 7
+    character: 50
+  token_type:
+    type: Identifier
+    identifier: disp
+- start_position:
+    bytes: 248
+    line: 7
+    character: 50
+  end_position:
+    bytes: 249
+    line: 7
+    character: 51
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 249
+    line: 7
+    character: 51
+  end_position:
+    bytes: 250
+    line: 7
+    character: 52
+  token_type:
+    type: Symbol
+    symbol: "="
+- start_position:
+    bytes: 250
+    line: 7
+    character: 52
+  end_position:
+    bytes: 251
+    line: 7
+    character: 53
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 251
+    line: 7
+    character: 53
+  end_position:
+    bytes: 252
+    line: 7
+    character: 54
+  token_type:
+    type: Number
+    text: "1"
+- start_position:
+    bytes: 252
+    line: 7
+    character: 54
+  end_position:
+    bytes: 253
+    line: 7
+    character: 55
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 253
+    line: 7
+    character: 55
+  end_position:
+    bytes: 254
+    line: 7
+    character: 56
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 254
+    line: 7
+    character: 56
+  end_position:
+    bytes: 264
+    line: 7
+    character: 66
+  token_type:
+    type: StringLiteral
+    literal: outlined
+    quote_type: Double
+- start_position:
+    bytes: 264
+    line: 7
+    character: 66
+  end_position:
+    bytes: 265
+    line: 7
+    character: 67
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 265
+    line: 7
+    character: 67
+  end_position:
+    bytes: 266
+    line: 7
+    character: 68
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 266
+    line: 7
+    character: 68
+  end_position:
+    bytes: 267
+    line: 7
+    character: 68
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 267
+    line: 8
+    character: 1
+  end_position:
+    bytes: 270
+    line: 8
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 270
+    line: 8
+    character: 4
+  end_position:
+    bytes: 271
+    line: 8
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 271
+    line: 9
+    character: 1
+  end_position:
+    bytes: 271
+    line: 9
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_empty/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_empty/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..8ad1f4c89d67f12c1b3e0ceef57a2683b3893008
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_empty/ast.snap
@@ -0,0 +1,115 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/vivy_cases/pass/main_empty
+---
+stmts:
+  - - Main:
+        main_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 0
+              line: 1
+              character: 1
+            end_position:
+              bytes: 4
+              line: 1
+              character: 5
+            token_type:
+              type: Symbol
+              symbol: main
+          trailing_trivia:
+            - start_position:
+                bytes: 4
+                line: 1
+                character: 5
+              end_position:
+                bytes: 5
+                line: 1
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        initial_variable:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 5
+              line: 1
+              character: 6
+            end_position:
+              bytes: 11
+              line: 1
+              character: 12
+            token_type:
+              type: StringLiteral
+              literal: init
+              quote_type: Double
+          trailing_trivia:
+            - start_position:
+                bytes: 11
+                line: 1
+                character: 12
+              end_position:
+                bytes: 12
+                line: 1
+                character: 13
+              token_type:
+                type: Whitespace
+                characters: " "
+        begin_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: 15
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        assignements: []
+        write_stmt: ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 15
+              line: 2
+              character: 1
+            end_position:
+              bytes: 18
+              line: 2
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 18
+                line: 2
+                character: 4
+              end_position:
+                bytes: 19
+                line: 2
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_empty/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_empty/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8701206cab7f8eaf66a4c3b1d687c8a72804adf4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_empty/source.lua
@@ -0,0 +1,2 @@
+main "init" do
+end
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_empty/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_empty/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..e5d60f280a2c9818ddb001cd43d177e5dfa66c69
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_empty/tokens.snap
@@ -0,0 +1,104 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/pass/main_empty
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: main
+- 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: StringLiteral
+    literal: init
+    quote_type: Double
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 14
+    line: 1
+    character: 15
+  end_position:
+    bytes: 15
+    line: 1
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 2
+    character: 1
+  end_position:
+    bytes: 18
+    line: 2
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 18
+    line: 2
+    character: 4
+  end_position:
+    bytes: 19
+    line: 2
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 19
+    line: 3
+    character: 1
+  end_position:
+    bytes: 19
+    line: 3
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_returns/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_returns/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..064c435c28c88b3d5dca3c51a08328fe02b2f556
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_returns/ast.snap
@@ -0,0 +1,183 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/vivy_cases/pass/main_returns
+---
+stmts:
+  - - Main:
+        main_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 0
+              line: 1
+              character: 1
+            end_position:
+              bytes: 4
+              line: 1
+              character: 5
+            token_type:
+              type: Symbol
+              symbol: main
+          trailing_trivia:
+            - start_position:
+                bytes: 4
+                line: 1
+                character: 5
+              end_position:
+                bytes: 5
+                line: 1
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        initial_variable:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 5
+              line: 1
+              character: 6
+            end_position:
+              bytes: 11
+              line: 1
+              character: 12
+            token_type:
+              type: StringLiteral
+              literal: init
+              quote_type: Double
+          trailing_trivia:
+            - start_position:
+                bytes: 11
+                line: 1
+                character: 12
+              end_position:
+                bytes: 12
+                line: 1
+                character: 13
+              token_type:
+                type: Whitespace
+                characters: " "
+        begin_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: 15
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        assignements: []
+        write_stmt:
+          write_token:
+            leading_trivia:
+              - start_position:
+                  bytes: 15
+                  line: 2
+                  character: 1
+                end_position:
+                  bytes: 19
+                  line: 2
+                  character: 5
+                token_type:
+                  type: Whitespace
+                  characters: "    "
+            token:
+              start_position:
+                bytes: 19
+                line: 2
+                character: 5
+              end_position:
+                bytes: 25
+                line: 2
+                character: 11
+              token_type:
+                type: Symbol
+                symbol: return
+            trailing_trivia:
+              - start_position:
+                  bytes: 25
+                  line: 2
+                  character: 11
+                end_position:
+                  bytes: 26
+                  line: 2
+                  character: 12
+                token_type:
+                  type: Whitespace
+                  characters: " "
+          begin_token: ~
+          variable_list:
+            pairs:
+              - End:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 26
+                      line: 2
+                      character: 12
+                    end_position:
+                      bytes: 32
+                      line: 2
+                      character: 18
+                    token_type:
+                      type: StringLiteral
+                      literal: init
+                      quote_type: Double
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 32
+                        line: 2
+                        character: 18
+                      end_position:
+                        bytes: 33
+                        line: 2
+                        character: 18
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+          end_token: ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 33
+              line: 3
+              character: 1
+            end_position:
+              bytes: 36
+              line: 3
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 36
+                line: 3
+                character: 4
+              end_position:
+                bytes: 37
+                line: 3
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_returns/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_returns/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..75ac778dd702e2b7d2aac070a439e3a65a46bae6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_returns/source.lua
@@ -0,0 +1,3 @@
+main "init" do
+    return "init"
+end
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_returns/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_returns/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..57984b669a7786ec7cfd7a7d08f17bf48672d3da
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/main_returns/tokens.snap
@@ -0,0 +1,160 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/pass/main_returns
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: main
+- 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: StringLiteral
+    literal: init
+    quote_type: Double
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 14
+    line: 1
+    character: 15
+  end_position:
+    bytes: 15
+    line: 1
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 2
+    character: 1
+  end_position:
+    bytes: 19
+    line: 2
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 19
+    line: 2
+    character: 5
+  end_position:
+    bytes: 25
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 25
+    line: 2
+    character: 11
+  end_position:
+    bytes: 26
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 26
+    line: 2
+    character: 12
+  end_position:
+    bytes: 32
+    line: 2
+    character: 18
+  token_type:
+    type: StringLiteral
+    literal: init
+    quote_type: Double
+- start_position:
+    bytes: 32
+    line: 2
+    character: 18
+  end_position:
+    bytes: 33
+    line: 2
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 33
+    line: 3
+    character: 1
+  end_position:
+    bytes: 36
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 36
+    line: 3
+    character: 4
+  end_position:
+    bytes: 37
+    line: 3
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 37
+    line: 4
+    character: 1
+  end_position:
+    bytes: 37
+    line: 4
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_1/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_1/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..885a4e5595ae516eee89700515d3dc1f46a696cf
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_1/ast.snap
@@ -0,0 +1,160 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/vivy_cases/pass/option_decl_1
+---
+stmts:
+  - - OptionDecl:
+        option_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: option
+          trailing_trivia:
+            - start_position:
+                bytes: 6
+                line: 1
+                character: 7
+              end_position:
+                bytes: 7
+                line: 1
+                character: 8
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 7
+                    line: 1
+                    character: 8
+                  end_position:
+                    bytes: 11
+                    line: 1
+                    character: 12
+                  token_type:
+                    type: Identifier
+                    identifier: titi
+                trailing_trivia: []
+        type_specifiers:
+          - punctuation:
+              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: " "
+            type_info:
+              Basic:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 13
+                    line: 1
+                    character: 14
+                  end_position:
+                    bytes: 19
+                    line: 1
+                    character: 20
+                  token_type:
+                    type: Identifier
+                    identifier: number
+                trailing_trivia:
+                  - start_position:
+                      bytes: 19
+                      line: 1
+                      character: 20
+                    end_position:
+                      bytes: 20
+                      line: 1
+                      character: 21
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        equal_token:
+          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: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 22
+                      line: 1
+                      character: 23
+                    end_position:
+                      bytes: 23
+                      line: 1
+                      character: 24
+                    token_type:
+                      type: Number
+                      text: "1"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 23
+                        line: 1
+                        character: 24
+                      end_position:
+                        bytes: 24
+                        line: 1
+                        character: 24
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_1/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_1/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..1da84c8f702ec3c541621fc47eafde25625a88ff
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_1/source.lua
@@ -0,0 +1 @@
+option titi: number = 1
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_1/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_1/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..5831befa3b1fa0307ad8b2db87d785e7405b0ff4
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_1/tokens.snap
@@ -0,0 +1,136 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/pass/option_decl_1
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: option
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: titi
+- 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: 19
+    line: 1
+    character: 20
+  token_type:
+    type: Identifier
+    identifier: number
+- start_position:
+    bytes: 19
+    line: 1
+    character: 20
+  end_position:
+    bytes: 20
+    line: 1
+    character: 21
+  token_type:
+    type: Whitespace
+    characters: " "
+- 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: Number
+    text: "1"
+- start_position:
+    bytes: 23
+    line: 1
+    character: 24
+  end_position:
+    bytes: 24
+    line: 1
+    character: 24
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 24
+    line: 2
+    character: 1
+  end_position:
+    bytes: 24
+    line: 2
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_2/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_2/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a985e625bee6e253654f260e59183f3351bfa76b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_2/ast.snap
@@ -0,0 +1,117 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/vivy_cases/pass/option_decl_3
+---
+stmts:
+  - - OptionDecl:
+        option_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: option
+          trailing_trivia:
+            - start_position:
+                bytes: 6
+                line: 1
+                character: 7
+              end_position:
+                bytes: 7
+                line: 1
+                character: 8
+              token_type:
+                type: Whitespace
+                characters: " "
+        name_list:
+          pairs:
+            - End:
+                leading_trivia: []
+                token:
+                  start_position:
+                    bytes: 7
+                    line: 1
+                    character: 8
+                  end_position:
+                    bytes: 11
+                    line: 1
+                    character: 12
+                  token_type:
+                    type: Identifier
+                    identifier: titi
+                trailing_trivia:
+                  - start_position:
+                      bytes: 11
+                      line: 1
+                      character: 12
+                    end_position:
+                      bytes: 12
+                      line: 1
+                      character: 13
+                    token_type:
+                      type: Whitespace
+                      characters: " "
+        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: " "
+        expr_list:
+          pairs:
+            - End:
+                Number:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 14
+                      line: 1
+                      character: 15
+                    end_position:
+                      bytes: 15
+                      line: 1
+                      character: 16
+                    token_type:
+                      type: Number
+                      text: "1"
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 15
+                        line: 1
+                        character: 16
+                      end_position:
+                        bytes: 16
+                        line: 1
+                        character: 16
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_2/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_2/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..8264a0bccec332f6abe130fe246909e38960ac91
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_2/source.lua
@@ -0,0 +1 @@
+option titi = 1
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_2/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_2/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..507c559d8cb830158d475c1c833deaba5878d4ae
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/option_decl_2/tokens.snap
@@ -0,0 +1,103 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/pass/option_decl_3
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 6
+    line: 1
+    character: 7
+  token_type:
+    type: Symbol
+    symbol: option
+- start_position:
+    bytes: 6
+    line: 1
+    character: 7
+  end_position:
+    bytes: 7
+    line: 1
+    character: 8
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 7
+    line: 1
+    character: 8
+  end_position:
+    bytes: 11
+    line: 1
+    character: 12
+  token_type:
+    type: Identifier
+    identifier: titi
+- 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: Number
+    text: "1"
+- 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: 16
+    line: 2
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_multiple/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_multiple/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..3ba9b7eab615d3e781c29f943ae76a81d7acd44c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_multiple/ast.snap
@@ -0,0 +1,274 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/vivy_cases/pass/write_multiple
+---
+stmts:
+  - - Main:
+        main_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 0
+              line: 1
+              character: 1
+            end_position:
+              bytes: 4
+              line: 1
+              character: 5
+            token_type:
+              type: Symbol
+              symbol: main
+          trailing_trivia:
+            - start_position:
+                bytes: 4
+                line: 1
+                character: 5
+              end_position:
+                bytes: 5
+                line: 1
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        initial_variable:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 5
+              line: 1
+              character: 6
+            end_position:
+              bytes: 11
+              line: 1
+              character: 12
+            token_type:
+              type: StringLiteral
+              literal: init
+              quote_type: Double
+          trailing_trivia:
+            - start_position:
+                bytes: 11
+                line: 1
+                character: 12
+              end_position:
+                bytes: 12
+                line: 1
+                character: 13
+              token_type:
+                type: Whitespace
+                characters: " "
+        begin_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: 15
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        assignements: []
+        write_stmt:
+          write_token:
+            leading_trivia:
+              - start_position:
+                  bytes: 15
+                  line: 2
+                  character: 1
+                end_position:
+                  bytes: 19
+                  line: 2
+                  character: 5
+                token_type:
+                  type: Whitespace
+                  characters: "    "
+            token:
+              start_position:
+                bytes: 19
+                line: 2
+                character: 5
+              end_position:
+                bytes: 25
+                line: 2
+                character: 11
+              token_type:
+                type: Symbol
+                symbol: return
+            trailing_trivia:
+              - start_position:
+                  bytes: 25
+                  line: 2
+                  character: 11
+                end_position:
+                  bytes: 26
+                  line: 2
+                  character: 12
+                token_type:
+                  type: Whitespace
+                  characters: " "
+          begin_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 26
+                line: 2
+                character: 12
+              end_position:
+                bytes: 27
+                line: 2
+                character: 13
+              token_type:
+                type: Symbol
+                symbol: "{"
+            trailing_trivia:
+              - start_position:
+                  bytes: 27
+                  line: 2
+                  character: 13
+                end_position:
+                  bytes: 28
+                  line: 2
+                  character: 14
+                token_type:
+                  type: Whitespace
+                  characters: " "
+          variable_list:
+            pairs:
+              - Punctuated:
+                  - leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 28
+                        line: 2
+                        character: 14
+                      end_position:
+                        bytes: 34
+                        line: 2
+                        character: 20
+                      token_type:
+                        type: StringLiteral
+                        literal: init
+                        quote_type: Double
+                    trailing_trivia: []
+                  - leading_trivia: []
+                    token:
+                      start_position:
+                        bytes: 34
+                        line: 2
+                        character: 20
+                      end_position:
+                        bytes: 35
+                        line: 2
+                        character: 21
+                      token_type:
+                        type: Symbol
+                        symbol: ","
+                    trailing_trivia:
+                      - start_position:
+                          bytes: 35
+                          line: 2
+                          character: 21
+                        end_position:
+                          bytes: 36
+                          line: 2
+                          character: 22
+                        token_type:
+                          type: Whitespace
+                          characters: " "
+              - End:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 36
+                      line: 2
+                      character: 22
+                    end_position:
+                      bytes: 42
+                      line: 2
+                      character: 28
+                    token_type:
+                      type: StringLiteral
+                      literal: last
+                      quote_type: Double
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 42
+                        line: 2
+                        character: 28
+                      end_position:
+                        bytes: 43
+                        line: 2
+                        character: 29
+                      token_type:
+                        type: Whitespace
+                        characters: " "
+          end_token:
+            leading_trivia: []
+            token:
+              start_position:
+                bytes: 43
+                line: 2
+                character: 29
+              end_position:
+                bytes: 44
+                line: 2
+                character: 30
+              token_type:
+                type: Symbol
+                symbol: "}"
+            trailing_trivia:
+              - start_position:
+                  bytes: 44
+                  line: 2
+                  character: 30
+                end_position:
+                  bytes: 45
+                  line: 2
+                  character: 30
+                token_type:
+                  type: Whitespace
+                  characters: "\n"
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 45
+              line: 3
+              character: 1
+            end_position:
+              bytes: 48
+              line: 3
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 48
+                line: 3
+                character: 4
+              end_position:
+                bytes: 49
+                line: 3
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_multiple/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_multiple/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..2cd2ac93373df91e63550a24d619ab76eaf3e6f0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_multiple/source.lua
@@ -0,0 +1,3 @@
+main "init" do
+    return { "init", "last" }
+end
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_multiple/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_multiple/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..311abb0a31ad681739a318750808f662ff3b2c58
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_multiple/tokens.snap
@@ -0,0 +1,238 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/pass/write_multiple
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: main
+- 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: StringLiteral
+    literal: init
+    quote_type: Double
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 14
+    line: 1
+    character: 15
+  end_position:
+    bytes: 15
+    line: 1
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 2
+    character: 1
+  end_position:
+    bytes: 19
+    line: 2
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 19
+    line: 2
+    character: 5
+  end_position:
+    bytes: 25
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 25
+    line: 2
+    character: 11
+  end_position:
+    bytes: 26
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 26
+    line: 2
+    character: 12
+  end_position:
+    bytes: 27
+    line: 2
+    character: 13
+  token_type:
+    type: Symbol
+    symbol: "{"
+- start_position:
+    bytes: 27
+    line: 2
+    character: 13
+  end_position:
+    bytes: 28
+    line: 2
+    character: 14
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 28
+    line: 2
+    character: 14
+  end_position:
+    bytes: 34
+    line: 2
+    character: 20
+  token_type:
+    type: StringLiteral
+    literal: init
+    quote_type: Double
+- start_position:
+    bytes: 34
+    line: 2
+    character: 20
+  end_position:
+    bytes: 35
+    line: 2
+    character: 21
+  token_type:
+    type: Symbol
+    symbol: ","
+- start_position:
+    bytes: 35
+    line: 2
+    character: 21
+  end_position:
+    bytes: 36
+    line: 2
+    character: 22
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 36
+    line: 2
+    character: 22
+  end_position:
+    bytes: 42
+    line: 2
+    character: 28
+  token_type:
+    type: StringLiteral
+    literal: last
+    quote_type: Double
+- start_position:
+    bytes: 42
+    line: 2
+    character: 28
+  end_position:
+    bytes: 43
+    line: 2
+    character: 29
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 43
+    line: 2
+    character: 29
+  end_position:
+    bytes: 44
+    line: 2
+    character: 30
+  token_type:
+    type: Symbol
+    symbol: "}"
+- start_position:
+    bytes: 44
+    line: 2
+    character: 30
+  end_position:
+    bytes: 45
+    line: 2
+    character: 30
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 45
+    line: 3
+    character: 1
+  end_position:
+    bytes: 48
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 48
+    line: 3
+    character: 4
+  end_position:
+    bytes: 49
+    line: 3
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 49
+    line: 4
+    character: 1
+  end_position:
+    bytes: 49
+    line: 4
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_single/ast.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_single/ast.snap
new file mode 100644
index 0000000000000000000000000000000000000000..4fb5aafd97fa8ab6c7c8825260c40cfc0abcf467
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_single/ast.snap
@@ -0,0 +1,183 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: ast.nodes()
+input_file: vvs_parser/tests/vivy_cases/pass/write_single
+---
+stmts:
+  - - Main:
+        main_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 0
+              line: 1
+              character: 1
+            end_position:
+              bytes: 4
+              line: 1
+              character: 5
+            token_type:
+              type: Symbol
+              symbol: main
+          trailing_trivia:
+            - start_position:
+                bytes: 4
+                line: 1
+                character: 5
+              end_position:
+                bytes: 5
+                line: 1
+                character: 6
+              token_type:
+                type: Whitespace
+                characters: " "
+        initial_variable:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 5
+              line: 1
+              character: 6
+            end_position:
+              bytes: 11
+              line: 1
+              character: 12
+            token_type:
+              type: StringLiteral
+              literal: init
+              quote_type: Double
+          trailing_trivia:
+            - start_position:
+                bytes: 11
+                line: 1
+                character: 12
+              end_position:
+                bytes: 12
+                line: 1
+                character: 13
+              token_type:
+                type: Whitespace
+                characters: " "
+        begin_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: 15
+              token_type:
+                type: Whitespace
+                characters: "\n"
+        assignements: []
+        write_stmt:
+          write_token:
+            leading_trivia:
+              - start_position:
+                  bytes: 15
+                  line: 2
+                  character: 1
+                end_position:
+                  bytes: 19
+                  line: 2
+                  character: 5
+                token_type:
+                  type: Whitespace
+                  characters: "    "
+            token:
+              start_position:
+                bytes: 19
+                line: 2
+                character: 5
+              end_position:
+                bytes: 25
+                line: 2
+                character: 11
+              token_type:
+                type: Symbol
+                symbol: return
+            trailing_trivia:
+              - start_position:
+                  bytes: 25
+                  line: 2
+                  character: 11
+                end_position:
+                  bytes: 26
+                  line: 2
+                  character: 12
+                token_type:
+                  type: Whitespace
+                  characters: " "
+          begin_token: ~
+          variable_list:
+            pairs:
+              - End:
+                  leading_trivia: []
+                  token:
+                    start_position:
+                      bytes: 26
+                      line: 2
+                      character: 12
+                    end_position:
+                      bytes: 32
+                      line: 2
+                      character: 18
+                    token_type:
+                      type: StringLiteral
+                      literal: init
+                      quote_type: Double
+                  trailing_trivia:
+                    - start_position:
+                        bytes: 32
+                        line: 2
+                        character: 18
+                      end_position:
+                        bytes: 33
+                        line: 2
+                        character: 18
+                      token_type:
+                        type: Whitespace
+                        characters: "\n"
+          end_token: ~
+        end_token:
+          leading_trivia: []
+          token:
+            start_position:
+              bytes: 33
+              line: 3
+              character: 1
+            end_position:
+              bytes: 36
+              line: 3
+              character: 4
+            token_type:
+              type: Symbol
+              symbol: end
+          trailing_trivia:
+            - start_position:
+                bytes: 36
+                line: 3
+                character: 4
+              end_position:
+                bytes: 37
+                line: 3
+                character: 4
+              token_type:
+                type: Whitespace
+                characters: "\n"
+    - ~
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_single/source.lua b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_single/source.lua
new file mode 100644
index 0000000000000000000000000000000000000000..75ac778dd702e2b7d2aac070a439e3a65a46bae6
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_single/source.lua
@@ -0,0 +1,3 @@
+main "init" do
+    return "init"
+end
diff --git a/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_single/tokens.snap b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_single/tokens.snap
new file mode 100644
index 0000000000000000000000000000000000000000..a41eb1eda57e3a1e0e771e5ae37292346361b605
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tests/vivy_cases/pass/write_single/tokens.snap
@@ -0,0 +1,160 @@
+---
+source: vvs_parser/tests/pass_cases.rs
+expression: tokens
+input_file: vvs_parser/tests/vivy_cases/pass/write_single
+---
+- start_position:
+    bytes: 0
+    line: 1
+    character: 1
+  end_position:
+    bytes: 4
+    line: 1
+    character: 5
+  token_type:
+    type: Symbol
+    symbol: main
+- 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: StringLiteral
+    literal: init
+    quote_type: Double
+- 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: 14
+    line: 1
+    character: 15
+  token_type:
+    type: Symbol
+    symbol: do
+- start_position:
+    bytes: 14
+    line: 1
+    character: 15
+  end_position:
+    bytes: 15
+    line: 1
+    character: 15
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 15
+    line: 2
+    character: 1
+  end_position:
+    bytes: 19
+    line: 2
+    character: 5
+  token_type:
+    type: Whitespace
+    characters: "    "
+- start_position:
+    bytes: 19
+    line: 2
+    character: 5
+  end_position:
+    bytes: 25
+    line: 2
+    character: 11
+  token_type:
+    type: Symbol
+    symbol: return
+- start_position:
+    bytes: 25
+    line: 2
+    character: 11
+  end_position:
+    bytes: 26
+    line: 2
+    character: 12
+  token_type:
+    type: Whitespace
+    characters: " "
+- start_position:
+    bytes: 26
+    line: 2
+    character: 12
+  end_position:
+    bytes: 32
+    line: 2
+    character: 18
+  token_type:
+    type: StringLiteral
+    literal: init
+    quote_type: Double
+- start_position:
+    bytes: 32
+    line: 2
+    character: 18
+  end_position:
+    bytes: 33
+    line: 2
+    character: 18
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 33
+    line: 3
+    character: 1
+  end_position:
+    bytes: 36
+    line: 3
+    character: 4
+  token_type:
+    type: Symbol
+    symbol: end
+- start_position:
+    bytes: 36
+    line: 3
+    character: 4
+  end_position:
+    bytes: 37
+    line: 3
+    character: 4
+  token_type:
+    type: Whitespace
+    characters: "\n"
+- start_position:
+    bytes: 37
+    line: 4
+    character: 1
+  end_position:
+    bytes: 37
+    line: 4
+    character: 1
+  token_type:
+    type: Eof
diff --git a/src/Rust/vvs_parser/src/tokenizer/lexer.rs b/src/Rust/vvs_parser/src/tokenizer/lexer.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7ce1b9b5677b38ba19e0a4eb1b23cf90a26ddd03
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tokenizer/lexer.rs
@@ -0,0 +1,764 @@
+//! Build the tokens. Don't need for outter world to know the lexer.
+
+use crate::{
+    tokenizer::{
+        Position, StringLiteralQuoteType, Symbol, Token, TokenReference, TokenType, TokenizerError, TokenizerErrorType,
+    },
+    ShortString,
+};
+use serde::{Deserialize, Serialize};
+
+/// 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<LexerResult<TokenReference>>,
+    peek_token: Option<LexerResult<TokenReference>>,
+}
+
+impl Lexer {
+    /// Creates a new Lexer from the given source string.
+    pub fn new(source: &str) -> Self {
+        let mut lexer = Self::new_lazy(source);
+        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, but does not process
+    /// the first token.
+    pub fn new_lazy(source: &str) -> Self {
+        Self { source: LexerSource::new(source), sent_eof: false, next_token: None, peek_token: None }
+    }
+
+    /// Returns the current token.
+    pub fn current(&self) -> Option<&LexerResult<TokenReference>> {
+        self.next_token.as_ref()
+    }
+
+    /// Returns the next token.
+    pub fn peek(&self) -> Option<&LexerResult<TokenReference>> {
+        self.peek_token.as_ref()
+    }
+
+    /// Consumes the current token and returns the next token.
+    pub fn consume(&mut self) -> Option<LexerResult<TokenReference>> {
+        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<Vec<Token>> {
+        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<LexerResult<Token>> {
+        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<TokenizerError>,
+    ) -> Option<LexerResult<Token>> {
+        Some(LexerResult::new(Token { token_type, start_position, end_position: self.source.position() }, errors))
+    }
+
+    fn process_next_with_trivia(&mut self) -> Option<LexerResult<TokenReference>> {
+        let mut leading_trivia = Vec::new();
+        let mut errors: Option<Vec<TokenizerError>> = 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) => {
+                    match errors.as_mut() {
+                        Some(errors) => errors.append(&mut new_errors),
+                        None => 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 };
+        match errors {
+            Some(errors) => Some(LexerResult::Recovered(token, errors)),
+            None => Some(LexerResult::Ok(token)),
+        }
+    }
+
+    fn process_first_with_trivia(&mut self) -> Option<LexerResult<TokenReference>> {
+        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<Token> {
+        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<LexerResult<Token>> {
+        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);
+            }
+        };
+
+        macro_rules! consume {
+            ($first: literal, $second: literal) => {
+                self.source.consume_two($first, $second)
+            };
+            ($first: literal) => {
+                self.source.consume($first)
+            };
+        }
+        macro_rules! create {
+            ($symbol: ident) => {
+                self.create(start_position, TokenType::Symbol { symbol: Symbol::$symbol })
+            };
+        }
+
+        match next {
+            // Identifiers
+            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;
+                    }
+                }
+
+                let token_type = if let Some(symbol) = Symbol::from_str(&identifier) {
+                    TokenType::Symbol { symbol }
+                } else {
+                    TokenType::Identifier { identifier: ShortString::from(identifier) }
+                };
+                self.create(start_position, token_type)
+            }
+
+            // Spaces
+            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"));
+                        continue;
+                    }
+
+                    if next == '\n' {
+                        end_position.bytes += next.len_utf8();
+                        whitespace.push(self.source.next().expect("peeked, but no next"));
+                    } 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;
+                }
+
+                Some(LexerResult::Ok(Token {
+                    token_type: TokenType::Whitespace { characters: ShortString::from(whitespace.as_str()) },
+                    start_position,
+                    end_position,
+                }))
+            }
+
+            // Integers
+            '0' if matches!(self.source.current(), Some('x' | 'X')) => {
+                let hex_character = self.source.next().unwrap();
+                self.read_hex_number(hex_character, start_position)
+            }
+            '0' if matches!(self.source.current(), Some('b' | 'B')) => {
+                let binary_character = self.source.next().unwrap();
+                self.read_binary_number(binary_character, start_position)
+            }
+            initial @ '0' => self.read_number(start_position, initial.to_string()),
+            initial @ ('1'..='9') => self.read_number(start_position, initial.to_string()),
+
+            // Strings
+            quote @ ('"' | '\'') => {
+                let (string, recovered) = self.read_string(quote);
+                let errors = recovered.then(|| TokenizerError {
+                    error: TokenizerErrorType::UnclosedString,
+                    range: (start_position, self.source.position()),
+                });
+                self.create_recovered(start_position, string, errors.into_iter().collect())
+            }
+
+            // Complicated things
+            '[' if matches!(self.source.current(), Some('[' | '=')) => {
+                let start_lexer_position = self.source.lexer_position;
+                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;
+                        create!(LeftBracket)
+                    }
+                }
+            }
+
+            // Consume three
+            '/' if consume!('/', '=') => create!(DoubleSlashEqual),
+            '.' if consume!('.', '=') => create!(TwoDotsEqual),
+
+            // Consume two
+            '/' if consume!('/') => create!(DoubleSlash),
+            '/' if consume!('=') => create!(SlashEqual),
+            ':' if consume!(':') => create!(TwoColons),
+            '+' if consume!('=') => create!(PlusEqual),
+            '*' if consume!('=') => create!(StarEqual),
+            '%' if consume!('=') => create!(PercentEqual),
+            '^' if consume!('=') => create!(CaretEqual),
+            '=' if consume!('=') => create!(TwoEqual),
+            '~' if consume!('>') => create!(DoubleGreaterThan),
+            '~' if consume!('=') => create!(TildeEqual),
+            '<' if consume!('~') => create!(DoubleLesserThan),
+            '<' if consume!('=') => create!(LessThanEqual),
+            '>' if consume!('=') => create!(GreaterThanEqual),
+            '.' if consume!('.') => create!(TwoDots),
+            '-' if consume!('=') => create!(MinusEqual),
+            '-' if consume!('>') => create!(ThinArrow),
+            '-' if consume!('-') => {
+                let (token, recovered) = self.read_comment();
+                let errors = recovered.then(|| TokenizerError {
+                    error: TokenizerErrorType::UnclosedComment,
+                    range: (start_position, self.source.position()),
+                });
+                self.create_recovered(start_position, token, errors.into_iter().collect())
+            }
+            '.' if matches!(self.source.current(), Some('0'..='9')) => {
+                self.read_number(start_position, ".".to_string())
+            }
+
+            // Consume one
+            ':' => create!(Colon),
+            '+' => create!(Plus),
+            '*' => create!(Star),
+            '%' => create!(Percent),
+            '^' => create!(Caret),
+            '=' => create!(Equal),
+            '~' => create!(Tilde),
+            '<' => create!(LessThan),
+            '>' => create!(GreaterThan),
+            '(' => create!(LeftParen),
+            ')' => create!(RightParen),
+            ']' => create!(RightBracket),
+            ';' => create!(Semicolon),
+            '&' => create!(Ampersand),
+            '|' => create!(Pipe),
+            '?' => create!(QuestionMark),
+            '#' => create!(Hash),
+            ',' => create!(Comma),
+            '[' => create!(LeftBracket),
+            '}' => create!(RightBrace),
+            '/' => create!(Slash),
+            '.' => create!(Dot),
+            '-' => create!(Minus),
+            '{' => create!(LeftBrace),
+
+            '\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 },
+            })),
+
+            // Oupsy
+            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<LexerResult<Token>> {
+        let mut hit_decimal = false;
+        while let Some(next) = self.source.current() {
+            if next.is_ascii_digit() || matches!(next, '_') {
+                number.push(self.source.next().expect("peeked, but no next"));
+            } else if matches!(next, '.') && hit_decimal {
+                return Some(self.eat_invalid_number(start_position, number));
+            } else if matches!(next, '.') {
+                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<Token> {
+        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<LexerResult<Token>> {
+        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() && !matches!(next, '_') {
+                break;
+            }
+            number.push(self.source.next().expect("peeked, but no next"));
+        }
+
+        self.create(start_position, TokenType::Number { text: ShortString::from(number) })
+    }
+
+    fn read_hex_number(&mut self, hex_character: char, start_position: Position) -> Option<LexerResult<Token>> {
+        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"))
+                }
+
+                'p' | 'P' if number.len() == 2 => return Some(self.eat_invalid_number(start_position, number)),
+                'p' | 'P' => return self.read_exponent_part(start_position, number),
+                '.' 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"));
+                }
+
+                _ => 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<LexerResult<Token>> {
+        let mut number = String::from_iter(['0', binary_character]);
+
+        while matches!(self.source.current(), Some('0' | '1' | '_')) {
+            number.push(self.source.next().expect("peeked, but no next"))
+        }
+
+        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 Some(next) = self.source.next() else {
+                let token = TokenType::StringLiteral { literal: literal.into(), multi_line_depth: 0, quote_type };
+                return (token, true);
+            };
+
+            match (escape, next) {
+                (true, 'z') => {
+                    escape = false;
+                    z_escaped = true;
+                    literal.push('z');
+                }
+
+                (true, ..) => {
+                    escape = false;
+                    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') => {
+                    let token = TokenType::StringLiteral { literal: literal.into(), multi_line_depth: 0, quote_type };
+                    return (token, true);
+                }
+
+                (false, ..) if next == quote => {
+                    let token = TokenType::StringLiteral { literal: literal.into(), multi_line_depth: 0, quote_type };
+                    return (token, 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 } | MultiLineBodyResult::Unclosed { blocks, body } => {
+                    return (TokenType::MultiLineComment { blocks, comment: body.into() }, false);
+                }
+
+                MultiLineBodyResult::NotMultiLine { blocks } => {
+                    comment.push('[');
+                    (0..blocks).for_each(|_| 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 Some(next) = self.source.next() else {
+                return MultiLineBodyResult::Unclosed { blocks, body };
+            };
+
+            if next == ']' {
+                let mut equal_signs = 0;
+                while equal_signs < blocks {
+                    if !self.source.consume('=') {
+                        body.push(']');
+                        (0..equal_signs).for_each(|_| body.push('='));
+                        continue 'read_comment_char;
+                    }
+                    equal_signs += 1;
+                }
+
+                if self.source.consume(']') {
+                    break;
+                }
+
+                body.push(']');
+                (0..equal_signs).for_each(|_| 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<char>,
+    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<char> {
+        self.source.get(self.lexer_position.index).copied()
+    }
+
+    pub(crate) fn next(&mut self) -> Option<char> {
+        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<char> {
+        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();
+            return true;
+        }
+        false
+    }
+
+    pub(crate) fn consume_two(&mut self, one: char, two: char) -> bool {
+        if self.current() == Some(one) && self.peek() == Some(two) {
+            self.next();
+            self.next();
+            return true;
+        }
+        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, Deserialize, Serialize)]
+pub enum LexerResult<T> {
+    /// The lexer operation was successful.
+    Ok(T),
+
+    /// The lexer operation was unsuccessful, and could not be recovered.
+    Fatal(Vec<TokenizerError>),
+
+    /// The lexer operation was unsuccessful, but some result can be extracted.
+    Recovered(T, Vec<TokenizerError>),
+}
+
+impl<T: std::fmt::Debug> LexerResult<T> {
+    fn new(value: T, errors: Vec<TokenizerError>) -> 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<TokenizerError> {
+        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<TokenizerError> {
+        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/src/Rust/vvs_parser/src/tokenizer/mod.rs b/src/Rust/vvs_parser/src/tokenizer/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e21238a7c4dd171caa135b4c6deb93fb953b0017
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tokenizer/mod.rs
@@ -0,0 +1,8 @@
+//! Used for tokenizing, the process of converting the code to individual tokens. Useful for
+//! getting symbols and manually tokenizing without going using an AST.
+
+mod lexer;
+mod structs;
+
+pub(crate) use lexer::*;
+pub use structs::*;
diff --git a/src/Rust/vvs_parser/src/tokenizer/structs.rs b/src/Rust/vvs_parser/src/tokenizer/structs.rs
new file mode 100644
index 0000000000000000000000000000000000000000..717e145fb380afd477cf8c7c93a50af22992c86a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/tokenizer/structs.rs
@@ -0,0 +1,719 @@
+use crate::{
+    tokenizer::{Lexer, LexerResult},
+    visitors::{Visit, VisitMut, Visitor, VisitorMut},
+    ShortString,
+};
+use derive_more::{Deref, Display};
+use serde::{Deserialize, Serialize};
+use std::{cmp::Ordering, fmt};
+
+macro_rules! symbol {
+    {
+        $(#[$symbol_meta:meta])*
+        pub enum Symbol {
+            $(
+                $(#[$meta:meta])*
+                $name:ident => $string:literal,
+            )+
+        }
+    } => {
+        paste::paste! {
+            $(#[$symbol_meta])*
+            #[derive(Display)]
+            pub enum Symbol {
+                $(
+                    $(#[$meta])*
+                    #[serde(rename = $string)]
+                    #[display("{}", $string)]
+                    $name,
+                )+
+            }
+
+            impl Symbol {
+                /// Given just the symbol text (no whitespace), returns the associated symbol, if
+                /// it exists. If you want a TokenReference instead, consider [TokenReference::symbol].
+                #[allow(clippy::should_implement_trait)]
+                pub fn from_str(symbol: &str) -> Option<Self> {
+                    match symbol {
+                        $($string => { Some(Self::$name) },)+
+                        _ => None,
+                    }
+                }
+            }
+
+        }
+    };
+}
+
+symbol! {
+    #[non_exhaustive]
+    #[allow(missing_docs)]
+    #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
+    /// 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",
+        ElIf     => "elif",
+        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",
+        Import   => "import",
+        Job      => "job",
+        Option   => "option",
+        Main     => "main",
+        Yield    => "yield",
+
+        PlusEqual        => "+=",
+        MinusEqual       => "-=",
+        StarEqual        => "*=",
+        SlashEqual       => "/=",
+        DoubleSlashEqual => "//=",
+        PercentEqual     => "%=",
+        CaretEqual       => "^=",
+        TwoDotsEqual     => "..=",
+
+        Ampersand         => "&",
+        ThinArrow         => "->",
+        TwoColons         => "::",
+        Caret             => "^",
+        Colon             => ":",
+        Comma             => ",",
+        Dot               => ".",
+        TwoDots           => "..",
+        Equal             => "=",
+        TwoEqual          => "==",
+        GreaterThan       => ">",
+        GreaterThanEqual  => ">=",
+        Hash              => "#",
+        LeftBrace         => "{",
+        LeftBracket       => "[",
+        LeftParen         => "(",
+        LessThan          => "<",
+        LessThanEqual     => "<=",
+        Minus             => "-",
+        Percent           => "%",
+        Pipe              => "|",
+        Plus              => "+",
+        QuestionMark      => "?",
+        RightBrace        => "}",
+        RightBracket      => "]",
+        RightParen        => ")",
+        Semicolon         => ";",
+        Slash             => "/",
+        DoubleSlash       => "//",
+        Star              => "*",
+        Tilde             => "~",
+        TildeEqual        => "~=",
+        DoubleGreaterThan => "~>",
+        DoubleLesserThan  => "<~",
+    }
+}
+
+/// The possible errors that can happen while tokenizing.
+#[derive(Clone, Debug, PartialEq, Eq, Display, Deserialize, Serialize)]
+pub enum TokenizerErrorType {
+    /// An unclosed multi-line comment was found
+    #[display("unclosed comment")]
+    UnclosedComment,
+
+    /// An unclosed string was found
+    #[display("unclosed string")]
+    UnclosedString,
+
+    /// An invalid number was found
+    #[display("invalid number")]
+    InvalidNumber,
+
+    /// An unexpected token was found
+    #[display("unexpected character {_0}")]
+    UnexpectedToken(char),
+
+    /// Symbol passed is not valid
+    /// Returned from [`TokenReference::symbol`]
+    #[display("invalid symbol {_0}")]
+    InvalidSymbol(String),
+}
+
+/// Used by serde
+fn is_usize_zero(input: &usize) -> bool {
+    *input == 0
+}
+
+/// The type of tokens in parsed code
+#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
+#[serde(tag = "type")]
+#[non_exhaustive]
+pub enum TokenType {
+    /// End of file, should always be the very last token
+    Eof,
+
+    /// An identifier, such as `foo`
+    Identifier {
+        /// The identifier itself
+        identifier: ShortString,
+    },
+
+    /// A multi line comment in the format of `--[[ comment ]]`
+    MultiLineComment {
+        /// Number of equals signs, if any, for the multi line comment
+        /// For example, `--[=[` would have a `blocks` value of `1`
+        blocks: usize,
+
+        /// The comment itself, ignoring opening and closing tags
+        comment: ShortString,
+    },
+
+    /// A literal number, such as `3.3`
+    Number {
+        /// The text representing the number, includes details such as `0x`
+        text: ShortString,
+    },
+
+    /// A shebang line
+    Shebang {
+        /// The shebang line itself
+        line: ShortString,
+    },
+
+    /// A single line comment, such as `-- comment`
+    SingleLineComment {
+        /// The comment, ignoring initial `--`
+        comment: ShortString,
+    },
+
+    /// A literal string, such as "Hello, world"
+    StringLiteral {
+        /// The literal itself, ignoring quotation marks
+        literal: ShortString,
+
+        #[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_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,
+    },
+
+    /// A [`Symbol`], such as `local` or `+`
+    Symbol {
+        /// The symbol itself
+        symbol: Symbol,
+    },
+
+    /// Whitespace, such as tabs or new lines
+    Whitespace {
+        /// Characters consisting of the whitespace
+        characters: ShortString,
+    },
+}
+
+impl TokenType {
+    /// 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 {
+        use TokenType::*;
+        matches!(self, Shebang { .. } | SingleLineComment { .. } | MultiLineComment { .. } | Whitespace { .. })
+    }
+
+    /// Returns the kind of the token type.
+    ///
+    /// ```rust
+    /// use vvs_parser::prelude::ast::*;
+    ///
+    /// assert_eq!(
+    ///     TokenType::Identifier {
+    ///         identifier: ShortString::new("hello")
+    ///     }.kind(),
+    ///     TokenKind::Identifier,
+    /// );
+    /// ```
+    pub fn kind(&self) -> TokenKind {
+        match self {
+            TokenType::Eof => TokenKind::Eof,
+            TokenType::Identifier { .. } => TokenKind::Identifier,
+            TokenType::MultiLineComment { .. } => TokenKind::MultiLineComment,
+            TokenType::Number { .. } => TokenKind::Number,
+            TokenType::Shebang { .. } => TokenKind::Shebang,
+            TokenType::SingleLineComment { .. } => TokenKind::SingleLineComment,
+            TokenType::StringLiteral { .. } => TokenKind::StringLiteral,
+            TokenType::Symbol { .. } => TokenKind::Symbol,
+            TokenType::Whitespace { .. } => TokenKind::Whitespace,
+        }
+    }
+
+    /// Returns a whitespace `TokenType` consisting of spaces
+    pub fn spaces(spaces: usize) -> Self {
+        TokenType::Whitespace { characters: " ".repeat(spaces).into() }
+    }
+
+    /// Returns a whitespace `TokenType` consisting of tabs
+    pub fn tabs(tabs: usize) -> Self {
+        TokenType::Whitespace { characters: "\t".repeat(tabs).into() }
+    }
+
+    /// Try to convert the token into a string slice. If it's not possible returns [None]. In the
+    /// [TokenType::StringLiteral] case, we try to unquote the string.
+    pub fn to_str(&self) -> Option<&str> {
+        use StringLiteralQuoteType::*;
+        match self {
+            TokenType::Identifier { identifier } => Some(identifier),
+            TokenType::StringLiteral { literal, quote_type: Double, .. } => Some(literal.trim_matches('\"').trim()),
+            TokenType::StringLiteral { literal, quote_type: Single, .. } => Some(literal.trim_matches('\'').trim()),
+            TokenType::StringLiteral { literal, quote_type: Brackets, multi_line_depth } => {
+                todo!("use {multi_line_depth} to get ride of the [==[ or the [[ or the [=[ in {literal}")
+            }
+            _ => None,
+        }
+    }
+
+    /// Same as [TokenType::to_str] but panics instead of returning [None].
+    pub fn as_str(&self) -> &str {
+        self.to_str().unwrap()
+    }
+}
+
+impl fmt::Display for TokenType {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            TokenType::Eof => Ok(()),
+            TokenType::Number { text } => text.fmt(formatter),
+            TokenType::Identifier { identifier } => identifier.fmt(formatter),
+            TokenType::MultiLineComment { blocks, comment } => {
+                write!(formatter, "--[{0}[{1}]{0}]", "=".repeat(*blocks), comment)
+            }
+            TokenType::Shebang { line } => line.fmt(formatter),
+            TokenType::SingleLineComment { comment } => write!(formatter, "--{comment}"),
+            TokenType::StringLiteral { literal, multi_line_depth, quote_type } => {
+                if *quote_type == StringLiteralQuoteType::Brackets {
+                    write!(formatter, "[{0}[{1}]{0}]", "=".repeat(*multi_line_depth), literal)
+                } else {
+                    write!(formatter, "{0}{1}{0}", quote_type.to_string(), literal)
+                }
+            }
+            TokenType::Symbol { symbol } => symbol.fmt(formatter),
+            TokenType::Whitespace { characters } => characters.fmt(formatter),
+        }
+    }
+}
+
+/// The kind of token. Contains no additional data.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[non_exhaustive]
+pub enum TokenKind {
+    /// End of file, should always be the very last token
+    Eof,
+
+    /// An identifier, such as `foo`
+    Identifier,
+
+    /// A multi line comment in the format of `--[[ comment ]]`
+    MultiLineComment,
+
+    /// A literal number, such as `3.3`
+    Number,
+
+    /// The shebang line
+    Shebang,
+
+    /// A single line comment, such as `-- comment`
+    SingleLineComment,
+
+    /// A literal string, such as "Hello, world"
+    StringLiteral,
+
+    /// A [`Symbol`], such as `local` or `+`
+    Symbol,
+
+    /// Whitespace, such as tabs or new lines
+    Whitespace,
+}
+
+/// A token such consisting of its [`Position`] and a [`TokenType`]
+#[derive(Clone, Debug, Eq, PartialEq, Display, Deserialize, Serialize)]
+#[display("{token_type}")]
+pub struct Token {
+    pub(crate) start_position: Position,
+    pub(crate) end_position: Position,
+    pub(crate) token_type: TokenType,
+}
+
+impl Token {
+    /// Creates a token with a zero position
+    pub const fn new(token_type: TokenType) -> Token {
+        Token { start_position: Position::new(), end_position: Position::new(), token_type }
+    }
+
+    /// The position a token begins at
+    pub fn start_position(&self) -> Position {
+        self.start_position
+    }
+
+    /// The position a token ends at
+    pub fn end_position(&self) -> Position {
+        self.end_position
+    }
+
+    /// The type of token as well as the data needed to represent it
+    /// If you don't need any other information, use [`token_kind`](Token::token_kind) instead.
+    pub fn token_type(&self) -> &TokenType {
+        &self.token_type
+    }
+
+    /// The kind of token with no additional data.
+    /// If you need any information such as idenitfier names, use [`token_type`](Token::token_type) instead.
+    pub fn token_kind(&self) -> TokenKind {
+        self.token_type().kind()
+    }
+}
+
+impl Ord for Token {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.start_position().cmp(&other.start_position())
+    }
+}
+
+impl PartialOrd for Token {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Visit for Token {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_token(self);
+        match self.token_kind() {
+            TokenKind::Eof => {}
+            TokenKind::Identifier => visitor.visit_identifier(self),
+            TokenKind::MultiLineComment => visitor.visit_multi_line_comment(self),
+            TokenKind::Number => visitor.visit_number(self),
+            TokenKind::Shebang => {}
+            TokenKind::SingleLineComment => visitor.visit_single_line_comment(self),
+            TokenKind::StringLiteral => visitor.visit_string_literal(self),
+            TokenKind::Symbol => visitor.visit_symbol(self),
+            TokenKind::Whitespace => visitor.visit_whitespace(self),
+        }
+    }
+}
+
+impl VisitMut for Token {
+    fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self {
+        let token = visitor.visit_token(self);
+        match token.token_kind() {
+            TokenKind::Eof => token,
+            TokenKind::Identifier => visitor.visit_identifier(token),
+            TokenKind::MultiLineComment => visitor.visit_multi_line_comment(token),
+            TokenKind::Number => visitor.visit_number(token),
+            TokenKind::Shebang => token,
+            TokenKind::SingleLineComment => visitor.visit_single_line_comment(token),
+            TokenKind::StringLiteral => visitor.visit_string_literal(token),
+            TokenKind::Symbol => visitor.visit_symbol(token),
+            TokenKind::Whitespace => visitor.visit_whitespace(token),
+        }
+    }
+}
+
+/// A reference to a token used by Ast's.
+/// Dereferences to a [`Token`]
+#[derive(Clone, Debug, Deref, Deserialize, Serialize)]
+pub struct TokenReference {
+    pub(crate) leading_trivia: Vec<Token>,
+    #[deref]
+    pub(crate) token: Token,
+    pub(crate) trailing_trivia: Vec<Token>,
+}
+
+impl TokenReference {
+    /// Creates a TokenReference from leading/trailing trivia as well as the leading token
+    pub const fn new(leading_trivia: Vec<Token>, token: Token, trailing_trivia: Vec<Token>) -> Self {
+        Self { leading_trivia, token, trailing_trivia }
+    }
+
+    /// Returns a symbol with the leading and trailing whitespace
+    /// Only whitespace is supported
+    /// ```rust
+    /// # use vvs_parser::prelude::{ast::*, *};
+    /// # fn main() -> Result<(), Box<TokenizerErrorType>> {
+    /// let symbol = TokenReference::symbol("\nreturn ")?;
+    /// assert_eq!(symbol.leading_trivia().next().unwrap().to_string(), "\n");
+    /// assert_eq!(symbol.token().token_type(), &TokenType::Symbol { symbol: Symbol::Return });
+    /// assert_eq!(symbol.trailing_trivia().next().unwrap().to_string(), " ");
+    /// assert!(TokenReference::symbol("isnt whitespace").is_err());
+    /// assert!(TokenReference::symbol(" notasymbol ").is_err());
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub fn symbol(text: &str) -> Result<Self, TokenizerErrorType> {
+        let mut lexer = Lexer::new_lazy(text);
+        let mut leading_trivia = Vec::new();
+        let symbol;
+        loop {
+            match lexer.process_next().expect("we shouldn't have hit eof") {
+                LexerResult::Ok(token @ Token { token_type: TokenType::Whitespace { .. }, .. }) => {
+                    leading_trivia.push(token)
+                }
+                LexerResult::Ok(token @ Token { token_type: TokenType::Symbol { .. }, .. }) => {
+                    symbol = token;
+                    break;
+                }
+                LexerResult::Ok(Token { token_type: TokenType::Eof, .. }) => {
+                    return Err(TokenizerErrorType::InvalidSymbol(text.to_owned()))
+                }
+                LexerResult::Ok(token) => {
+                    return Err(TokenizerErrorType::UnexpectedToken(token.to_string().chars().next().unwrap()))
+                }
+                LexerResult::Fatal(mut errors) | LexerResult::Recovered(_, mut errors) => {
+                    return Err(errors.remove(0).error);
+                }
+            }
+        }
+
+        let mut trailing_trivia = Vec::new();
+        loop {
+            match lexer.process_next().expect("we shouldn't have hit eof") {
+                LexerResult::Ok(token @ Token { token_type: TokenType::Whitespace { .. }, .. }) => {
+                    trailing_trivia.push(token);
+                }
+                LexerResult::Ok(Token { token_type: TokenType::Eof, .. }) => break,
+                LexerResult::Ok(token) => {
+                    return Err(TokenizerErrorType::UnexpectedToken(token.to_string().chars().next().unwrap()));
+                }
+                LexerResult::Fatal(mut errors) | LexerResult::Recovered(_, mut errors) => {
+                    return Err(errors.remove(0).error);
+                }
+            }
+        }
+
+        Ok(TokenReference { leading_trivia, token: symbol, trailing_trivia })
+    }
+
+    pub(crate) fn basic_symbol(text: &str) -> Self {
+        TokenReference::symbol(text).unwrap()
+    }
+
+    /// Returns the inner token.
+    pub fn token(&self) -> &Token {
+        &self.token
+    }
+
+    /// Returns the leading trivia
+    pub fn leading_trivia(&self) -> impl Iterator<Item = &Token> {
+        self.leading_trivia.iter()
+    }
+
+    /// Returns the trailing trivia
+    pub fn trailing_trivia(&self) -> impl Iterator<Item = &Token> {
+        self.trailing_trivia.iter()
+    }
+
+    /// Creates a clone of the current TokenReference with the new inner token, preserving trivia.
+    pub fn with_token(&self, token: Token) -> Self {
+        Self { token, leading_trivia: self.leading_trivia.clone(), 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 }
+    }
+
+    /// Checks if the token is in the given symbol set
+    pub fn in_symbols(&self, symbols: &[Symbol]) -> bool {
+        symbols.iter().any(|&symbol| self.is_symbol(symbol))
+    }
+
+    /// Checks if the token is of the given kind
+    pub fn is_kind(&self, kind: TokenKind) -> bool {
+        self.token.token_kind() == kind
+    }
+}
+
+impl std::borrow::Borrow<Token> for &TokenReference {
+    fn borrow(&self) -> &Token {
+        self
+    }
+}
+
+impl fmt::Display for TokenReference {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        for trivia in &self.leading_trivia {
+            trivia.fmt(formatter)?;
+        }
+        self.token.fmt(formatter)?;
+        for trivia in &self.trailing_trivia {
+            trivia.fmt(formatter)?;
+        }
+        Ok(())
+    }
+}
+
+impl From<&TokenReference> for TokenReference {
+    fn from(value: &TokenReference) -> Self {
+        value.clone()
+    }
+}
+
+impl PartialEq<Self> for TokenReference {
+    fn eq(&self, other: &Self) -> bool {
+        (**self).eq(other)
+            && self.leading_trivia == other.leading_trivia
+            && self.trailing_trivia == other.trailing_trivia
+    }
+}
+
+impl Eq for TokenReference {}
+
+impl Ord for TokenReference {
+    fn cmp(&self, other: &Self) -> Ordering {
+        (**self).cmp(&**other)
+    }
+}
+
+impl PartialOrd for TokenReference {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Visit for TokenReference {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        visitor.visit_token(self);
+        if matches!(self.token().token_kind(), TokenKind::Eof) {
+            visitor.visit_eof(self);
+        }
+        self.leading_trivia.visit(visitor);
+        self.token.visit(visitor);
+        self.trailing_trivia.visit(visitor);
+    }
+}
+
+impl VisitMut for TokenReference {
+    fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self {
+        let mut token_reference = visitor.visit_token_reference(self);
+        if matches!(token_reference.token().token_kind(), TokenKind::Eof) {
+            token_reference = visitor.visit_eof(token_reference);
+        }
+        token_reference.leading_trivia = token_reference.leading_trivia.visit_mut(visitor);
+        token_reference.token = token_reference.token.visit_mut(visitor);
+        token_reference.trailing_trivia = token_reference.trailing_trivia.visit_mut(visitor);
+        token_reference
+    }
+}
+
+/// Used to represent exact positions of tokens in code
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
+pub struct Position {
+    pub(crate) bytes: usize,
+    pub(crate) line: usize,
+    pub(crate) character: usize,
+}
+
+impl Position {
+    /// Create a new default position. Can be called in const context.
+    pub const fn new() -> Self {
+        Self { bytes: 0, line: 0, character: 0 }
+    }
+
+    /// How many bytes, ignoring lines, it would take to find this position
+    pub fn bytes(self) -> usize {
+        self.bytes
+    }
+
+    /// Index of the character on the line for this position
+    pub fn character(self) -> usize {
+        self.character
+    }
+
+    /// Line the position lies on
+    pub fn line(self) -> usize {
+        self.line
+    }
+}
+
+impl Ord for Position {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.bytes.cmp(&other.bytes)
+    }
+}
+
+impl PartialOrd for Position {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+/// The types of quotes used in a Lua string
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
+#[non_exhaustive]
+pub enum StringLiteralQuoteType {
+    /// Strings formatted \[\[with brackets\]\]
+    Brackets,
+
+    /// Strings formatted "with double quotes"
+    Double,
+
+    /// Strings formatted 'with single quotes'
+    Single,
+}
+
+impl fmt::Display for StringLiteralQuoteType {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            // 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 => write!(f, "\""),
+            StringLiteralQuoteType::Single => write!(f, "'"),
+        }
+    }
+}
+
+/// Information about an error that occurs while tokenizing
+#[derive(Clone, Debug, PartialEq, Eq, Display, Deserialize, Serialize)]
+#[display("{error} ({}:{} to {}:{})",
+    range.0.line, range.0.character, range.1.line, range.1.character
+)]
+pub struct TokenizerError {
+    /// The type of error
+    pub(crate) error: TokenizerErrorType,
+
+    /// The range of the token that caused the error
+    pub(crate) range: (Position, Position),
+}
+
+impl TokenizerError {
+    /// The type of error
+    pub fn error(&self) -> &TokenizerErrorType {
+        &self.error
+    }
+
+    /// The position of the first token that caused the error
+    pub fn position(&self) -> Position {
+        self.range.0
+    }
+
+    /// The range of the token that caused the error
+    pub fn range(&self) -> (Position, Position) {
+        self.range
+    }
+}
+
+impl std::error::Error for TokenizerError {}
diff --git a/src/Rust/vvs_parser/src/traits.rs b/src/Rust/vvs_parser/src/traits.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6567e0e1519460294863d18b34c6bce32aa0c70e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/traits.rs
@@ -0,0 +1,85 @@
+#![allow(dead_code)]
+
+//! Usefull traits for the vivy parser crate.
+
+use std::borrow::Cow;
+
+/// Extensions for the [Result] enum.
+pub trait ResultExtension<T, E> {
+    /// Inspect the value part of the result and transform it with a callback.
+    fn inspect_mut(self, cb: impl FnOnce(&mut T)) -> Self;
+
+    /// Inspect the error part of the result and transform it with a callback.
+    fn inspect_err_mut(self, cb: impl FnOnce(&mut E)) -> Self;
+}
+
+impl<T, E> ResultExtension<T, E> for Result<T, E> {
+    fn inspect_err_mut(mut self, cb: impl FnOnce(&mut E)) -> Self {
+        if let Err(error) = &mut self {
+            cb(error);
+        }
+        self
+    }
+
+    fn inspect_mut(mut self, cb: impl FnOnce(&mut T)) -> Self {
+        if let Ok(value) = &mut self {
+            cb(value);
+        }
+        self
+    }
+}
+
+/// Extensions for the [Vec] struct.
+pub trait VecExtension<T> {
+    /// Push an item at the end of the vector and returns the result.
+    fn join(self, value: T) -> Self;
+
+    /// Returns the without the elements as selected by the callback.
+    fn without(self, cb: impl FnMut(&T) -> bool) -> Self;
+}
+
+impl<T> VecExtension<T> for Vec<T> {
+    fn join(mut self, value: T) -> Self {
+        self.push(value);
+        self
+    }
+
+    fn without(mut self, cb: impl FnMut(&T) -> bool) -> Self {
+        self.retain(cb);
+        self
+    }
+}
+
+impl<T> VecExtension<T> for std::collections::VecDeque<T> {
+    fn join(mut self, value: T) -> Self {
+        self.push_back(value);
+        self
+    }
+
+    fn without(mut self, cb: impl FnMut(&T) -> bool) -> Self {
+        self.retain(cb);
+        self
+    }
+}
+
+/// Like [Default], but we get a reference to a static instead.
+pub trait DefaultRef {
+    fn default_ref() -> &'static Self;
+}
+
+/// A string that can be lazy.
+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<F: FnOnce() -> String> MaybeLazyString for F {
+    fn to_str(self) -> Cow<'static, str> {
+        Cow::Owned(self())
+    }
+}
diff --git a/src/Rust/vvs_parser/src/util.rs b/src/Rust/vvs_parser/src/util.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cb6059f6a142794ce18d775d9b6bd969a94e495c
--- /dev/null
+++ b/src/Rust/vvs_parser/src/util.rs
@@ -0,0 +1,111 @@
+use crate::{ast::Punctuated, tokenizer::TokenReference};
+use std::{
+    borrow::Borrow,
+    fmt::{Display, Write},
+};
+
+// Check if the vector is empty or full of None's
+#[allow(clippy::ptr_arg)]
+pub fn empty_optional_vector<T>(vec: &Vec<Option<T>>) -> bool {
+    vec.iter().all(Option::is_none)
+}
+
+pub fn display_option<T: Display, O: Borrow<Option<T>>>(option: O) -> String {
+    match option.borrow() {
+        Some(x) => x.to_string(),
+        None => "".to_string(),
+    }
+}
+
+pub fn display_optional_punctuated<T: Display>(pair: &(T, Option<TokenReference>)) -> String {
+    format!("{}{}", pair.0, display_option(&pair.1))
+}
+
+pub fn display_optional_punctuated_vec<T: Display>(vec: &[(T, Option<TokenReference>)]) -> String {
+    let mut string = String::new();
+    for pair in vec {
+        string.push_str(&display_optional_punctuated(pair));
+    }
+    string
+}
+
+pub fn join_vec<T: Display, V: AsRef<[T]>>(vec: V) -> String {
+    let mut string = String::new();
+    for item in vec.as_ref() {
+        string.push_str(&item.to_string());
+    }
+    string
+}
+
+pub fn join_type_specifiers<I: IntoIterator<Item = Option<T2>>, T1: Display, T2: Display>(
+    parameters: &Punctuated<T1>,
+    type_specifiers: I,
+) -> String {
+    let mut string = String::new();
+
+    for (parameter, type_specifier) in parameters
+        .pairs()
+        .zip(type_specifiers.into_iter().chain(std::iter::repeat_with(|| None)))
+    {
+        let _ = write!(
+            string,
+            "{}{}{}",
+            parameter.value(),
+            display_option(type_specifier),
+            display_option(parameter.punctuation())
+        );
+    }
+
+    string
+}
+
+pub fn join_iterators<
+    I1: IntoIterator<Item = Option<T2>>,
+    I2: IntoIterator<Item = Option<T3>>,
+    T1: Display,
+    T2: Display,
+    T3: Display,
+>(
+    parameters: &Punctuated<T1>,
+    first_iterator: I1,
+    second_iterator: I2,
+) -> String {
+    let mut string = String::new();
+
+    for ((name, item1), item2) in parameters
+        .pairs()
+        .zip(first_iterator.into_iter())
+        .zip(second_iterator.into_iter())
+    {
+        let _ = write!(
+            string,
+            "{}{}{}{}",
+            name.value(),
+            display_option(item1),
+            display_option(item2),
+            display_option(name.punctuation())
+        );
+    }
+
+    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;
+            $(
+                if $lua_version.[<has_ $version>]() {
+                    version_passes = true;
+                }
+            )+
+            version_passes
+        }}
+    };
+}
diff --git a/src/Rust/vvs_parser/src/visitors.rs b/src/Rust/vvs_parser/src/visitors.rs
new file mode 100644
index 0000000000000000000000000000000000000000..45a88c68047d74dfb748cb282b0d8d576b5fdc88
--- /dev/null
+++ b/src/Rust/vvs_parser/src/visitors.rs
@@ -0,0 +1,227 @@
+//! Used to create visitors that recurse through [`Ast`](ast::Ast) nodes.
+
+use crate::{
+    ast::*,
+    private::Sealed,
+    tokenizer::{Token, TokenReference},
+};
+
+macro_rules! create_visitor {
+    (ast: {
+        $($visit_name:ident => $ast_type:ident,)+
+    }, token: {
+        $($visit_token:ident,)+
+    }) => {
+        /// A trait that implements functions to listen for specific nodes/tokens.
+        /// Unlike [`VisitorMut`], nodes/tokens passed are immutable.
+        pub trait Visitor {
+            /// Visit the nodes of an [`Ast`](crate::ast::Ast)
+            fn visit_ast(&mut self, ast: &Ast) where Self: Sized {
+                ast.nodes().visit(self);
+                ast.eof().visit(self);
+            }
+
+            paste::item! {
+                $(
+                    #[allow(missing_docs)]
+                    fn $visit_name(&mut self, _node: &$ast_type) { }
+                    #[allow(missing_docs)]
+                    fn [<$visit_name _end>](&mut self, _node: &$ast_type) { }
+                )+
+            }
+
+            $(
+                #[allow(missing_docs)]
+                fn $visit_token(&mut self, _token: &Token) { }
+            )+
+        }
+
+        /// A trait that implements functions to listen for specific nodes/tokens.
+        /// Unlike [`Visitor`], nodes/tokens passed are mutable.
+        pub trait VisitorMut {
+            /// Visit the nodes of an [`Ast`](crate::ast::Ast)
+            fn visit_ast(&mut self, ast: Ast) -> Ast where Self: Sized {
+                // TODO: Visit tokens?
+                let eof = ast.eof().to_owned();
+                let nodes = ast.nodes.visit_mut(self);
+
+                Ast {
+                    nodes,
+                    // Everything gets cloned with this visitor, so there's no original tokens
+                    eof: self.visit_eof(eof),
+                }
+            }
+
+            paste::item! { $(
+                #[allow(missing_docs)]
+                fn $visit_name(&mut self, node: $ast_type) -> $ast_type {
+                    node
+                }
+
+                #[allow(missing_docs)]
+                fn [<$visit_name _end>](&mut self, node: $ast_type) -> $ast_type {
+                    node
+                }
+            )+ }
+
+            $(
+                #[allow(missing_docs)]
+                fn $visit_token(&mut self, token: Token) -> Token {
+                    token
+                }
+            )+
+        }
+    };
+}
+
+#[doc(hidden)]
+pub trait Visit: Sealed {
+    fn visit<V: Visitor>(&self, visitor: &mut V);
+}
+
+#[doc(hidden)]
+pub trait VisitMut: Sealed
+where
+    Self: Sized,
+{
+    fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self;
+}
+
+impl<T: Visit> Visit for &T {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        (**self).visit(visitor);
+    }
+}
+
+impl<T: Visit> Visit for &mut T {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        (**self).visit(visitor);
+    }
+}
+
+impl<T: Visit> Visit for Vec<T> {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        for item in self {
+            item.visit(visitor);
+        }
+    }
+}
+
+impl<T: VisitMut> VisitMut for Vec<T> {
+    fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self {
+        self.into_iter().map(|item| item.visit_mut(visitor)).collect()
+    }
+}
+
+impl<T: Visit> Visit for Option<T> {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        if let Some(item) = self {
+            item.visit(visitor);
+        }
+    }
+}
+
+impl<T: VisitMut> VisitMut for Option<T> {
+    fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self {
+        self.map(|item| item.visit_mut(visitor))
+    }
+}
+
+impl<A: Visit, B: Visit> Visit for (A, B) {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        self.0.visit(visitor);
+        self.1.visit(visitor);
+    }
+}
+
+impl<A: VisitMut, B: VisitMut> VisitMut for (A, B) {
+    fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self {
+        (self.0.visit_mut(visitor), self.1.visit_mut(visitor))
+    }
+}
+
+impl<T: Visit> Visit for Box<T> {
+    fn visit<V: Visitor>(&self, visitor: &mut V) {
+        (**self).visit(visitor);
+    }
+}
+
+impl<T: VisitMut> VisitMut for Box<T> {
+    fn visit_mut<V: VisitorMut>(self, visitor: &mut V) -> Self {
+        Box::new((*self).visit_mut(visitor))
+    }
+}
+
+create_visitor!(ast: {
+    visit_anonymous_call => FunctionArgs,
+    visit_assignment => Assignment,
+    visit_block => Block,
+    visit_call => Call,
+    visit_contained_span => ContainedSpan,
+    visit_do => Do,
+    visit_else_if => ElseIf,
+    visit_eof => TokenReference,
+    visit_expression => Expression,
+    visit_field => Field,
+    visit_function_args => FunctionArgs,
+    visit_function_body => FunctionBody,
+    visit_function_call => FunctionCall,
+    visit_function_declaration => FunctionDeclaration,
+    visit_function_name => FunctionName,
+    visit_generic_for => GenericFor,
+    visit_if => If,
+    visit_index => Index,
+    visit_local_assignment => LocalAssignment,
+    visit_local_function => LocalFunction,
+    visit_last_stmt => LastStmt,
+    visit_method_call => MethodCall,
+    visit_numeric_for => NumericFor,
+    visit_parameter => Parameter,
+    visit_prefix => Prefix,
+    visit_return => Return,
+    visit_repeat => Repeat,
+    visit_stmt => Stmt,
+    visit_suffix => Suffix,
+    visit_table_constructor => TableConstructor,
+    visit_token_reference => TokenReference,
+    visit_un_op => UnOp,
+    visit_var => Var,
+    visit_var_expression => VarExpression,
+    visit_while => While,
+    visit_compound_assignment => CompoundAssignment,
+    visit_compound_op => CompoundOp,
+    visit_else_if_expression => ElseIfExpression,
+    visit_if_expression => IfExpression,
+
+    // Types
+    visit_type_argument => TypeArgument,
+    visit_type_assertion => TypeAssertion,
+    visit_type_declaration => TypeDeclaration,
+    visit_type_field => TypeField,
+    visit_type_field_key => TypeFieldKey,
+    visit_type_info => TypeInfo,
+    visit_type_specifier => TypeSpecifier,
+
+    // Lua >=5.2
+    visit_attribute => Attribute,
+
+    // Vivy
+    visit_main => Main,
+    visit_write => Write,
+    visit_yield => Yield,
+    visit_import => Import,
+    visit_call_list => CallList,
+    visit_option_decl => OptionDecl,
+    visit_call_list_item => CallListItem,
+    visit_main_assignement => MainAssignement,
+}, token: {
+    visit_identifier,
+    visit_multi_line_comment,
+    visit_number,
+    visit_single_line_comment,
+    visit_string_literal,
+    visit_symbol,
+    visit_token,
+    visit_whitespace,
+    visit_interpolated_string_segment,
+});
diff --git a/src/Rust/vvs_parser/src/vivy/error_report.rs b/src/Rust/vvs_parser/src/vivy/error_report.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1ddc23d0fc5f9211caf6e8c611fc8ba206ecbe8b
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/error_report.rs
@@ -0,0 +1,126 @@
+use crate::Error;
+use codespan_reporting::{
+    diagnostic::{Diagnostic, Label},
+    files::SimpleFiles,
+    term::{Chars, DisplayStyle},
+};
+use derive_more::Display;
+use hashbrown::HashMap;
+use std::{mem, str};
+use termcolor::ColorChoice;
+
+/// Utility to report error to the user.
+pub struct ErrorReport<'a> {
+    /// The list of parsed files.
+    files: SimpleFiles<&'a str, &'a str>,
+
+    /// We cache the ID, so that we can call the [ErrorReport::add_error] and
+    /// [ErrorReport::add_warning] multiple times on the same file.
+    id_cache: HashMap<&'a str, usize>,
+
+    /// The list of [Error], can be errors or warnings depending on their [ErrorReportType].
+    messages: HashMap<usize, Vec<(ErrorReportType, Error)>>,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Display)]
+enum ErrorReportType {
+    #[display("error")]
+    Error,
+
+    #[display("warning")]
+    Warning,
+}
+
+impl<'a> ErrorReport<'a> {
+    /// Create a new error report.
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    fn add<I, T>(&mut self, name: &'a str, src: &'a str, ty: ErrorReportType, iter: I) -> &mut Self
+    where
+        I: IntoIterator<Item = T>,
+        T: Into<Error>,
+    {
+        let file_id = self.id_cache.entry(name).or_insert_with(|| self.files.add(name, src));
+        self.messages
+            .entry(*file_id)
+            .or_default()
+            .extend(iter.into_iter().map(|error| (ty, error.into())));
+        self
+    }
+
+    /// Add errors to the report.
+    pub fn add_errors<I, T>(&mut self, name: &'a str, source: &'a str, errors: I) -> &mut Self
+    where
+        I: IntoIterator<Item = T>,
+        T: Into<Error>,
+    {
+        self.add(name, source, ErrorReportType::Error, errors)
+    }
+
+    /// Add warnings to the report.
+    pub fn add_warnings<I, T>(&mut self, name: &'a str, source: &'a str, errors: I) -> &mut Self
+    where
+        I: IntoIterator<Item = T>,
+        T: Into<Error>,
+    {
+        self.add(name, source, ErrorReportType::Warning, errors)
+    }
+
+    /// Report all the stored errors. Returns true if the report contained any error. Return false
+    /// if the report was empty or contained only warnings. Note that this operation will empty the
+    /// report struct.
+    pub fn report(&mut self) -> bool {
+        if self.messages.is_empty() {
+            return false;
+        }
+
+        let Self { files, messages, .. } = mem::take(self);
+        let mut output = termcolor::StandardStream::stdout(ColorChoice::Auto);
+        let config = codespan_reporting::term::Config {
+            display_style: DisplayStyle::Rich,
+            chars: Chars::box_drawing(),
+            ..Default::default()
+        };
+
+        messages.into_iter().fold(false, |acc, (file_id, messages)| {
+            messages.iter().fold(false, |acc, (report_type, message)| {
+                let diagnostic = match report_type {
+                    ErrorReportType::Error => Diagnostic::error(),
+                    ErrorReportType::Warning => Diagnostic::warning(),
+                }
+                .with_message(message.error_message())
+                .with_code(message.error_code())
+                .with_labels(vec![Label::primary(file_id, message.byte_range())]);
+
+                codespan_reporting::term::emit(&mut output, &config, &files, &diagnostic).is_err()
+                    || (*report_type == ErrorReportType::Error || acc)
+            }) || acc
+        })
+    }
+
+    /// Report all stored errors and warnings, but don't say if any error was actually reported.
+    /// Like [ErrorReport::report], this operation will empty the report.
+    pub fn report_and_ignore(&mut self) {
+        self.report();
+    }
+}
+
+impl ErrorReport<'_> {
+    /// Reports a single error
+    pub fn error(name: &'_ str, source: &'_ str, error: impl Into<Error>) {
+        ErrorReport::new().add_errors(name, source, [error.into()]).report();
+    }
+
+    /// Reports a single warning
+    pub fn warning(name: &'_ str, source: &'_ str, warning: impl Into<Error>) {
+        ErrorReport::new().add_warnings(name, source, [warning.into()]).report();
+    }
+}
+
+impl<'a> Default for ErrorReport<'a> {
+    fn default() -> Self {
+        Self { files: SimpleFiles::new(), messages: Default::default(), id_cache: Default::default() }
+    }
+}
diff --git a/src/Rust/vvs_parser/src/vivy/frontend_pipeline.rs b/src/Rust/vvs_parser/src/vivy/frontend_pipeline.rs
new file mode 100644
index 0000000000000000000000000000000000000000..53bc5d77bf182921be794636546e8a6e68e3b9b3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/frontend_pipeline.rs
@@ -0,0 +1,327 @@
+//! Contains the main code for the compiler. The compiler parses and do checks on the code, do some
+//! optimisations and then returns the [ast::Ast] if no errors where found.
+
+use crate::{
+    ast::*,
+    tokenizer::TokenReference,
+    traits::VecExtension as _,
+    vivy::{
+        error_report::ErrorReport,
+        library::Library,
+        passes::*,
+        search_path::{SearchPath, DEFAULT_SEARCH_PATH},
+        symbol_table::SymbolTable,
+        *,
+    },
+    ShortString,
+};
+use derive_more::Display;
+use hashbrown::{HashMap, HashSet};
+use std::{borrow::Cow, cell::RefCell, fmt, fs, mem, path::Path, rc::Rc};
+
+/// Process a program.
+pub struct FrontendPipeline<'a> {
+    /// Options from a possibly passed file to the compiler.
+    options: Option<Rc<OptionTable>>,
+
+    /// The content of the program / main module.
+    program: Cow<'a, str>,
+
+    /// List of imported modules.
+    imports: HashMap<ShortString, Rc<(Ast, Cow<'static, str>)>>,
+
+    /// List of imported symbol tables.
+    symbols: Vec<Rc<SymbolTable<'a, TypeInfo>>>,
+
+    /// The search path.
+    search: &'a SearchPath,
+
+    /// Is the current module being compiled the main module?
+    is_main: bool,
+
+    /// The include path, upper in the vector is the modules importing the ones down in the vector.
+    process_path: Vec<ShortString>,
+
+    /// The library of available types.
+    library: Rc<RefCell<Library>>,
+
+    /// List of user defined passes. Will be run in order after we are done with our own passes.
+    passes: &'a [&'a dyn UserFrontendPass],
+}
+
+/// Record of all the options defined, unused, setted in the program.
+pub struct OptionsRecord {
+    /// List of all unused declared options.
+    unused_options: Vec<(ShortString, ShortString)>,
+
+    /// All setted options.
+    setted_options: Vec<(ShortString, ShortString, Expression)>,
+
+    /// All declared options.
+    declared_options: Vec<(ShortString, ShortString, Expression)>,
+}
+
+impl fmt::Display for OptionsRecord {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let Self { setted_options, .. } = self;
+        match setted_options.iter().map(|(a, b, _)| a.len() + b.len()).max() {
+            None | Some(0) => Ok(()),
+            Some(len) => setted_options.iter().try_for_each(|(module, name, expression)| {
+                writeln!(f, "{module}.{name: >len$} {expression}", len = len - module.len())
+            }),
+        }
+    }
+}
+
+/// Result of the front-end. Don't show that directly to the user, will show [FrontendOutput].
+struct CompilerResult {
+    /// The [Ast] of the main program's module.
+    ast: Ast,
+
+    /// List of all imported modules' [Ast]
+    imports: HashMap<ShortString, Rc<(Ast, Cow<'static, str>)>>,
+
+    /// The main program.
+    main: MainProgram,
+
+    /// Record of all options in the program.
+    options: OptionsRecord,
+
+    /// All the defined types.
+    library: Rc<RefCell<Library>>,
+}
+
+/// The result of the frontend.
+pub struct FrontendOutput {
+    /// The [Ast] of the main program's module.
+    pub ast: Ast,
+
+    /// List of all imported modules' [Ast]
+    pub imports: HashMap<ShortString, Ast>,
+
+    /// The main program.
+    pub main: MainProgram,
+
+    /// Record of all options in the program.
+    pub options: OptionsRecord,
+
+    /// All the defined types.
+    pub library: Library,
+}
+
+impl From<CompilerResult> for FrontendOutput {
+    fn from(value: CompilerResult) -> Self {
+        let CompilerResult { ast, imports, main, options, library } = value;
+        let library = RefCell::into_inner(Rc::into_inner(library).expect("unique owner"));
+        let imports = HashMap::from_iter(
+            imports
+                .into_iter()
+                .map(|(module, ptr)| (module, Rc::into_inner(ptr).expect("unique owner").0)),
+        );
+        Self { ast, main, options, imports, library }
+    }
+}
+
+impl fmt::Display for FrontendOutput {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let Self { imports, main, options, library, .. } = self;
+        write!(f, "imported modules: ")?;
+        imports.keys().try_for_each(|module| write!(f, "{module} "))?;
+        writeln!(f)?;
+
+        writeln!(f, "{options}")?;
+        writeln!(f, "{library}")?;
+        writeln!(f, "{main:#?}")
+    }
+}
+
+/// Tells if the frontend failed or not.
+#[derive(Debug, Display, Clone, Copy)]
+#[display("frontend error")]
+pub struct FrontendError;
+
+impl std::error::Error for FrontendError {}
+
+impl From<()> for FrontendError {
+    fn from(_: ()) -> Self {
+        Self {}
+    }
+}
+
+#[derive(Default)]
+struct ImportAllResult {
+    declared_options: Vec<(ShortString, ShortString, Expression)>,
+    unused: Vec<(ShortString, ShortString)>,
+}
+
+impl FromIterator<ImportAllResult> for ImportAllResult {
+    fn from_iter<T: IntoIterator<Item = ImportAllResult>>(iter: T) -> Self {
+        let mut iter = iter.into_iter();
+        let Some(ret) = iter.next() else {
+            return Default::default();
+        };
+        iter.fold(ret, |mut ret, item| {
+            let Self { mut declared_options, unused } = item;
+            ret.declared_options.append(&mut declared_options);
+            ret.unused.retain(|option| unused.contains(option));
+            ret
+        })
+    }
+}
+
+impl<'a> FrontendPipeline<'a> {
+    /// Create a new pipeline to parse, to check and do black magic.
+    pub fn new(SourceCode { name, code }: &'a SourceCode) -> Self {
+        Self {
+            program: Cow::Borrowed(code.as_ref()),
+            options: None,
+            imports: Default::default(),
+            symbols: vec![],
+            is_main: true,
+            search: &DEFAULT_SEARCH_PATH,
+            process_path: vec![ShortString::new(name.as_ref())],
+            library: Rc::new(RefCell::new(Library::default())),
+            passes: &[],
+        }
+    }
+
+    /// Add passes to do for each module at the end of mendatory passes.
+    pub fn passes(self, passes: &'a [&'a dyn UserFrontendPass]) -> Self {
+        Self { passes, ..self }
+    }
+
+    /// Get the name of the module we are compiling here. We should always have a name, if we parse
+    /// the stdin we still have a name for the module: stdin...
+    pub fn name(&self) -> &ShortString {
+        self.process_path.last().expect("module name")
+    }
+
+    /// Set the option file to use for this instance of the program.
+    pub fn options(self, options: Option<impl AsRef<Path>>) -> Result<Self, FrontendError> {
+        let Some(options) = options else { return Ok(self) };
+        let options = options.as_ref();
+
+        let name = options
+            .file_name()
+            .ok_or_else(|| log::error!("expected a file with an actual name"))?
+            .to_str()
+            .ok_or_else(|| log::error!("expected files with utf8 names"))?;
+
+        let code = fs::read_to_string(options)
+            .map_err(|err| log::error!("failed to read option file '{}': {err}", options.display()))?;
+
+        Ok(crate::ast::OptionTableResult::parse_fallible(&code)
+            .into_result()
+            .map(|options| Self { options: Some(Rc::new(options)), ..self })
+            .map_err(|errors| ErrorReport::new().add_errors(name, &code, errors).report_and_ignore())?)
+    }
+
+    /// Set the [SearchPath] to use for this instance of the program.
+    pub fn search(self, search: &'a SearchPath) -> Self {
+        Self { search, ..self }
+    }
+
+    /// Import all modules from the given list and add them to the current pipeline.
+    fn import_all(&mut self, import_list: Vec<TokenReference>) -> Result<ImportAllResult, FrontendError> {
+        Iterator::collect(import_list.into_iter().map(|import| {
+            let name = import.token_type().as_str();
+            if self.imports.contains_key(name) {
+                return Ok(ImportAllResult::default());
+            } else if self.process_path.iter().any(|path| path.as_str() == name) {
+                ErrorReport::error(
+                    self.name(),
+                    &self.program,
+                    AstError::from_parts(import.clone(), "recursive indlude of module"),
+                );
+                return Err(FrontendError);
+            }
+
+            let program = self.search.resolve(name).ok_or_else(|| {
+                ErrorReport::error(
+                    self.name(),
+                    &self.program,
+                    AstError::from_parts(import.clone(), "failed to find the module to import"),
+                )
+            })?;
+
+            let CompilerResult {
+                ast, imports, options: OptionsRecord { unused_options, declared_options, .. }, ..
+            } = FrontendPipeline {
+                process_path: self.process_path.clone().join(ShortString::new(name)),
+                imports: mem::take(&mut self.imports), // Will be replaced.
+                program: match program {
+                    Cow::Borrowed(program) => Cow::Borrowed(program),
+                    Cow::Owned(ref program) => Cow::Borrowed(program.as_str()),
+                },
+                options: self.options.clone(),
+                symbols: self.symbols.clone(),
+                library: self.library.clone(),
+                is_main: false,
+                ..*self
+            }
+            .process()?;
+
+            debug_assert!({
+                let prev = HashSet::<&ShortString>::from_iter(self.imports.keys());
+                let news = HashSet::<&ShortString>::from_iter(imports.keys());
+                (prev.len() <= news.len()) && (prev.intersection(&news).count() == prev.len())
+            });
+            let _ = mem::replace(&mut self.imports, imports); // Replace with a more complete import list.
+            self.imports.insert(ShortString::new(name), Rc::new((ast, program)));
+
+            Ok(ImportAllResult { declared_options, unused: unused_options })
+        }))
+    }
+
+    /// Process the pipeline. Some returned values may be hidden from the user, or things
+    /// transformed a but more for the main result, but here we keep them.
+    fn process(mut self) -> Result<CompilerResult, FrontendError> {
+        let ast = AstResult::parse_fallible(&self.program).into_result().map_err(|err| {
+            let _ = ErrorReport::new().add_errors(self.name(), &self.program, err).report();
+        })?;
+
+        let (ast, StmtCheckerResult { decl_opts, setd_opts, main, imported }) =
+            StmtChecker::new(ast, (self.name().as_str(), self.program.as_ref()))
+                .is_main(self.is_main)
+                .process()?;
+        let ImportAllResult { mut declared_options, unused } = self.import_all(imported)?;
+
+        declared_options.extend(
+            decl_opts
+                .into_iter()
+                .map(|(name, value)| (self.name().clone(), name, value.into())),
+        );
+
+        let symbols = SymbolTable::new(&ast, self.options.as_deref())
+            .import(self.symbols.iter().map(Rc::as_ref))
+            .take();
+
+        let loc = (self.name().as_str(), self.program.as_ref());
+        let (ast, _) = TypeCollector::new(ast, loc, &mut self.library.borrow_mut()).process()?;
+        let (ast, _) = TypeChecker::new(ast, loc, &self.library.borrow(), symbols.sub_scope()).process()?;
+        let (ast, OptsTransformResult { unused }) = match self.options.clone() {
+            None => (ast, Default::default()),
+            Some(options) => {
+                let (ast, results) = OptsTransform::new(ast, loc, &options).process()?;
+                (ast, OptsTransformResult { unused: results.unused.without(|opt| unused.contains(opt)) })
+            }
+        };
+
+        Ok(CompilerResult {
+            ast: self.passes.iter().try_fold(ast, |prog, pass| {
+                log::debug!("apply pass {} on module {}", pass.name(), self.name());
+                pass.process(prog, self.name(), self.program.as_ref())
+            })?,
+            imports: self.imports,
+            options: OptionsRecord { declared_options, setted_options: setd_opts, unused_options: unused },
+            library: self.library.clone(),
+            main: main.unwrap_or_default(),
+        })
+    }
+
+    /// Process the pipeline. Returns the [Ast] or an error. Note that if an error occured, they
+    /// will be printed out to the terminal.
+    pub fn run(self) -> Result<FrontendOutput, FrontendError> {
+        self.process().map(Into::into)
+    }
+}
diff --git a/src/Rust/vvs_parser/src/vivy/library.rs b/src/Rust/vvs_parser/src/vivy/library.rs
new file mode 100644
index 0000000000000000000000000000000000000000..95d15e5fda3e38fd8201408661bce30db20f1e4e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/library.rs
@@ -0,0 +1,333 @@
+//! Store informations about methods and fields for types.
+
+use crate::{ast::TypeInfo, ShortString};
+use derive_more::{Display, IntoIterator, IsVariant};
+use hashbrown::HashMap;
+use std::{fmt, sync::LazyLock};
+
+/// Tells whether a field is mutable or constant.
+#[derive(PartialEq, Eq, Clone, Copy, Debug, IsVariant)]
+pub enum FieldMutability {
+    /// The field can be mutated by a user.
+    Mutable,
+
+    /// The field can't be mutated by a user and can represent an internal variant of the variable.
+    Constant,
+}
+
+/// Informations about a field of a [TypeRecord].
+#[derive(PartialEq, Clone, Copy)]
+pub struct TypeRecordField<'a>(pub FieldMutability, pub &'a TypeInfo);
+
+/// Informations about a method of a [TypeRecord].
+#[derive(PartialEq, Clone, Copy)]
+pub struct TypeRecordMethod<'a>(pub &'a [TypeInfo], pub &'a TypeInfo, pub bool);
+
+impl TypeRecordMethod<'_> {
+    /// Tells whether the method is really a method or just a free function.
+    pub fn is_method(&self) -> bool {
+        let TypeRecordMethod(_, _, is_method) = self;
+        *is_method
+    }
+}
+
+/// A record stores informations about a type, the fields and the methods.
+#[derive(Clone)]
+pub struct TypeRecord {
+    type_info: TypeInfo,
+    is_std: bool,
+    fields: HashMap<ShortString, (FieldMutability, TypeInfo)>,
+    methods: HashMap<ShortString, (Vec<TypeInfo>, TypeInfo)>,
+}
+
+static STANDARD_RECORDS: LazyLock<Vec<TypeRecord>> = LazyLock::new(|| {
+    macro_rules! records {
+        ($( struct $ty: ident $struct: tt impl $methods: tt )*) => { Vec::from_iter([$(records!(@ $ty $struct $methods)),*]) };
+        (@ $type: ident $fields: tt { $($(fn $method: ident ($($arg: ident),*) -> $ret: ident;)+)? }) => {
+            std::mem::take(records!(@ TypeRecord::new_std(TypeInfo::$type().clone()), $fields)
+                $(.with_methods([
+                    $((ShortString::new(stringify!($method)), vec![$(TypeInfo::$arg().clone()),*], TypeInfo::$ret().clone())),*
+                ]))?
+            )
+        };
+        (@ $a: expr, const $f: ident : $fty: ident ) => { $a.with_field(stringify!($f).into(), FieldMutability::Constant, TypeInfo::$fty().clone()) };
+        (@ $a: expr, mut   $f: ident : $fty: ident ) => { $a.with_field(stringify!($f).into(), FieldMutability::Mutable,  TypeInfo::$fty().clone()) };
+        (@ $acc: expr, {}) => { $acc };
+        (@ $acc: expr, { $v: tt $f: ident : $fty: ident $(, $vs: tt $fs: ident : $ftys: ident)* $(,)? }) => {
+            records!(@ records!(@ $acc, $v $f: $fty), { $($vs $fs: $ftys),* })
+        };
+    }
+
+    records! {
+        struct number {} impl {
+            fn is_nan()   -> number;
+            fn is_zero()  -> number;
+            fn is_true()  -> number;
+            fn is_false() -> number;
+            fn floor()    -> number;
+            fn ceil()     -> number;
+        }
+
+        struct string {} impl {
+            fn new() -> string;
+            fn put(char) -> string;
+            fn append(string) -> string;
+
+            fn len() -> number;
+            fn get(number) -> char;
+
+            fn is_lowercase() -> number;
+            fn is_uppercase() -> number;
+            fn to_lowercase() -> string;
+            fn to_uppercase() -> string;
+        }
+
+        struct char {} impl {
+            fn is_lowercase() -> number;
+            fn is_uppercase() -> number;
+            fn to_lowercase() -> char;
+            fn to_uppercase() -> char;
+        }
+
+        struct table {} impl {
+            fn new() -> table;
+            fn len() -> number;
+            fn get(any) -> any;
+            fn set(any, any) -> nil;
+        }
+
+        struct any {} impl {
+            fn new() -> any;
+
+            fn to_string() -> string;
+            fn to_number() -> number;
+            fn to_table()  -> table;
+        }
+
+        struct line {
+            const index: number, // Index of the line in the original document.
+            mut   start: number, // Start time of the line.
+            mut   end:   number, // End time of the line.
+        } impl {
+            fn len() -> number;
+            fn syllabe(number) -> syllabe;
+            fn syllabes()      -> syllabes;
+        }
+
+        struct lines {} impl {
+            fn len() -> number;
+            fn line(number) -> line;
+            fn syllabes()   -> syllabes;
+        }
+
+        struct syllabes {} impl {
+            fn len() -> number;
+            fn syllabe(number) -> syllabe;
+        }
+
+        struct syllabe {
+            const index: number, // Index in the parent line.
+            mut   start: number, // Start time of the syllabe.
+            mut   end:   number, // End time of the syllabe.
+        } impl {
+            fn len() -> number;
+            fn text() -> string;
+            fn get(number) -> char;
+        }
+    }
+});
+
+impl TypeRecord {
+    /// Create a new type record.
+    pub fn new(type_info: TypeInfo) -> Self {
+        Self { type_info, is_std: false, ..Default::default() }
+    }
+
+    /// Create a new standard type record.
+    fn new_std(type_info: TypeInfo) -> Self {
+        Self { type_info, is_std: true, ..Default::default() }
+    }
+
+    /// Add or override a field in the record.
+    pub fn with_field(&mut self, field: ShortString, mutability: FieldMutability, type_info: TypeInfo) -> &mut Self {
+        self.fields.insert(field, (mutability, type_info));
+        self
+    }
+
+    /// Add or override a method in the record.
+    pub fn with_method(&mut self, method: ShortString, arguments: Vec<TypeInfo>, returns: TypeInfo) -> &mut Self {
+        self.methods.insert(method, (arguments, returns));
+        self
+    }
+
+    /// Add or override fields in the record.
+    pub fn with_fields(
+        &mut self,
+        iter: impl IntoIterator<Item = (ShortString, FieldMutability, TypeInfo)>,
+    ) -> &mut Self {
+        iter.into_iter().fold(self, |s, (k, m, t)| s.with_field(k, m, t))
+    }
+
+    /// Add or override methods in the record.
+    pub fn with_methods(
+        &mut self,
+        iter: impl IntoIterator<Item = (ShortString, Vec<TypeInfo>, TypeInfo)>,
+    ) -> &mut Self {
+        iter.into_iter().fold(self, |s, (k, m, t)| s.with_method(k, m, t))
+    }
+
+    /// Get the fields of instances of this type.
+    pub fn fields(&self) -> impl Iterator<Item = (&ShortString, TypeRecordField)> {
+        self.fields
+            .iter()
+            .map(|(field, (mutability, type_info))| (field, TypeRecordField(*mutability, type_info)))
+    }
+
+    /// Get the methods of instances of this type.
+    pub fn methods(&self) -> impl Iterator<Item = (&ShortString, TypeRecordMethod)> {
+        self.methods.iter().map(|(method, (args, returns))| {
+            (method, TypeRecordMethod(args, returns, args.first().map(|_| todo!()).unwrap_or_default()))
+        })
+    }
+
+    /// Get a field's informations if it exists, otherwise get [None].
+    pub fn field(&self, field: impl AsRef<str>) -> Option<TypeRecordField> {
+        self.fields
+            .get(field.as_ref())
+            .map(|(mutability, type_info)| TypeRecordField(*mutability, type_info))
+    }
+
+    /// Get a method's informations if it exists, otherwise get [None].
+    pub fn method(&self, method: impl AsRef<str>) -> Option<TypeRecordMethod> {
+        self.methods
+            .get(method.as_ref())
+            .map(|(args, returns)| TypeRecordMethod(args, returns, args.first().map(|_| todo!()).unwrap_or_default()))
+    }
+
+    /// Get the [TypeInfo] of this record.
+    pub fn type_info(&self) -> &TypeInfo {
+        &self.type_info
+    }
+}
+
+impl Default for TypeRecord {
+    fn default() -> Self {
+        Self { is_std: true, type_info: Default::default(), fields: Default::default(), methods: Default::default() }
+    }
+}
+
+impl fmt::Display for TypeRecord {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let this = self.type_info();
+        let std_comment = match self.is_std {
+            true => "--[[ std! ]]",
+            false => "",
+        };
+        writeln!(f, "struct {std_comment} {this} {{")?;
+        self.fields()
+            .try_for_each(|(name, TypeRecordField(mutability, type_info))| {
+                let mutability = (mutability == FieldMutability::Mutable)
+                    .then_some("mut ")
+                    .unwrap_or_default();
+                writeln!(f, "\t{mutability} {name}: {type_info},")
+            })?;
+        writeln!(f, "}}")?;
+
+        self.methods()
+            .try_for_each(|(name, func @ TypeRecordMethod(args, ret, ..))| {
+                write!(f, "function {this}:{name}(")?;
+                if func.is_method() && !args.is_empty() {
+                    write!(f, "{this},")?;
+                } else if func.is_method() {
+                    write!(f, "{this}")?;
+                }
+                args.iter().enumerate().try_for_each(|(idx, arg)| match idx {
+                    0 => write!(f, "{arg}"),
+                    _ => write!(f, ", {arg}"),
+                })?;
+                writeln!(f, ") -> {ret};")
+            })
+    }
+}
+
+/// Stores all the knowned [TypeRecord] for a program. Can differentiate between standard type
+/// records and users' type records.
+#[derive(IntoIterator)]
+pub struct Library(Vec<TypeRecord>);
+
+impl Library {
+    /// Create a new library.
+    pub fn new() -> Self {
+        Self::from_iter(STANDARD_RECORDS.iter())
+    }
+
+    /// Iterate throu the records.
+    pub fn iter(&self) -> impl Iterator<Item = &TypeRecord> {
+        self.0.iter()
+    }
+
+    /// Iterate throu the records in a mutable way. Not that you can only mutate non-standard
+    /// types' record.
+    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut TypeRecord> {
+        self.0.iter_mut().filter(|TypeRecord { is_std, .. }| !*is_std)
+    }
+
+    /// Tells wether a specific record for a type name is present or not.
+    pub fn has(&self, name: impl AsRef<str>) -> bool {
+        self.get(name).is_some()
+    }
+
+    /// Get the record for a type name, if not present returns a newly created record.
+    pub fn get(&self, name: impl AsRef<str>) -> Option<&TypeRecord> {
+        self.iter().find(|TypeRecord { type_info, .. }| match type_info {
+            TypeInfo::Basic(type_info) => type_info.token_type().as_str() == name.as_ref(),
+            _ => false,
+        })
+    }
+
+    /// Get the record for a type name in a mutable way, if not present returns [None]. If the
+    /// record is from standard type, also returns [None].
+    pub fn get_mut(&mut self, name: impl AsRef<str>) -> Option<&mut TypeRecord> {
+        self.iter_mut().find(|TypeRecord { type_info, .. }| match type_info {
+            TypeInfo::Basic(type_info) => type_info.token_type().as_str() == name.as_ref(),
+            _ => false,
+        })
+    }
+
+    /// Set a type record for a type. If the record is already present, replace it. If the already
+    /// present record is of a standard type, it won't be replaced.
+    pub fn put(&mut self, record: TypeRecord) {
+        let find = |(idx, TypeRecord { type_info, is_std, .. }): (_, &_)| {
+            (*type_info == record.type_info).then_some((idx, *is_std))
+        };
+        match self.0.iter().enumerate().find_map(find) {
+            Some((_, true)) => {}
+            Some((idx, false)) => self.0[idx] = record,
+            None => self.0.push(record),
+        }
+    }
+}
+
+impl FromIterator<TypeRecord> for Library {
+    fn from_iter<T: IntoIterator<Item = TypeRecord>>(iter: T) -> Self {
+        Self(iter.into_iter().collect())
+    }
+}
+
+impl<'a> FromIterator<&'a TypeRecord> for Library {
+    fn from_iter<T: IntoIterator<Item = &'a TypeRecord>>(iter: T) -> Self {
+        Self(iter.into_iter().cloned().collect())
+    }
+}
+
+impl Default for Library {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl fmt::Display for Library {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.iter().try_for_each(|record| write!(f, "{record}"))
+    }
+}
diff --git a/src/Rust/vvs_parser/src/vivy/main_program.rs b/src/Rust/vvs_parser/src/vivy/main_program.rs
new file mode 100644
index 0000000000000000000000000000000000000000..54ddd0901346a4683025dc7cf8e70dd3740526be
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/main_program.rs
@@ -0,0 +1,120 @@
+//! Main program and utilities to be able to complete the work.
+
+use crate::{ast::Expression, ShortString};
+use derive_more::{IntoIterator, IsVariant};
+
+/// The main program to execute in the parsed script.
+#[derive(Default, Debug)]
+pub struct MainProgram {
+    /// The initial variable name of the read ASS file.
+    pub initial: ShortString,
+
+    /// Steps to do, in order, to make the program progress.
+    pub steps: Vec<MainProgramStep>,
+
+    /// The variables to write at the end of the program.
+    pub returns: MainProgramReturns,
+}
+
+impl MainProgram {
+    /// Set the initial variable name.
+    pub fn with_initial(self, initial: ShortString) -> Self {
+        Self { initial, ..self }
+    }
+
+    /// Set the steps for the main program.
+    pub fn with_steps(self, steps: Vec<MainProgramStep>) -> Self {
+        Self { steps, ..self }
+    }
+
+    /// Set the returned variables
+    pub fn with_returns(self, returns: impl IntoIterator<Item = ShortString>) -> Self {
+        Self { returns: returns.into_iter().collect(), ..self }
+    }
+}
+
+/// The returned variables from the main program.
+#[derive(Debug, Default, IntoIterator)]
+pub struct MainProgramReturns {
+    #[into_iterator(owned)]
+    variables: Vec<ShortString>,
+}
+
+impl FromIterator<ShortString> for MainProgramReturns {
+    fn from_iter<T: IntoIterator<Item = ShortString>>(iter: T) -> Self {
+        Self { variables: iter.into_iter().collect() }
+    }
+}
+
+/// A step to do for the main program.
+#[derive(Debug)]
+pub struct MainProgramStep {
+    /// The name of the assignated variable.
+    destination: ShortString,
+
+    /// The name of the job with its source module, in this order: `(module, job)`.
+    job: (ShortString, ShortString),
+
+    /// The arguments to pass to the job, the variables to read (and possibly rearange), and the
+    /// parameters to set.
+    call_list: Vec<MainProgramCallListItem>,
+}
+
+impl MainProgramStep {
+    /// Create a new program step.
+    pub fn new(
+        destination: ShortString,
+        job: (ShortString, ShortString),
+        call_list: impl IntoIterator<Item = MainProgramCallListItem>,
+    ) -> Self {
+        Self { destination, job, call_list: call_list.into_iter().collect() }
+    }
+
+    /// Get the name of the variable to write the result of the job into.
+    pub fn destination(&self) -> &ShortString {
+        &self.destination
+    }
+
+    /// Get the name of the source module where to find the job we are trying to call.
+    pub fn module(&self) -> &ShortString {
+        &self.job.0
+    }
+
+    /// Get the name of the job we are trying to call.
+    pub fn job(&self) -> &ShortString {
+        &self.job.1
+    }
+
+    /// Get the arguments of the job.
+    pub fn call_list_items(&self) -> impl Iterator<Item = &MainProgramCallListItem> {
+        self.call_list.iter()
+    }
+}
+
+/// An item to pass to a job when we call it.
+#[derive(Debug, IsVariant)]
+pub enum MainProgramCallListItem {
+    /// We add a variable to process.
+    Variable(ShortString),
+
+    /// We set a parameter for the job.
+    Parameter(ShortString, Expression),
+}
+
+impl MainProgramCallListItem {
+    /// Treat the call list item as a variable if possible.
+    pub fn as_variable(&self) -> Option<&ShortString> {
+        match self {
+            MainProgramCallListItem::Variable(variable) => Some(variable),
+            _ => None,
+        }
+    }
+
+    /// Treat the call list item as a parameter setting if possible.
+    pub fn as_parameter(&self) -> Option<(&ShortString, &Expression)> {
+        match self {
+            MainProgramCallListItem::Parameter(argument, value) => Some((argument, value)),
+            _ => None,
+        }
+    }
+}
diff --git a/src/Rust/vvs_parser/src/vivy/mod.rs b/src/Rust/vvs_parser/src/vivy/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e28ae6ec611852cbc4a5fc6e4569a2e9ed28ecf0
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/mod.rs
@@ -0,0 +1,45 @@
+//! Vivy specific logic
+
+mod error_report;
+mod frontend_pipeline;
+mod library;
+mod main_program;
+mod passes;
+mod search_path;
+mod symbol_table;
+
+use std::{borrow::Cow, fs, io, path::Path};
+
+pub use self::{error_report::ErrorReport, frontend_pipeline::*, main_program::*, passes::UserFrontendPass};
+
+/// The representation of a source file.
+pub struct SourceCode {
+    name: Cow<'static, str>,
+    code: Cow<'static, str>,
+}
+
+impl SourceCode {
+    /// Create a new source file from a file.
+    pub fn from_path(path: impl AsRef<Path>) -> io::Result<Self> {
+        Ok(Self {
+            name: Cow::Owned(
+                path.as_ref()
+                    .file_name()
+                    .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "path doesn't have a file name"))?
+                    .to_string_lossy()
+                    .to_string(),
+            ),
+            code: Cow::Owned(fs::read_to_string(path.as_ref())?),
+        })
+    }
+
+    /// Create a new source file from memory.
+    pub fn from_memory(code: Cow<'static, str>) -> Self {
+        Self { name: Cow::Borrowed("--"), code }
+    }
+
+    /// Get the name of the source file.
+    pub fn name(&self) -> &str {
+        &self.name
+    }
+}
diff --git a/src/Rust/vvs_parser/src/vivy/passes/mod.rs b/src/Rust/vvs_parser/src/vivy/passes/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6c6f8e65044f33f3832a102c727ceadebf32045d
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/passes/mod.rs
@@ -0,0 +1,141 @@
+//! Passes to verify and transform the Vivy Script code written by an user.
+
+mod opts_transform;
+mod stmt_checker;
+mod type_checker;
+mod type_collector;
+
+pub use self::{opts_transform::*, stmt_checker::*, type_checker::*, type_collector::*};
+
+/// Macro used to declare a pass, can be a transform pass or a visit pass (for the role).
+/// ```ignore
+/// declare_pass! {
+///     transform::OptsTransform
+///     aux_infos { options: toml::Table }
+///     opt_infos { verbose: u8 }
+///     results { replaced_count: usize, unused_options: Vec<String> }
+/// };
+/// impl VisitorMut for OptsTransform {}
+/// ```
+#[macro_export]
+macro_rules! declare_pass {
+    (
+        $(#[$meta: meta])*
+        $role: ident :: $name: ident : $lifetime: lifetime {
+            $($field_attr: ident : $field_ty: ty),* $(,)?
+        }
+
+        $(aux_infos { $($info_attr: ident : $info_ty: ty),+$(,)? })?
+        $(opt_infos { $($opts_attr: ident : $opts_ty: ty),+$(,)? })?
+        $(results   { $($res_attr:  ident : $res_ty:  ty),+$(,)? })?
+    ) => {
+        $(#[$meta])*
+        pub struct $name <$lifetime> {
+            program: Option<$crate::ast::Ast>,
+            name:    &$lifetime str,
+            source:  &$lifetime str,
+            report:  $crate::vivy::error_report::ErrorReport<$lifetime>,
+            $(  $field_attr: $field_ty,)*
+            $($($info_attr:  $info_ty),+,)?
+            $($($opts_attr:  Option<$opts_ty>),+,)?
+            $($($res_attr:   $res_ty),+,)?
+        }
+
+        paste::paste! {
+            #[doc = "The resut structure for the  [" $name "] pass."]
+            #[derive(Default)]
+            pub struct [< $name Result >]  {
+                $($(pub $res_attr: $res_ty),+)?
+            }
+        }
+
+        impl <$lifetime> $name <$lifetime> {
+            paste::paste! {
+                #[doc = "Create a new [" $name "] pass."]
+                pub fn new(
+                    program:        $crate::ast::Ast,
+                    (name, source): (&$lifetime str, &$lifetime str)
+                    $($(, $info_attr: $info_ty)+)?
+                ) -> Self {
+                    Self {
+                        program: Some(program), name, source,
+                        report: $crate::vivy::error_report::ErrorReport::new(),
+                        $($($info_attr),+,)?
+                        $(  $field_attr: Default::default(),)*
+                        $($($opts_attr:  None),+,)?
+                        $($($res_attr:   Default::default()),+,)?
+                    }
+                }
+
+                /// Add a new ast error to the error list.
+                #[allow(dead_code)]
+                fn error(&mut self, token: impl Into<$crate::tokenizer::TokenReference>, error: impl Into<std::borrow::Cow<'static, str>>) {
+                    self.report.add_errors(
+                        self.name,
+                        self.source,
+                        [$crate::Error::AstError($crate::ast::AstError::from_parts(token.into(), error))]
+                    );
+                }
+
+                /// Add a new ast warning to the error list.
+                #[allow(dead_code)]
+                fn warning(&mut self, token: impl Into<$crate::tokenizer::TokenReference>, error: impl Into<std::borrow::Cow<'static, str>>) {
+                    self.report.add_warnings(
+                        self.name,
+                        self.source,
+                        [$crate::Error::AstError($crate::ast::AstError::from_parts(token.into(), error))]
+                    );
+                }
+
+                $($(
+                    #[doc = "Set the optional information '" $opts_attr "' for the [" $name "] pass."]
+                    #[allow(clippy::wrong_self_convention)]
+                    pub fn $opts_attr(self, $opts_attr: $opts_ty) -> Self {
+                        Self { $opts_attr: Some($opts_attr), ..self }
+                    }
+                )+)?
+
+                #[doc = "Apply the [" $name "] pass and get the resulting [vvs_parser::ast::Ast] or the list of the errors."]
+                pub fn process(mut self) -> Result<($crate::ast::Ast, [< $name Result >]), ()> {
+                    let ast = self.program.take().unwrap();
+                    let ast = $crate::declare_pass!(@apply_on_ast $role (self, ast));
+                    match self.report.report() {
+                        true => Err(()),
+                        false => Ok((ast, [< $name Result >] {
+                            $($($res_attr: self.$res_attr),+)?
+                        })),
+                    }
+                }
+            }
+        }
+    };
+
+    (@apply_on_ast transform ($self: ident, $ast: expr)) => {{
+        use $crate::visitors::VisitorMut;
+        $self.visit_ast($ast)
+    }};
+
+    (@apply_on_ast visit ($self: ident, $ast: expr)) => {{
+        use $crate::visitors::Visitor;
+        $self.visit_ast(&$ast);
+        $ast
+    }};
+}
+
+/// Trait used to provide a way for users to create their own passes
+pub trait UserFrontendPass {
+    /// Get the name of the pass. For logging purposes.
+    fn name(&self) -> &'static str;
+
+    /// Get the description of the pass. For logging purposes.
+    fn description(&self) -> &'static str;
+
+    /// Do the work on a specific module. The order in which the modules are passed is not
+    /// guarented. It is better to not store state with interior mutability.
+    fn process(
+        &self,
+        program: crate::ast::Ast,
+        name: &str,
+        source: &str,
+    ) -> Result<crate::ast::Ast, crate::vivy::FrontendError>;
+}
diff --git a/src/Rust/vvs_parser/src/vivy/passes/opts_transform.rs b/src/Rust/vvs_parser/src/vivy/passes/opts_transform.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6c60caf8b37f6b40b1aa3d9b881199b8f9ca5e8e
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/passes/opts_transform.rs
@@ -0,0 +1,49 @@
+use crate::{ast::*, node::Node, tokenizer::*, ShortString};
+
+crate::declare_pass! {
+    /// The option optimization is here to substitute the options with the values chosen by the
+    /// user.
+    #[allow(dead_code)]
+    transform::OptsTransform: 'a {}
+
+    aux_infos { options: &'a OptionTable                 }
+    results   { unused:  Vec<(ShortString, ShortString)> }
+}
+
+impl crate::visitors::VisitorMut for OptsTransform<'_> {
+    fn visit_expression_end(&mut self, expression: Expression) -> Expression {
+        match expression {
+            Expression::Var(Var::Expression(var)) => self.process_var_expression(var),
+            expression => expression,
+        }
+    }
+}
+
+impl OptsTransform<'_> {
+    fn process_var_expression(&mut self, var: Box<VarExpression>) -> Expression {
+        let module = match var.prefix() {
+            Prefix::Name(TokenReference {
+                token: Token { token_type: TokenType::Identifier { identifier }, .. },
+                ..
+            }) if self.options.has_section(identifier) => identifier.clone(),
+            _ => return Expression::Var(Var::Expression(var)),
+        };
+
+        match var.suffixes().next() {
+            Some(Suffix::Index(Index::Dot {
+                name: TokenReference { token: Token { token_type: TokenType::Identifier { ref identifier }, .. }, .. },
+                ..
+            })) if var.suffixes().count() == 1 => self.options.get(&module, identifier).cloned().unwrap_or_else(|| {
+                self.error(var.tokens().next().unwrap(), format!("failed to find option `{module}.{identifier}`"));
+                Expression::Symbol(TokenReference::basic_symbol("nil"))
+            }),
+
+            Some(Suffix::Index(name)) => {
+                self.error(name.tokens().next().unwrap(), "expected a reference to an option, e.g. `module.option`");
+                Expression::Symbol(TokenReference::basic_symbol("nil"))
+            }
+
+            _ => Expression::Var(Var::Expression(var.clone())),
+        }
+    }
+}
diff --git a/src/Rust/vvs_parser/src/vivy/passes/stmt_checker.rs b/src/Rust/vvs_parser/src/vivy/passes/stmt_checker.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7dbb413a4eeb258749e0d7fb77d369e8a6f546f3
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/passes/stmt_checker.rs
@@ -0,0 +1,259 @@
+use crate::{
+    ast::{Punctuated, TypeInfo, *},
+    node::Node,
+    tokenizer::{Token, TokenKind, TokenReference, TokenType},
+    visitors::Visit,
+    vivy::main_program::{MainProgram, MainProgramCallListItem, MainProgramStep},
+    ShortString,
+};
+
+crate::declare_pass! {
+    /// The statement checker is here to verify that statements are not used in incorrect positions.
+    visit::StmtChecker: 'a {
+        in_job: bool,
+    }
+
+    opt_infos { is_main: bool }
+    results   {
+        imported:  Vec<TokenReference>,
+        setd_opts: Vec<(ShortString, ShortString, Expression)>,
+        decl_opts: Vec<(ShortString, OptionDefaultValue)>,
+        main:      Option<MainProgram>,
+    }
+}
+
+impl crate::visitors::Visitor for StmtChecker<'_> {
+    fn visit_ast(&mut self, ast: &Ast) {
+        ast.nodes().stmts().for_each(|stmt| match stmt {
+            Stmt::Import(import) => self.check_import(import),
+            Stmt::Main(main) => self.check_main(main),
+            Stmt::Assignment(assignment) => self.check_option_set(assignment),
+            Stmt::OptionDecl(declaration) => self.check_option_decl(declaration),
+
+            stmt @ Stmt::FunctionDeclaration(_) | stmt @ Stmt::LocalFunction(_) => stmt.visit(self),
+            stmt @ Stmt::JobDeclaration(_) => {
+                self.in_job = true;
+                stmt.visit(self);
+                self.in_job = false;
+            }
+
+            Stmt::TypeDeclaration(_) => unimplemented!("custom types are tbd"),
+
+            stmt => self.error(stmt.tokens().next().unwrap(), "unexpected statement"),
+        });
+        if !ast.eof().is_kind(TokenKind::Eof) {
+            self.error(ast.eof(), "expected eof token here");
+        }
+        self.warn_on_reimport();
+    }
+
+    fn visit_yield(&mut self, yields: &Yield) {
+        if !self.in_job {
+            self.error(yields.token(), "the yield statement can only be used from inside a job")
+        }
+    }
+
+    fn visit_import(&mut self, node: &Import) {
+        self.error(node.import_token(), "the 'import' statement is only valid in top-level position")
+    }
+
+    fn visit_option_decl(&mut self, node: &OptionDecl) {
+        self.error(node.option_token(), "the 'option' statement is only valid in top-level position")
+    }
+
+    fn visit_write(&mut self, node: &Write) {
+        self.error(node.write_token(), "the 'write' statement is only valid in the main statement")
+    }
+
+    fn visit_main(&mut self, node: &Main) {
+        self.error(node.main_token(), "the 'main' statement is only valid in top-level position")
+    }
+}
+
+impl StmtChecker<'_> {
+    fn warn_on_reimport(&mut self) {
+        let mut vec: Vec<_> = self
+            .imported
+            .iter()
+            .map(|token| ShortString::new(token.token_type().as_str()))
+            .collect();
+        vec.sort();
+
+        enum State {
+            Empty,
+            Import(ShortString),
+            AlreadyWarned(ShortString),
+        }
+
+        let mut state = State::Empty;
+        for current in vec {
+            match state {
+                // Double import.
+                State::Import(last) if last == current => {
+                    state = State::AlreadyWarned(current);
+                    let token = self
+                        .imported
+                        .iter()
+                        .find(|import| import.token_type().as_str() == last.as_str())
+                        .unwrap()
+                        .clone();
+                    self.warning(token, "already imported");
+                }
+
+                // Multi-import, but already warned.
+                State::AlreadyWarned(ref last) if *last == current => {}
+
+                // Current changed.
+                State::AlreadyWarned(_) | State::Import(_) | State::Empty => state = State::Import(current),
+            }
+        }
+    }
+
+    fn check_option_decl(&mut self, declaration: &OptionDecl) {
+        declaration.declarations().for_each(|(n, ty, v)| match n.token_type() {
+            TokenType::Identifier { identifier } if self.decl_opts.iter().any(|(opt, _)| opt == identifier) => {
+                self.error(n, "redefinition of option");
+            }
+            TokenType::Identifier { identifier } => self.decl_opts.push((
+                identifier.clone(),
+                OptionDefaultValue { expression: v.clone(), type_info: ty.map(|ty| ty.type_info().clone()) },
+            )),
+            token => unreachable!("expected an identifier! {token:?}"),
+        })
+    }
+
+    fn check_import(&mut self, import: &Import) {
+        assert!(import.name().is_kind(TokenKind::StringLiteral), "import name token should be a string literal");
+        self.imported.push(import.name().clone());
+    }
+
+    fn check_option_set(&mut self, assignation: &Assignment) {
+        if !self.is_main.unwrap_or_default() {
+            return self.error(
+                assignation.tokens().next().expect("assignation"),
+                "options can be set only from the main script file",
+            );
+        }
+
+        let handle = |v: &Var| match v {
+            Var::Expression(expression) => {
+                let module = match expression.prefix() {
+                    Prefix::Name(TokenReference {
+                        token: Token { token_type: TokenType::Identifier { identifier }, .. },
+                        ..
+                    }) => identifier.clone(),
+                    prefix => {
+                        let token = prefix.tokens().next().unwrap();
+                        self.error(token, "invalid module name, expected an identifier");
+                        return None;
+                    }
+                };
+
+                let error_token = match expression.suffixes().next() {
+                    Some(Suffix::Index(Index::Dot {
+                        name:
+                            TokenReference { token: Token { token_type: TokenType::Identifier { identifier }, .. }, .. },
+                        ..
+                    })) if expression.suffixes().count() == 1 => return Some((module, identifier.clone())),
+                    Some(suffix) => suffix.tokens().next().unwrap().clone(),
+                    None => expression.tokens().next().unwrap().clone(),
+                };
+                self.error(error_token, "expected a reference to an option by its name, e.g. `module.option`");
+                None
+            }
+
+            Var::Name(name) => match name.token_type() {
+                TokenType::Identifier { identifier } => Some((ShortString::new(self.name), identifier.clone())),
+                _ => unreachable!(),
+            },
+        };
+
+        let options = Vec::from_iter(assignation.variables().iter().flat_map(handle))
+            .into_iter()
+            .zip(assignation.expressions().into_iter().cloned())
+            .map(|((module, name), val)| (module, name, val));
+        self.setd_opts.extend(options);
+    }
+
+    fn check_main(&mut self, main: &Main) {
+        if !self.is_main.unwrap_or_default() {
+            return self.error(main.main_token(), "the main statement must always be in the main script file");
+        } else if self.main.is_some() {
+            return self.error(main.main_token(), "multiple main found");
+        }
+
+        let mut declared_variables = vec![main.initial_variable().clone()];
+        let mut program_steps = Vec::with_capacity(main.assignements().len());
+        for step in main.assignements() {
+            let call_list = step.call_list_items().flat_map(|item| match item {
+                CallListItem::Variable(var) => declared_variables
+                    .contains(var)
+                    .then(|| MainProgramCallListItem::Variable(var.token_type().as_str().into()))
+                    .ok_or_else(|| self.error(var, "use of undeclared variable")),
+
+                CallListItem::SetParameter { parameter, expression, .. } => {
+                    let parameter = parameter.token_type().as_str();
+                    log::error!("check if the job has the parameter {parameter}");
+                    Ok(MainProgramCallListItem::Parameter(ShortString::new(parameter), expression.clone()))
+                }
+            });
+
+            if !declared_variables.contains(step.destination()) {
+                self.error(step.destination(), "redefined variable");
+                continue;
+            }
+
+            let (module, job) = step.called_job_identifiers();
+            log::error!("check if the module and the job are correct…");
+
+            program_steps.push(MainProgramStep::new(
+                step.destination().token_type().as_str().into(),
+                (module.clone(), job.clone()),
+                call_list,
+            ));
+            declared_variables.push(step.destination().clone());
+        }
+
+        let written_variables = main
+            .returns()
+            .map(|write| write.variables())
+            .into_iter()
+            .flat_map(Punctuated::iter);
+        let written_variables = written_variables.flat_map(|written| {
+            declared_variables
+                .contains(written)
+                .then(|| ShortString::new(written.token_type().as_str()))
+                .ok_or_else(|| self.error(written, "try to write a variable that was not declared"))
+        });
+
+        self.main = Some(
+            MainProgram::default()
+                .with_initial(ShortString::new(main.initial_variable().token_type().as_str()))
+                .with_steps(program_steps)
+                .with_returns(written_variables),
+        );
+    }
+}
+
+pub struct OptionDefaultValue {
+    expression: Expression,
+    type_info: Option<TypeInfo>,
+}
+
+impl From<OptionDefaultValue> for Expression {
+    fn from(value: OptionDefaultValue) -> Self {
+        value.expression
+    }
+}
+
+impl OptionDefaultValue {
+    /// Get the default value for the option.
+    pub fn expression(&self) -> &Expression {
+        &self.expression
+    }
+
+    /// Get the type info if specified
+    pub fn type_info(&self) -> Option<&TypeInfo> {
+        self.type_info.as_ref()
+    }
+}
diff --git a/src/Rust/vvs_parser/src/vivy/passes/type_checker.rs b/src/Rust/vvs_parser/src/vivy/passes/type_checker.rs
new file mode 100644
index 0000000000000000000000000000000000000000..712253f5417f5617ee3684b2ef2418dcaa666607
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/passes/type_checker.rs
@@ -0,0 +1,551 @@
+use crate::{
+    ast::*,
+    node::Node,
+    tokenizer::*,
+    traits::DefaultRef,
+    vivy::{library::*, symbol_table::SymbolTable},
+};
+
+crate::declare_pass! {
+    /// The type checker is here to verify type corectness of the program and infer types, etc. To
+    /// check the types we will need to do custom things...
+    visit::TypeChecker: 'a {}
+
+    aux_infos {
+        library: &'a Library,
+        symbol_table: SymbolTable<'a, TypeInfo>,
+    }
+}
+
+impl crate::visitors::Visitor for TypeChecker<'_> {
+    fn visit_ast(&mut self, ast: &Ast) {
+        for error in Vec::from_iter(ast.nodes().stmts().flat_map(|stmt| match stmt {
+            Stmt::JobDeclaration(decl) => self.type_compute().callable(decl.body(), true).err(),
+            Stmt::FunctionDeclaration(decl) => self.type_compute().callable(decl.body(), false).err(),
+            Stmt::LocalFunction(decl) => self.type_compute().callable(decl.body(), false).err(),
+            Stmt::Assignment(assignments) => self.type_compute().assignments(assignments).map(|_| ()).err(),
+            Stmt::OptionDecl(_) | Stmt::Import(_) => None, // NOOP / Types already registered...
+            Stmt::TypeDeclaration(_) => unimplemented!("custom types are tbd"),
+            _ => unreachable!("already checked that they are not here"),
+        })) {
+            self.report
+                .add_errors(self.name, self.source, [crate::Error::AstError(*error)]);
+        }
+        if !ast.eof().is_kind(TokenKind::Eof) {
+            self.error(ast.eof(), "expected eof token here");
+        }
+    }
+}
+
+impl TypeChecker<'_> {
+    fn type_compute(&self) -> TypeCompute {
+        TypeCompute::new(self.library, self.symbol_table.sub_scope())
+    }
+}
+
+/// The thing that will actually compute types and returns errors in case of problems.
+struct TypeCompute<'a> {
+    library: &'a Library,
+    symbols: SymbolTable<'a, TypeInfo>,
+    in_loop: bool,
+    in_job: bool,
+    returns: &'a TypeInfo,
+}
+
+type TypeComputeError = Box<AstError>;
+type TypeComputeResult<'a> = Result<(TypeInfo, SymbolTable<'a, TypeInfo>), TypeComputeError>;
+
+macro_rules! box_error {
+    ($token: expr, $format: literal                   $(,)?) => { Box::new(AstError::from_parts($token.into(), format!($format            ))) };
+    ($token: expr, $format: literal, $($args: expr),+ $(,)?) => { Box::new(AstError::from_parts($token.into(), format!($format, $($args),+))) };
+}
+
+fn unsupported<T>(token: &TokenReference, whats: &str) -> Result<T, TypeComputeError> {
+    Err(box_error!(token, "{whats} are not supported for now"))
+}
+
+impl<'a> TypeCompute<'a> {
+    fn new(library: &'a Library, symbols: SymbolTable<'a, TypeInfo>) -> Self {
+        Self { library, symbols, returns: TypeInfo::default_ref(), in_loop: false, in_job: false }
+    }
+
+    fn sub(&'a self) -> Self {
+        Self { symbols: self.symbols.sub_scope(), ..*self }
+    }
+
+    fn set(mut self, symbol: &TokenReference, ty: TypeInfo) -> Result<Self, TypeComputeError> {
+        self.symbols.set(symbol.token_type().as_str(), ty).map_err(|var| {
+            box_error!(symbol, "{var} was already defined at the root level of the program and is thus a constant")
+        })?;
+        Ok(self)
+    }
+
+    fn in_loop(self) -> Self {
+        Self { in_loop: true, ..self }
+    }
+
+    fn assignments(self, assignments: &'a Assignment) -> TypeComputeResult<'a> {
+        let mut assignments = assignments.variables().iter().zip(assignments.expressions());
+        assignments.try_for_each(|(dest, expr)| self.sub().assignation(dest, expr))?;
+        Ok((TypeInfo::default(), self.symbols))
+    }
+
+    fn check_method_call(
+        self,
+        record: &TypeRecord,
+        method: &MethodCall,
+        caller: &TokenReference,
+        token: &TokenReference,
+    ) -> Result<TypeInfo, TypeComputeError> {
+        let method_name = method.name().token_type().as_str();
+        let (arguments, returns) = match record
+            .method(method_name)
+            .ok_or_else(|| box_error!(token, "undefined method '{caller}:{method_name}'"))?
+        {
+            TypeRecordMethod([this, args @ ..], ret, true) if this == record.type_info() => (args, ret),
+            TypeRecordMethod(args, ret, false) => (args, ret),
+            TypeRecordMethod([this, ..], _, true) => {
+                return Err(box_error!(token, "try to call '{this}:{method_name}' on expression of type '{caller}'"))
+            }
+            TypeRecordMethod(.., true) => unreachable!(),
+        };
+        self.check_func_args(arguments, returns, method.args(), token)
+    }
+
+    fn check_func_args(
+        self,
+        arguments: &[TypeInfo],
+        returns: &TypeInfo,
+        func_args: &FunctionArgs,
+        token: &TokenReference,
+    ) -> Result<TypeInfo, TypeComputeError> {
+        match func_args {
+            FunctionArgs::String(_) => match arguments.first() {
+                Some(type_info) if arguments.len() == 1 && type_info == TypeInfo::string() => Ok(returns.clone()),
+                Some(type_info) if arguments.len() == 1 => Err(box_error!(
+                    token,
+                    "try to pass a string argument to a function that a variable of type {type_info}"
+                )),
+                Some(_) => {
+                    Err(box_error!(token, "try to pass an argument to a function that takes {}", arguments.len()))
+                }
+                None => Err(box_error!(token, "try to pass an argument to a function that takes none",)),
+            },
+
+            FunctionArgs::TableConstructor(_) if arguments.len() != 1 => Err(box_error!(
+                token,
+                "try to pass a table as argument to a function that takes {} arguments",
+                arguments.len()
+            )),
+            FunctionArgs::TableConstructor(args) => {
+                debug_assert_eq!(arguments.len(), 1);
+                todo!("find a way to correctly parse expected types...");
+                // We can pass a table because we expect a table, or because we pass named
+                // arguments...
+            }
+
+            FunctionArgs::Parentheses { arguments: args, .. } => {
+                if args.len() != arguments.len() {
+                    let (arg_len, func_len) = (args.len(), arguments.len());
+                    return Err(box_error!(
+                        token,
+                        "try to pass {arg_len} arguments to a function that takes {func_len}"
+                    ));
+                }
+                let mut arguments = args.iter().enumerate().zip(arguments.iter());
+                match arguments.find_map(|((idx, arg), type_info)| {
+                    self.sub()
+                        .expression_as_type(type_info, arg)
+                        .is_err()
+                        .then(|| (idx, arg.tokens().next().unwrap(), type_info))
+                }) {
+                    Some((n, tok, ty)) => Err(box_error!(tok, "expected argument n°{n} to be of type {ty}")),
+                    None => Ok(returns.clone()),
+                }
+            }
+        }
+    }
+
+    fn expression(self, expression: &'a Expression) -> TypeComputeResult<'a> {
+        match expression {
+            Expression::Parentheses { expression, .. } => self.expression(expression),
+            Expression::FunctionCall(call) => self.suffixes(call.prefix(), call.suffixes()),
+
+            Expression::Number(_) => Ok((TypeInfo::number().clone(), self.symbols)),
+            Expression::String(_) => Ok((TypeInfo::string().clone(), self.symbols)),
+            Expression::TypeAssertion { .. } => Ok((TypeInfo::default(), self.symbols)),
+
+            Expression::Var(Var::Expression(var)) => self.suffixes(var.prefix(), var.suffixes()),
+            Expression::Var(Var::Name(token)) => {
+                let ty = self
+                    .symbols
+                    .get(token.token_type().as_str())
+                    .ok_or_else(|| box_error!(token, "undefined variable"))?;
+                Ok((ty.clone(), self.symbols))
+            }
+
+            Expression::Symbol(token) => match token.token_type() {
+                TokenType::Symbol { symbol: Symbol::Nil } => Ok((TypeInfo::default(), self.symbols)),
+                TokenType::Symbol { symbol: Symbol::False | Symbol::True } => {
+                    Ok((TypeInfo::number().clone(), self.symbols))
+                }
+                _ => unreachable!(),
+            },
+
+            Expression::UnaryOperator { unop, expression } => {
+                use {TypeInfo::*, UnOp::*};
+                let (ty, symbols) = self.expression(expression)?;
+                let is_container =
+                    matches!(ty, Array { .. } | Basic(_) | Optional { .. } | Table { .. } | Tuple { .. });
+                match unop {
+                    Minus(_) | Not(_) | Tilde(_) if ty == *TypeInfo::number() => Ok((ty, symbols)),
+                    Hash(_) if is_container => Ok((TypeInfo::number().clone(), symbols)),
+                    _ => {
+                        Err(box_error!(unop.token(), "can't apply this unary operator to an expression of type '{ty}'"))
+                    }
+                }
+            }
+
+            Expression::BinaryOperator { lhs, binop, rhs } => {
+                use BinOp::*;
+                let ty = self.sub().expression(lhs)?.0;
+                self.sub().expression_as_type(&ty, rhs)?;
+                match binop {
+                    TwoEqual(_) | TildeEqual(_) => Ok((TypeInfo::number().clone(), self.symbols)),
+                    TwoDots(_) if ty == *TypeInfo::string() => Ok((TypeInfo::number().clone(), self.symbols)),
+
+                    GreaterThan(_) | GreaterThanEqual(_) | LessThan(_) | LessThanEqual(_) | DoubleGreaterThan(_)
+                    | DoubleLesserThan(_) | Caret(_) | Pipe(_) | Ampersand(_) | Tilde(_) | Percent(_) | Star(_)
+                    | Slash(_) | DoubleSlash(_) | Minus(_) | Plus(_) | And(_) | Or(_)
+                        if ty == *TypeInfo::number() =>
+                    {
+                        Ok((ty, self.symbols))
+                    }
+
+                    _ => Err(box_error!(
+                        binop.token(),
+                        "can't apply this binary operator to an expression of type '{ty}'",
+                    )),
+                }
+            }
+
+            Expression::IfExpression(_) => todo!(),
+            Expression::TableConstructor(_) => todo!(),
+
+            Expression::Function(_) => unsupported(expression.tokens().next().unwrap(), "lambdas"),
+        }
+    }
+
+    fn suffixes(self, prefix: &'a Prefix, suffixes: impl Iterator<Item = &'a Suffix> + 'a) -> TypeComputeResult<'a> {
+        let prefix = match prefix {
+            Prefix::Expression(expression) => self.sub().expression(expression)?.0,
+            Prefix::Name(token) => self
+                .symbols
+                .get(token.token_type().as_str())
+                .cloned()
+                .ok_or_else(|| box_error!(token, "try to reference an undefined variable or function"))?,
+        };
+
+        let ty = suffixes.into_iter().try_fold(prefix, |prefix, suffix| match prefix {
+            TypeInfo::Callback { arguments, return_type, .. } => match suffix {
+                Suffix::Call(Call::AnonymousCall(call)) => {
+                    let arguments =
+                        Vec::from_iter(arguments.into_iter().map(|TypeArgument { type_info, .. }| type_info));
+                    self.sub()
+                        .check_func_args(&arguments, &return_type, call, suffix.tokens().next().unwrap())
+                }
+                suffix => unreachable!("{suffix:?}"),
+            },
+
+            TypeInfo::Array { type_info, .. } => match suffix {
+                Suffix::Index(Index::Dot { name, .. }) => match name.token_type().as_str() {
+                    "first" | "last" => Ok(*type_info),
+                    field => Err(box_error!(name, "unknown field '{field}' for array")),
+                },
+                Suffix::Index(Index::Brackets { expression, .. }) => self
+                    .sub()
+                    .expression_as_type(TypeInfo::number(), expression)
+                    .map(|_| *type_info),
+                _ => unreachable!(),
+            },
+
+            TypeInfo::Basic(type_name) => {
+                let suffix_token = suffix.tokens().next().unwrap();
+                let record = self
+                    .library
+                    .get(type_name.token_type().as_str())
+                    .ok_or_else(|| box_error!(suffix_token, "try to use undefined type '{type_name}'"))?;
+                match suffix {
+                    Suffix::Call(Call::MethodCall(method)) => {
+                        self.sub().check_method_call(record, method, &type_name, suffix_token)
+                    }
+                    Suffix::Index(Index::Dot { name, .. }) => {
+                        let TypeRecordField(_, field) = record
+                            .field(name.token_type().as_str())
+                            .ok_or_else(|| box_error!(suffix_token, "undefined field for type '{type_name}'"))?;
+                        Ok(field.clone())
+                    }
+                    Suffix::Index(Index::Brackets { expression, .. }) => todo!("{expression}"),
+                    suffix => unreachable!("{suffix}"),
+                }
+            }
+
+            TypeInfo::Tuple { types, .. } => {
+                let index = match suffix {
+                    Suffix::Index(Index::Dot { name: token, .. })
+                    | Suffix::Index(Index::Brackets { expression: Expression::Number(token), .. }) => token,
+                    _ => unreachable!(),
+                };
+                let handle = |str: &str| {
+                    str.parse::<usize>().map_err(|err| {
+                        box_error!(index, "index into a tuple must be a known integer at compilation time: {err}",)
+                    })
+                };
+                let ty = types.iter().nth(match index.token_type() {
+                    TokenType::Identifier { identifier } => match identifier.as_str() {
+                        "zero" | "first" => 0,
+                        "one" | "second" => 1,
+                        "two" => 2,
+                        idx => return Err(box_error!(index, "unknown tuple index: '{idx}'")),
+                    },
+                    TokenType::Number { text } => handle(text.as_str())?,
+                    idx @ TokenType::StringLiteral { .. } => handle(idx.as_str())?,
+                    _ => todo!(),
+                });
+                ty.cloned()
+                    .ok_or_else(|| box_error!(index, "out of range in tuple: ({types})"))
+            }
+
+            TypeInfo::Table { fields, .. } => {
+                let field = match suffix {
+                    Suffix::Index(Index::Brackets { expression: Expression::String(name), .. })
+                    | Suffix::Index(Index::Dot { name, .. }) => name.token_type().as_str(),
+                    _ => unreachable!(),
+                };
+                let field = fields.iter().find_map(|TypeField { key, value, .. }| {
+                    let TypeFieldKey::Name(key) = key else { unreachable!() };
+                    let key = key.token_type().as_str();
+                    (field == key).then_some(value)
+                });
+                field.cloned().ok_or_else(|| {
+                    box_error!(suffix.tokens().next().unwrap(), "failed to find field in {{ {fields} }}")
+                })
+            }
+
+            TypeInfo::Optional { base, .. } => match suffix {
+                Suffix::Call(Call::MethodCall(call)) => match call.args() {
+                    FunctionArgs::Parentheses { arguments, .. } if arguments.is_empty() => {
+                        match call.name().token_type().as_str() {
+                            "is_nil" | "is_value" => Ok(TypeInfo::number().clone()),
+                            "value" => Ok(*base),
+                            m => Err(box_error!(suffix.tokens().next().unwrap(), "unknown method '{base}::{m}'")),
+                        }
+                    }
+                    _ => Err(box_error!(
+                        suffix.tokens().next().unwrap(),
+                        "can't pass parguments to '{base}::{}'",
+                        call.name(),
+                    )),
+                },
+                _ => Err(box_error!(suffix.tokens().next().unwrap(), "incorrect usage of optional value")),
+            },
+
+            TypeInfo::Typeof { .. } => Ok(TypeInfo::string().clone()),
+        })?;
+
+        Ok((ty, self.symbols))
+    }
+
+    fn expression_as_type(self, as_ty: &TypeInfo, expression: &'a Expression) -> Result<(), TypeComputeError> {
+        let (ty, _) = self.sub().expression(expression)?;
+        (ty == *as_ty).then_some(()).ok_or_else(|| {
+            box_error!(expression.tokens().next().unwrap(), "the expression should be of type '{as_ty}', got: '{ty}'",)
+        })
+    }
+
+    fn local_assignment(mut self, assignment: &'a LocalAssignment) -> TypeComputeResult<'a> {
+        let variables = assignment.names().iter();
+        let variables = variables
+            .zip(assignment.type_specifiers().map(|ty| ty.map(TypeSpecifier::type_info)))
+            .zip(assignment.expressions());
+        let variables = variables.map(|((name, ty), val)| {
+            let ty = match ty {
+                None => self.sub().expression(val)?.0,
+                Some(ty) => {
+                    self.sub().expression_as_type(ty, val)?;
+                    ty.clone()
+                }
+            };
+            Ok::<_, TypeComputeError>((name.token_type().as_str().into(), ty))
+        });
+        let symbols = self
+            .symbols
+            .extend(variables.collect::<Result<Vec<_>, TypeComputeError>>()?)
+            .map_err(|variable| {
+                box_error!(assignment.local_token(), "can't declare {variable} because it shadows a global variable",)
+            })?
+            .take();
+        Ok((TypeInfo::default(), symbols))
+    }
+
+    fn compound_assignment(self, assignment: &'a CompoundAssignment) -> TypeComputeResult<'a> {
+        todo!()
+    }
+
+    fn yields(self, yields: &'a Yield) -> TypeComputeResult<'a> {
+        if !self.in_job {
+            Err(box_error!(yields.token(), "yielding values is only possible from jobs"))
+        } else {
+            todo!()
+        }
+    }
+
+    fn assignation(self, variable: &'a Var, expression: &'a Expression) -> Result<(), TypeComputeError> {
+        match variable {
+            Var::Expression(_) => todo!(),
+            Var::Name(variable) => match variable.token_type() {
+                TokenType::Identifier { identifier } if self.symbols.root().get(identifier).is_some() => {
+                    Err(box_error!(variable, "try to assign a global variable"))
+                }
+                TokenType::Identifier { identifier } => match self.symbols.get(identifier).cloned() {
+                    Some(ty) => self.expression_as_type(&ty, expression),
+                    None => Err(box_error!(variable, "try to assign an undefined variable")),
+                },
+                _ => unreachable!(),
+            },
+        }
+    }
+
+    fn stmt(self, stmt: &'a Stmt) -> TypeComputeResult<'a> {
+        match stmt {
+            Stmt::CompoundAssignment(assignments) => self.compound_assignment(assignments),
+            Stmt::LocalAssignment(assignment) => self.local_assignment(assignment),
+            Stmt::Assignment(assignments) => self.assignments(assignments),
+            Stmt::FunctionCall(call) => self.suffixes(call.prefix(), call.suffixes()),
+            Stmt::Yield(yields) => self.yields(yields),
+            Stmt::Do(block) => self.block(block.block()),
+
+            Stmt::If(if_stmt) => {
+                self.sub().expression_as_type(TypeInfo::number(), if_stmt.condition())?;
+                self.sub().block(if_stmt.block())?;
+                for elseif in if_stmt.else_if().into_iter().flatten() {
+                    self.sub().expression_as_type(TypeInfo::number(), elseif.condition())?;
+                    self.sub().block(elseif.block())?;
+                }
+                if let Some(block) = if_stmt.else_block() {
+                    self.sub().block(block)?;
+                }
+                Ok((TypeInfo::default(), self.symbols))
+            }
+
+            Stmt::Repeat(repeat_stmt) => {
+                let symbols = self.sub().block(repeat_stmt.block())?.1;
+                TypeCompute { symbols, ..self }
+                    .in_loop()
+                    .expression_as_type(TypeInfo::number(), repeat_stmt.until())?;
+                Ok((TypeInfo::default(), self.symbols))
+            }
+
+            Stmt::While(while_stmt) => {
+                self.sub()
+                    .expression_as_type(TypeInfo::number(), while_stmt.condition())?;
+                self.sub().in_loop().block(while_stmt.block())?;
+                Ok((TypeInfo::default(), self.symbols))
+            }
+
+            Stmt::NumericFor(for_stmt) => {
+                self.sub().expression_as_type(TypeInfo::number(), for_stmt.start())?;
+                self.sub().expression_as_type(TypeInfo::number(), for_stmt.end())?;
+                if let Some(step) = for_stmt.step() {
+                    self.sub().expression_as_type(TypeInfo::number(), step)?;
+                }
+                self.sub()
+                    .set(for_stmt.index_variable(), TypeInfo::number().clone())?
+                    .block(for_stmt.block())?;
+                Ok((TypeInfo::default(), self.symbols))
+            }
+
+            Stmt::GenericFor(_) => todo!(),
+
+            Stmt::JobDeclaration(decl) => {
+                Err(box_error!(decl.function_token(), "nested declaration of job is forbidden"))
+            }
+
+            Stmt::FunctionDeclaration(decl) => unsupported(decl.function_token(), "nested declaration of functions"),
+            Stmt::LocalFunction(decl) => unsupported(decl.function_token(), "nested declaration of functions"),
+            Stmt::TypeDeclaration(_) => unsupported(stmt.tokens().next().unwrap(), "custom types"),
+
+            Stmt::Import(_) | Stmt::Write(_) | Stmt::Main(_) | Stmt::OptionDecl(_) => {
+                unreachable!("should have been already checked / can't be inside function and job declarations")
+            }
+        }
+    }
+
+    fn last_stmt(self, stmt: &'a LastStmt) -> TypeComputeResult<'a> {
+        match stmt {
+            LastStmt::Break(token) | LastStmt::Continue(token) => match self.in_loop {
+                true => Ok((TypeInfo::default(), self.symbols)),
+                false => Err(box_error!(token, "invalid statement, not inside a loop")),
+            },
+
+            LastStmt::Return(returns) if returns.returns().len() >= 2 => {
+                unsupported(returns.token(), "tuples to return multiple things")
+            }
+            LastStmt::Return(returns) if returns.returns().len() == 1 => (self.returns != TypeInfo::default_ref())
+                .then(|| self.expression(returns.returns().iter().next().unwrap()))
+                .ok_or_else(|| {
+                    box_error!(returns.token(), "function or job returns something, but this return statement is empty")
+                })?,
+            LastStmt::Return(returns) if returns.returns().len() == 1 => (self.returns != TypeInfo::default_ref())
+                .then(|| (TypeInfo::default(), self.symbols))
+                .ok_or_else(|| {
+                    box_error!(
+                        returns.token(),
+                        "expected to return an expression of type {}, but returns nothing here",
+                        self.returns,
+                    )
+                }),
+            LastStmt::Return(_) => unreachable!(),
+        }
+    }
+
+    fn block(self, block: &'a Block) -> TypeComputeResult<'a> {
+        let symbols = block.stmts().try_fold(self.symbols.sub_scope(), |symbols, stmt| {
+            Ok::<_, TypeComputeError>(TypeCompute { symbols, ..self }.stmt(stmt)?.1)
+        })?;
+        Ok(match block.last_stmt() {
+            Some(stmt) => (TypeCompute { symbols, ..self }.last_stmt(stmt)?.0, self.symbols),
+            None => (TypeInfo::default(), self.symbols),
+        })
+    }
+
+    fn callable(mut self, callable: &'a FunctionBody, is_job: bool) -> TypeComputeResult<'a> {
+        self.in_job = is_job;
+        self.returns = callable
+            .return_type()
+            .map(|specifier| specifier.type_info())
+            .unwrap_or(TypeInfo::default_ref());
+
+        if let Some((idx, parameter)) = callable
+            .parameters()
+            .iter()
+            .zip(callable.type_specifiers().map(|ty| ty.map(|ty| ty.type_info())))
+            .enumerate()
+            .find_map(|(idx, (parameter, specifier))| match specifier {
+                Some(ty) => self
+                    .symbols
+                    .set(parameter.token_type().as_str(), ty.clone())
+                    .is_err()
+                    .then_some((idx + 1, parameter)),
+                None => Some((idx + 1, parameter)),
+            })
+        {
+            return Err(box_error!(
+                parameter.tokens().next().unwrap(),
+                "parameter n°{idx} named '{parameter}' has no type specifier or is an ellipse '...' or shadows a global variable",
+            ));
+        }
+
+        self.block(callable.block())
+    }
+}
diff --git a/src/Rust/vvs_parser/src/vivy/passes/type_collector.rs b/src/Rust/vvs_parser/src/vivy/passes/type_collector.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e24536a60e14a80d3169e6c8eec9ac588402cb25
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/passes/type_collector.rs
@@ -0,0 +1,11 @@
+use crate::vivy::library::*;
+
+crate::declare_pass! {
+    /// Collector of custom type, to register them in the library.
+    #[allow(dead_code)]
+    visit::TypeCollector: 'a {}
+
+    aux_infos { library: &'a mut Library }
+}
+
+impl crate::visitors::Visitor for TypeCollector<'_> {}
diff --git a/src/Rust/vvs_parser/src/vivy/search_path.rs b/src/Rust/vvs_parser/src/vivy/search_path.rs
new file mode 100644
index 0000000000000000000000000000000000000000..fd24ed86a9b2edc9d05b7958f06fcb1890e6e23a
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/search_path.rs
@@ -0,0 +1,51 @@
+//! Used to search for other files when using the `import` statement in Vivy Script.
+
+use std::{borrow::Cow, fs, path::PathBuf};
+
+/// Search path, can pass the name of a module and will try to return the associated code.
+#[derive(Default)]
+pub struct SearchPath {
+    folders: Vec<PathBuf>,
+}
+
+/// The extension for vivy script files.
+pub const VIVY_SCRIPT_EXTENSION: &str = "vvs";
+
+impl SearchPath {
+    /// Create a new search path.
+    pub const fn new() -> Self {
+        Self { folders: Vec::new() }
+    }
+
+    /// Resolve the search path to get the desired code.
+    pub fn resolve(&self, import: &str) -> Option<Cow<'static, str>> {
+        self.folders.iter().find_map(|folder| {
+            let mut path = folder.join(import);
+            path.set_extension(VIVY_SCRIPT_EXTENSION);
+            let code = fs::read_to_string(path).ok()?;
+            Some(Cow::Owned(code))
+        })
+    }
+
+    /// Add a folder to the search list.
+    pub fn push(&mut self, folder: PathBuf) {
+        self.folders.push(folder)
+    }
+}
+
+impl Extend<PathBuf> for SearchPath {
+    /// Add multiple folders to the search list.
+    fn extend<T: IntoIterator<Item = PathBuf>>(&mut self, iter: T) {
+        self.folders.extend(iter)
+    }
+}
+
+impl FromIterator<PathBuf> for SearchPath {
+    /// Create a search list from a list of folders.
+    fn from_iter<T: IntoIterator<Item = PathBuf>>(iter: T) -> Self {
+        Self { folders: iter.into_iter().collect() }
+    }
+}
+
+/// The default search path, by default we only search the pre-packaged files.
+pub(crate) static DEFAULT_SEARCH_PATH: SearchPath = SearchPath::new();
diff --git a/src/Rust/vvs_parser/src/vivy/symbol_table.rs b/src/Rust/vvs_parser/src/vivy/symbol_table.rs
new file mode 100644
index 0000000000000000000000000000000000000000..156e6036de0283dee5bee35afef324f90e506459
--- /dev/null
+++ b/src/Rust/vvs_parser/src/vivy/symbol_table.rs
@@ -0,0 +1,103 @@
+use crate::{traits::DefaultRef, ShortString};
+use hashbrown::HashMap;
+use std::ops;
+
+/// The symbol table stores the available symbols with theyr type or whatever.
+pub struct SymbolTable<'a, T> {
+    /// A possible parent for this scope. The invariant is: either [SymbolTable::parent] or
+    /// [SymbolTable::imported] can be non-empty/null.
+    parent: Option<&'a SymbolTable<'a, T>>,
+
+    /// Imported scopes. The invariant is: either [SymbolTable::parent] or [SymbolTable::imported]
+    /// can be non-empty/null.
+    imported: Vec<&'a SymbolTable<'a, T>>,
+
+    /// List of symbols from this scope.
+    symbols: HashMap<ShortString, T>,
+}
+
+impl<T> Default for SymbolTable<'_, T> {
+    fn default() -> Self {
+        Self { parent: None, symbols: HashMap::new(), imported: vec![] }
+    }
+}
+
+impl<'a, T> SymbolTable<'a, T> {
+    /// Create a new sub-scoped symbol table.
+    pub fn sub_scope(&'a self) -> Self {
+        Self { parent: Some(self), symbols: Default::default(), imported: vec![] }
+    }
+
+    /// Add a new variable to the current scope. We override symbols (non-UB shadowing of
+    /// variables). Note that we can't shadow or set variables from the root scope as it denotes
+    /// the global state. In case of error we return the name of the problematic variable.
+    pub fn set(&mut self, symbol: impl Into<ShortString> + AsRef<str>, value: T) -> Result<&mut Self, ShortString> {
+        if self.root().get(symbol.as_ref()).is_none() {
+            self.symbols.insert(symbol.into(), value);
+            Ok(self)
+        } else {
+            Err(symbol.into())
+        }
+    }
+
+    /// Add variables from an iterator. Same rules as [Self::set].
+    pub fn extend(&mut self, iter: impl IntoIterator<Item = (ShortString, T)>) -> Result<&mut Self, ShortString> {
+        iter.into_iter()
+            .try_fold(self, |this, (symbol, value)| this.set(symbol, value))
+    }
+
+    /// Imports other scopes into this one. Note that if this scope is not the root one, then we
+    /// will panic...
+    pub fn import(&mut self, iter: impl IntoIterator<Item = &'a SymbolTable<'a, T>>) -> &mut Self {
+        debug_assert!(self.parent.is_none(), "can't have a parent and import another scope");
+        self.imported.extend(iter);
+        self
+    }
+
+    /// Get the root scope.
+    pub fn root(&self) -> &Self {
+        let mut root = self;
+        while let Some(parent) = root.parent {
+            root = parent;
+        }
+        root
+    }
+
+    /// Get a variable/callback/function from this scope or any parent scope.
+    pub fn get(&self, symbol: impl AsRef<str>) -> Option<&T> {
+        self.symbols
+            .get(symbol.as_ref())
+            .or_else(|| self.parent?.get(symbol.as_ref()))
+            .or_else(|| self.imported.iter().find_map(|scope| scope.get(symbol.as_ref())))
+    }
+
+    /// Consume the mutable reference to give back the owned table.
+    pub(crate) fn take(&mut self) -> Self {
+        std::mem::take(self)
+    }
+}
+
+impl<T> FromIterator<(ShortString, T)> for SymbolTable<'_, T> {
+    fn from_iter<I: IntoIterator<Item = (ShortString, T)>>(iter: I) -> Self {
+        let mut table = Self::default();
+        let _ = table.extend(iter);
+        table
+    }
+}
+
+impl<Idx: AsRef<str>, T: DefaultRef + 'static> ops::Index<Idx> for SymbolTable<'_, T> {
+    type Output = T;
+
+    /// Same as [SymbolTable::get] but we returns a reference to a default value if the variable was not found.
+    fn index(&self, index: Idx) -> &Self::Output {
+        self.get(index).unwrap_or_else(|| T::default_ref())
+    }
+}
+
+impl<'a> SymbolTable<'a, crate::ast::TypeInfo> {
+    /// Create a new type symbol table, e.g. a [SymbolTable] where the values are
+    /// [crate::ast::TypeInfo]. This can be usefull for type checking passes.
+    pub fn new(ast: &crate::ast::Ast, options: Option<&crate::ast::OptionTable>) -> Self {
+        todo!()
+    }
+}
diff --git a/src/Rust/vvs_parser/vivy-script.vim b/src/Rust/vvs_parser/vivy-script.vim
new file mode 100644
index 0000000000000000000000000000000000000000..f5ccddb8c0130f4cbe790d842bf27235ac882e1e
--- /dev/null
+++ b/src/Rust/vvs_parser/vivy-script.vim
@@ -0,0 +1,37 @@
+if exists('b:current_syntax') | finish |  endif
+let b:current_syntax = 'vivy script'
+
+syn keyword VVKeywords          option import set repeat main end do then typeof yield
+syn keyword VVKeywords          for while if else return local in elseif elif until
+syn keyword VVOperators         or xor not and mod
+syn keyword VVBoolean           true false
+syn keyword VVSelf              self
+
+syn keyword VVDeclCallable      function job nextgroup=VVSDeclCallableName
+syn match   VVDeclCallableName  '[a-zA-Z_][a-zA-Z_0-9]*\ze('
+syn match   VVType              ':\ *\zs[a-zA-Z_][a-zA-Z_0-9]*\(<[a-zA-Z_][a-zA-Z_0-9]*>\)\?'
+
+syn region  VVString1           start=/"/ skip=/\\"/ end=/"/
+syn region  VVString2           start=/'/ skip=/\\'/ end=/'/
+syn region  VVString3           start=/\[\[/ end=/\]\]/
+syn match   VVNumber            /-\?\<\d\+\.\d*\(e[+-]\d\+\)\?\>/
+syn match   VVNumber            /-\?\<\d\+\>/
+
+syn match   VVComment1          "--\(-\)\?.*$"
+syn region  VVComment2          start="--\(-\)\?\[\[*" end="\]\]"
+
+syn match   VVVariable          '[A-Z_][A-Z_0-9]*'
+
+hi def link VVDeclCallable      Keyword
+hi def link VVDeclCallableName  Function
+hi def link VVKeywords          Keyword
+hi def link VVOperators         Keyword
+hi def link VVSelf              Constant
+hi def link VVType              Type
+hi def link VVComment1          Comment
+hi def link VVComment2          Comment
+hi def link VVNumber            Float
+hi def link VVBoolean           Boolean
+hi def link VVString1           String
+hi def link VVString2           String
+hi def link VVString3           String
diff --git a/src/Rust/vvs_parser_derive/Cargo.toml b/src/Rust/vvs_parser_derive/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..f25fee11662dd10364747b8466a6031e84bb7ad5
--- /dev/null
+++ b/src/Rust/vvs_parser_derive/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name        = "vvs_parser_derive"
+license     = "MPL-2.0"
+description = "Internally used for the vvs_parser project. Do not use."
+
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+
+[lib]
+proc-macro = true
+
+[dependencies]
+indexmap.workspace    = true
+proc-macro2.workspace = true
+quote.workspace       = true
+
+syn = { version = "1", features = ["extra-traits"] }
diff --git a/src/Rust/vvs_parser_derive/LICENSE.md b/src/Rust/vvs_parser_derive/LICENSE.md
new file mode 100644
index 0000000000000000000000000000000000000000..2b8bbd4546a3f2c86fb661e735422cda8d896427
--- /dev/null
+++ b/src/Rust/vvs_parser_derive/LICENSE.md
@@ -0,0 +1,347 @@
+Mozilla Public License Version 2.0
+==================================
+
+### 1. Definitions
+
+**1.1. “Contributor”**
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+**1.2. “Contributor Version”**
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+**1.3. “Contribution”**
+    means Covered Software of a particular Contributor.
+
+**1.4. “Covered Software”**
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+**1.5. “Incompatible With Secondary Licenses”**
+    means
+
+* **(a)** that the initial Contributor has attached the notice described
+    in Exhibit B to the Covered Software; or
+* **(b)** that the Covered Software was made available under the terms of
+    version 1.1 or earlier of the License, but not also under the
+    terms of a Secondary License.
+
+**1.6. “Executable Form”**
+    means any form of the work other than Source Code Form.
+
+**1.7. “Larger Work”**
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+**1.8. “License”**
+    means this document.
+
+**1.9. “Licensable”**
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+**1.10. “Modifications”**
+    means any of the following:
+
+* **(a)** any file in Source Code Form that results from an addition to,
+    deletion from, or modification of the contents of Covered
+    Software; or
+* **(b)** any new file in Source Code Form that contains any Covered
+    Software.
+
+**1.11. “Patent Claims” of a Contributor**
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+**1.12. “Secondary License”**
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+**1.13. “Source Code Form”**
+    means the form of the work preferred for making modifications.
+
+**1.14. “You” (or “Your”)**
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, “You” includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, “control” means **(a)** the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or **(b)** ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+### 2. License Grants and Conditions
+
+#### 2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+* **(a)** under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+* **(b)** under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+#### 2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+#### 2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+* **(a)** for any code that a Contributor has removed from Covered Software;
+    or
+* **(b)** for infringements caused by: **(i)** Your and any other third party's
+    modifications of Covered Software, or **(ii)** the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+* **(c)** under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+#### 2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+#### 2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+#### 2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+#### 2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+### 3. Responsibilities
+
+#### 3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+#### 3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+* **(a)** such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+* **(b)** You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+#### 3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+#### 3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+#### 3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+### 4. Inability to Comply Due to Statute or Regulation
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: **(a)** comply with
+the terms of this License to the maximum extent possible; and **(b)**
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+### 5. Termination
+
+**5.1.** The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated **(a)** provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and **(b)** on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+**5.2.** If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+### 6. Disclaimer of Warranty
+
+> Covered Software is provided under this License on an “as is”
+> basis, without warranty of any kind, either expressed, implied, or
+> statutory, including, without limitation, warranties that the
+> Covered Software is free of defects, merchantable, fit for a
+> particular purpose or non-infringing. The entire risk as to the
+> quality and performance of the Covered Software is with You.
+> Should any Covered Software prove defective in any respect, You
+> (not any Contributor) assume the cost of any necessary servicing,
+> repair, or correction. This disclaimer of warranty constitutes an
+> essential part of this License. No use of any Covered Software is
+> authorized under this License except under this disclaimer.
+
+### 7. Limitation of Liability
+
+> Under no circumstances and under no legal theory, whether tort
+> (including negligence), contract, or otherwise, shall any
+> Contributor, or anyone who distributes Covered Software as
+> permitted above, be liable to You for any direct, indirect,
+> special, incidental, or consequential damages of any character
+> including, without limitation, damages for lost profits, loss of
+> goodwill, work stoppage, computer failure or malfunction, or any
+> and all other commercial damages or losses, even if such party
+> shall have been informed of the possibility of such damages. This
+> limitation of liability shall not apply to liability for death or
+> personal injury resulting from such party's negligence to the
+> extent applicable law prohibits such limitation. Some
+> jurisdictions do not allow the exclusion or limitation of
+> incidental or consequential damages, so this exclusion and
+> limitation may not apply to You.
+
+### 8. Litigation
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+### 9. Miscellaneous
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+### 10. Versions of the License
+
+#### 10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+#### 10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+#### 10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+## Exhibit A - Source Code Form License Notice
+
+    This Source Code Form is subject to the terms of the Mozilla Public
+    License, v. 2.0. If a copy of the MPL was not distributed with this
+    file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+## Exhibit B - “Incompatible With Secondary Licenses” Notice
+
+    This Source Code Form is "Incompatible With Secondary Licenses", as
+    defined by the Mozilla Public License, v. 2.0.
diff --git a/src/Rust/vvs_parser_derive/src/derive.rs b/src/Rust/vvs_parser_derive/src/derive.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4d6c5cf9d6761ae7d26742f5968d2f94a382b2da
--- /dev/null
+++ b/src/Rust/vvs_parser_derive/src/derive.rs
@@ -0,0 +1,139 @@
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use syn::{parse_macro_input, DeriveInput};
+
+pub trait DeriveGenerator: EnumGenerator + StructGenerator {
+    fn complete(input: &syn::DeriveInput, tokens: TokenStream) -> TokenStream;
+
+    fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+        let input = parse_macro_input!(input as DeriveInput);
+
+        let expanded = match &input.data {
+            syn::Data::Enum(data) => <Self as EnumGenerator>::generate(&input.ident, data),
+            syn::Data::Struct(data) => <Self as StructGenerator>::generate(&input.ident, data),
+            _ => unimplemented!(),
+        };
+
+        Self::complete(&input, expanded).into()
+    }
+}
+
+pub trait EnumGenerator {
+    fn generate(input: &syn::Ident, enumm: &syn::DataEnum) -> TokenStream;
+}
+
+pub trait StructGenerator {
+    fn generate(input: &syn::Ident, strukt: &syn::DataStruct) -> TokenStream;
+}
+
+pub trait MatchEnumGenerator {
+    const DEREF: bool = false;
+    const SELF: &'static str = "self";
+
+    fn complete(input: TokenStream) -> TokenStream {
+        input
+    }
+
+    fn case_named(_input: &syn::Ident, _variant: &syn::Ident, _fields: &syn::FieldsNamed) -> TokenStream {
+        quote! {}
+    }
+
+    fn case_unnamed(_input: &syn::Ident, _variant: &syn::Ident, _fields: &syn::FieldsUnnamed) -> TokenStream {
+        quote! {}
+    }
+
+    fn case_unit(_input: &syn::Ident, _variant: &syn::Ident) -> TokenStream {
+        quote! {}
+    }
+}
+
+impl<T: MatchEnumGenerator> EnumGenerator for T {
+    fn generate(input_ident: &syn::Ident, enumm: &syn::DataEnum) -> TokenStream {
+        let mut cases = Vec::with_capacity(enumm.variants.len());
+
+        for variant in &enumm.variants {
+            let variant_ident = &variant.ident;
+
+            match &variant.fields {
+                syn::Fields::Named(fields) => {
+                    cases.push(T::case_named(input_ident, variant_ident, fields));
+                }
+
+                syn::Fields::Unnamed(fields) => {
+                    cases.push(T::case_unnamed(input_ident, variant_ident, fields));
+                }
+
+                syn::Fields::Unit => cases.push(T::case_unit(input_ident, variant_ident)),
+            }
+        }
+
+        let self_ident = format_ident!("{}", T::SELF);
+        let deref = if T::DEREF { Some(quote! { * }) } else { None };
+
+        T::complete(quote! {
+            match #deref #self_ident {
+                #(#cases)*
+            }
+        })
+    }
+}
+
+pub trait Hint
+where
+    Self: Sized,
+{
+    fn key_value(_key: String, _value: String) -> Option<Self> {
+        None
+    }
+
+    fn unit(_name: String) -> Option<Self> {
+        None
+    }
+}
+
+pub fn search_hint<T: Hint>(name: &str, attrs: &[syn::Attribute]) -> Option<T> {
+    macro_rules! path_ident {
+        ($path:expr) => {
+            match $path.get_ident() {
+                Some(ident) => ident,
+                None => continue,
+            }
+        };
+    }
+
+    for attr in attrs {
+        let meta = match attr.parse_meta() {
+            Ok(meta) => meta,
+            Err(_) => continue,
+        };
+
+        if path_ident!(meta.path()) != name {
+            continue;
+        };
+
+        if let syn::Meta::List(list) = meta {
+            for nested in list.nested {
+                match nested {
+                    syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
+                        return T::unit(path_ident!(path).to_string());
+                    }
+
+                    syn::NestedMeta::Meta(syn::Meta::NameValue(name_value)) => {
+                        return T::key_value(
+                            path_ident!(name_value.path).to_string(),
+                            match name_value.lit {
+                                syn::Lit::Str(lit_str) => lit_str.value(),
+
+                                other => unimplemented!("nested meta value: {:#?}", other),
+                            },
+                        );
+                    }
+
+                    other => unimplemented!("unknown attribute: {:#?}", other),
+                }
+            }
+        }
+    }
+
+    None
+}
diff --git a/src/Rust/vvs_parser_derive/src/lib.rs b/src/Rust/vvs_parser_derive/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d62ebbc2ed3a1b7313baf43ee36a1d665aa3afc4
--- /dev/null
+++ b/src/Rust/vvs_parser_derive/src/lib.rs
@@ -0,0 +1,21 @@
+#![recursion_limit = "128"]
+
+extern crate proc_macro;
+
+mod derive;
+mod node;
+mod visit;
+
+use derive::DeriveGenerator;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Visit, attributes(visit))]
+pub fn derive_visit(input: TokenStream) -> TokenStream {
+    visit::VisitGenerator::derive(input)
+}
+
+#[proc_macro_derive(Node, attributes(node))]
+pub fn derive_node(input: TokenStream) -> TokenStream {
+    node::NodeGenerator::derive(input)
+}
diff --git a/src/Rust/vvs_parser_derive/src/node.rs b/src/Rust/vvs_parser_derive/src/node.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5efb943949dbc6cc61c890b0f2b24e4d6c8d93f4
--- /dev/null
+++ b/src/Rust/vvs_parser_derive/src/node.rs
@@ -0,0 +1,429 @@
+use crate::derive::*;
+
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+
+fn token_getter(ty: &syn::Type, ident: &syn::Ident, mut prefix: Option<TokenStream>, deref: bool) -> TokenStream {
+    if let syn::Type::Path(path) = ty {
+        let token_ref = path.path.segments.first().expect("no first segment?");
+
+        // Clippy suggests *cow.ident, which doesn't work
+        #[allow(clippy::cmp_owned)]
+        if token_ref.ident.to_string() == "TokenReference" {
+            return quote! {
+                crate::node::TokenItem::TokenReference(&#prefix #ident)
+            };
+        }
+    }
+
+    if deref {
+        prefix = Some(quote! { * });
+    }
+
+    quote! {
+        crate::node::TokenItem::MoreTokens(&#prefix #ident)
+    }
+}
+
+#[derive(PartialEq)]
+enum NodeHint {
+    FullRange,
+}
+
+impl Hint for NodeHint {
+    fn unit(name: String) -> Option<Self> {
+        if name == "full_range" {
+            Some(NodeHint::FullRange)
+        } else {
+            None
+        }
+    }
+}
+
+pub struct NodeGenerator;
+
+impl DeriveGenerator for NodeGenerator {
+    fn complete(input: &syn::DeriveInput, tokens: TokenStream) -> TokenStream {
+        let input_ident = &input.ident;
+        let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+
+        let macro_name = format_ident!("NodeGenerator{}", input_ident);
+
+        let pattern = quote! {{
+            range => $range:expr,
+            similar => $similar:expr,
+            tokens => $tokens:expr,
+        }};
+
+        quote! {
+            macro_rules! #macro_name {
+                ("range", #pattern) => {
+                    $range
+                };
+
+                ("similar", #pattern) => {
+                    $similar
+                };
+
+                ("tokens", #pattern) => {
+                    $tokens
+                }
+            }
+
+            impl #impl_generics crate::node::Node #impl_generics for #input_ident #ty_generics #where_clause {
+                fn start_position(&self) -> Option<crate::tokenizer::Position> {
+                    Some(#macro_name!("range", { #tokens })?.0)
+                }
+
+                fn end_position(&self) -> Option<crate::tokenizer::Position> {
+                    Some(#macro_name!("range", { #tokens })?.1)
+                }
+
+                fn similar(&self, other: &Self) -> bool {
+                    #macro_name!("similar", { #tokens })
+                }
+
+                fn tokens<'a>(&'a self) -> crate::node::Tokens<'a> {
+                    #macro_name!("tokens", { #tokens })
+                }
+            }
+
+            impl #impl_generics crate::private::Sealed for #input_ident #ty_generics #where_clause {}
+        }
+    }
+}
+
+impl StructGenerator for NodeGenerator {
+    fn generate(ident: &syn::Ident, strukt: &syn::DataStruct) -> TokenStream {
+        let range = StructRangeGenerator::generate(ident, strukt);
+        let similar = StructSimilarGenerator::generate(ident, strukt);
+        let tokens = StructTokensGenerator::generate(ident, strukt);
+
+        quote! {
+            range => { #range },
+            similar => { #similar },
+            tokens => { #tokens },
+        }
+    }
+}
+
+pub struct StructRangeGenerator;
+
+impl StructGenerator for StructRangeGenerator {
+    fn generate(_: &syn::Ident, strukt: &syn::DataStruct) -> TokenStream {
+        let fields = strukt
+            .fields
+            .iter()
+            .map(|field| field.ident.as_ref().unwrap())
+            .collect::<Vec<_>>();
+
+        let full_range = strukt
+            .fields
+            .iter()
+            .find(|field| search_hint("node", &field.attrs) == Some(NodeHint::FullRange));
+
+        if let Some(full_range) = full_range {
+            let ident = full_range.ident.as_ref().unwrap();
+            quote! {
+                self.#ident.range()
+            }
+        } else {
+            let (mut start_position, mut end_position) =
+                (Vec::with_capacity(fields.len()), Vec::with_capacity(fields.len()));
+
+            for field in &fields {
+                start_position.push(quote! {
+                    .or_else(|| {
+                        self.#field.start_position()
+                    })
+                });
+            }
+
+            for field in fields.iter().rev() {
+                end_position.push(quote! {
+                    .or_else(|| {
+                        self.#field.end_position()
+                    })
+                });
+            }
+
+            quote! {
+                Some((None #(#start_position)*?, None #(#end_position)*?))
+            }
+        }
+    }
+}
+
+pub struct StructSimilarGenerator;
+
+impl StructGenerator for StructSimilarGenerator {
+    fn generate(_: &syn::Ident, strukt: &syn::DataStruct) -> TokenStream {
+        let fields = strukt
+            .fields
+            .iter()
+            .map(|field| field.ident.as_ref().unwrap())
+            .collect::<Vec<_>>();
+
+        quote! {
+            #(
+                self.#fields.similar(&other.#fields) &&
+            )* true
+        }
+    }
+}
+
+pub struct StructTokensGenerator;
+
+impl StructGenerator for StructTokensGenerator {
+    fn generate(_: &syn::Ident, strukt: &syn::DataStruct) -> TokenStream {
+        let mut getters = Vec::with_capacity(strukt.fields.len());
+
+        for field in &strukt.fields {
+            getters.push(token_getter(
+                &field.ty,
+                field.ident.as_ref().unwrap(),
+                Some(quote! {
+                    self.
+                }),
+                false,
+            ));
+        }
+
+        quote! {
+            crate::node::Tokens {
+                items: vec![#(
+                    #getters,
+                )*],
+            }
+        }
+    }
+}
+
+impl EnumGenerator for NodeGenerator {
+    fn generate(ident: &syn::Ident, enumm: &syn::DataEnum) -> TokenStream {
+        let range = EnumRangeGenerator::generate(ident, enumm);
+        let similar = EnumSimilarGenerator::generate(ident, enumm);
+        let tokens = EnumTokensGenerator::generate(ident, enumm);
+
+        quote! {
+            range => {
+                #[allow(unused)]
+                #range
+            },
+
+            similar => { #similar },
+            tokens => { #tokens },
+        }
+    }
+}
+
+pub struct EnumRangeGenerator;
+
+impl MatchEnumGenerator for EnumRangeGenerator {
+    fn case_named(input: &syn::Ident, variant: &syn::Ident, named: &syn::FieldsNamed) -> TokenStream {
+        let fields = named
+            .named
+            .iter()
+            .map(|field| field.ident.as_ref().unwrap())
+            .collect::<Vec<_>>();
+
+        let full_range = named
+            .named
+            .iter()
+            .find(|field| search_hint("node", &field.attrs) == Some(NodeHint::FullRange));
+
+        let body = if let Some(full_range) = full_range {
+            let ident = full_range.ident.as_ref().unwrap();
+            quote! {
+                #ident.range()
+            }
+        } else {
+            let (mut start_position, mut end_position) =
+                (Vec::with_capacity(fields.len()), Vec::with_capacity(fields.len()));
+
+            for field in &fields {
+                start_position.push(quote! {
+                    .or_else(|| {
+                        #field.start_position()
+                    })
+                });
+            }
+
+            for field in fields.iter().rev() {
+                end_position.push(quote! {
+                    .or_else(|| {
+                        #field.end_position()
+                    })
+                });
+            }
+
+            quote! {
+                Some((None #(#start_position)*?, None #(#end_position)*?))
+            }
+        };
+
+        quote! {
+            #input::#variant {
+                #(#fields,)*
+            } => {
+                #body
+            }
+        }
+    }
+
+    fn case_unnamed(input: &syn::Ident, variant: &syn::Ident, fields: &syn::FieldsUnnamed) -> TokenStream {
+        let fields = &fields.unnamed;
+
+        if fields.len() == 1 {
+            quote! {
+                #input::#variant(inner) => {
+                    Some((inner.start_position()?, inner.end_position()?))
+                }
+            }
+        } else {
+            let fields_count = fields.len() - 1;
+            let field_match: Vec<_> = fields
+                .iter()
+                .enumerate()
+                .map(|(index, _)| {
+                    syn::Ident::new(
+                        match index {
+                            0 => "first",
+                            _x if _x == fields_count => "last",
+                            _ => "_",
+                        },
+                        variant.span(),
+                    )
+                })
+                .collect();
+
+            quote! {
+                #input::#variant(
+                    #(#field_match,)*
+                ) => {
+                    Some((first.start_position()?, last.end_position()?))
+                }
+            }
+        }
+    }
+}
+
+pub struct EnumSimilarGenerator;
+
+impl MatchEnumGenerator for EnumSimilarGenerator {
+    fn case_named(input: &syn::Ident, variant: &syn::Ident, named: &syn::FieldsNamed) -> TokenStream {
+        let fields = named
+            .named
+            .iter()
+            .map(|field| field.ident.as_ref().unwrap())
+            .collect::<Vec<_>>();
+
+        let other_fields: Vec<_> = fields.iter().map(|ident| format_ident!("other_{}", ident)).collect();
+
+        quote! {
+            #input::#variant {
+                #(#fields,)*
+            } => {
+                if let #input::#variant {
+                    #(
+                        #fields: #other_fields,
+                    )*
+                } = &other {
+                    #(
+                        #fields.similar(#other_fields) &&
+                    )* true
+                } else {
+                    false
+                }
+            }
+        }
+    }
+
+    fn case_unnamed(input: &syn::Ident, variant: &syn::Ident, fields: &syn::FieldsUnnamed) -> TokenStream {
+        let fields: Vec<_> = fields
+            .unnamed
+            .iter()
+            .enumerate()
+            .map(|(index, _)| format_ident!("__self_{}", index))
+            .collect();
+
+        let other_fields: Vec<_> = fields.iter().map(|ident| format_ident!("other_{}", ident)).collect();
+
+        quote! {
+            #input::#variant(
+                #(#fields,)*
+            ) => {
+                if let #input::#variant(#(#other_fields,)*) = &other {
+                    #(
+                        #fields.similar(#other_fields) &&
+                    )* true
+                } else {
+                    false
+                }
+            }
+        }
+    }
+
+    fn case_unit(input: &syn::Ident, variant: &syn::Ident) -> TokenStream {
+        quote! {
+            #input::#variant => other == #input::#variant
+        }
+    }
+}
+
+pub struct EnumTokensGenerator;
+
+impl MatchEnumGenerator for EnumTokensGenerator {
+    const DEREF: bool = true;
+
+    fn case_named(input: &syn::Ident, variant: &syn::Ident, named: &syn::FieldsNamed) -> TokenStream {
+        let named = &named.named;
+
+        let mut fields = Vec::with_capacity(named.len());
+        let mut getters = Vec::with_capacity(named.len());
+
+        for field in named {
+            fields.push(field.ident.as_ref().unwrap());
+            getters.push(token_getter(&field.ty, field.ident.as_ref().unwrap(), None, true));
+        }
+
+        quote! {
+            #input::#variant {
+                #(ref #fields,)*
+            } => {
+                crate::node::Tokens {
+                    items: vec![#(
+                        #getters,
+                    )*],
+                }
+            }
+        }
+    }
+
+    fn case_unnamed(input: &syn::Ident, variant: &syn::Ident, fields: &syn::FieldsUnnamed) -> TokenStream {
+        let names: Vec<_> = fields
+            .unnamed
+            .iter()
+            .enumerate()
+            .map(|(index, _)| format_ident!("__self_{}", index))
+            .collect();
+
+        let mut getters = Vec::with_capacity(fields.unnamed.len());
+
+        for (field, name) in fields.unnamed.iter().zip(&names) {
+            getters.push(token_getter(&field.ty, name, None, true));
+        }
+
+        quote! {
+            #input::#variant(
+                #(ref #names,)*
+             ) => {
+                crate::node::Tokens {
+                    items: vec![#(
+                        #getters,
+                    )*],
+                }
+            }
+        }
+    }
+}
diff --git a/src/Rust/vvs_parser_derive/src/visit.rs b/src/Rust/vvs_parser_derive/src/visit.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2eb585ca08bbd317dcaf69ef218cf05c8f5d91d7
--- /dev/null
+++ b/src/Rust/vvs_parser_derive/src/visit.rs
@@ -0,0 +1,264 @@
+use crate::derive::*;
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+use std::collections::HashMap;
+
+// Not 100% accurate, but it is to full-moon's codebase
+fn snake_case(pascal_case: &str) -> String {
+    let mut chars = pascal_case.chars();
+    let mut result = chars.next().unwrap().to_ascii_lowercase().to_string();
+
+    for character in chars {
+        if character.is_ascii_uppercase() {
+            result.push('_');
+            result.push(character.to_ascii_lowercase());
+        } else {
+            result.push(character);
+        }
+    }
+
+    result
+}
+
+#[derive(Debug, PartialEq)]
+enum VisitHint {
+    Contains(String),
+    Skip,
+    SkipVisitSelf,
+    VisitAs(String),
+}
+
+impl Hint for VisitHint {
+    fn key_value(key: String, value: String) -> Option<Self> {
+        if key == "visit_as" {
+            Some(VisitHint::VisitAs(value))
+        } else if key == "contains" {
+            Some(VisitHint::Contains(value))
+        } else {
+            None
+        }
+    }
+
+    fn unit(name: String) -> Option<Self> {
+        match name.as_str() {
+            "skip" => Some(VisitHint::Skip),
+            "skip_visit_self" => Some(VisitHint::SkipVisitSelf),
+            _ => None,
+        }
+    }
+}
+
+pub struct VisitGenerator;
+
+impl VisitGenerator {
+    fn visit_fields(data_fields: &syn::Fields, prefix: TokenStream) -> TokenStream {
+        let mut fields = Vec::new();
+        let mut contains = HashMap::new();
+
+        for field in data_fields
+            .iter()
+            .filter(|field| search_hint("visit", &field.attrs) != Some(VisitHint::Skip))
+        {
+            let ident = field.ident.as_ref().unwrap();
+            let token_stream = quote! { #prefix #ident };
+
+            if let Some(VisitHint::Contains(contains_node)) = search_hint("visit", &field.attrs) {
+                contains.insert(contains_node, ident);
+            } else if let Some(contains_me) = contains.remove(&ident.to_string()) {
+                fields.push(quote! {
+                    #prefix #contains_me.tokens.0
+                });
+
+                fields.push(token_stream);
+
+                fields.push(quote! {
+                    #prefix #contains_me.tokens.1
+                });
+            } else {
+                fields.push(token_stream);
+            }
+        }
+
+        assert!(contains.is_empty(), "#[visit(contains = \"...\")] used in wrong order: {contains:?}",);
+
+        quote! {
+            #(visit!(#fields, visitor);)*
+        }
+    }
+}
+
+impl DeriveGenerator for VisitGenerator {
+    fn complete(input: &syn::DeriveInput, tokens: TokenStream) -> TokenStream {
+        let input_ident = &input.ident;
+        let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+
+        let (visit_self, visit_self_end) = match search_hint("visit", &input.attrs) {
+            Some(VisitHint::SkipVisitSelf) => (quote! {}, quote! {}),
+            Some(VisitHint::VisitAs(visit_as)) => {
+                let visit_as_end = syn::Ident::new(&format!("visit_{visit_as}_end"), input_ident.span());
+                let visit_as = syn::Ident::new(&format!("visit_{visit_as}"), input_ident.span());
+
+                (
+                    quote! {
+                        visit_self!(#visit_as);
+                    },
+                    quote! {
+                        visit_self!(#visit_as_end);
+                    },
+                )
+            }
+            _ => {
+                // name of self in snake_case
+                let ssself =
+                    syn::Ident::new(&format!("visit_{}", snake_case(&input_ident.to_string())), input_ident.span());
+
+                let ssself_end =
+                    syn::Ident::new(&format!("visit_{}_end", snake_case(&input_ident.to_string())), input_ident.span());
+
+                (
+                    quote! {
+                        visit_self!(#ssself);
+                    },
+                    quote! {
+                        visit_self!(#ssself_end);
+                    },
+                )
+            }
+        };
+
+        quote! {
+            #[allow(unused_macros)]
+            impl #impl_generics crate::visitors::Visit for #input_ident #ty_generics #where_clause {
+                fn visit<V: crate::visitors::Visitor>(&self, visitor: &mut V) {
+                    macro_rules! visit {
+                        ($visit_what: expr, $visitor: expr) => {
+                            $visit_what.visit($visitor);
+                        }
+                    }
+
+                    macro_rules! visit_self {
+                        ($name: ident) => {
+                            visitor.$name(self);
+                        }
+                    }
+
+                    macro_rules! set_self {
+                        ($value: expr) => {
+                            $value;
+                        }
+                    }
+
+                    macro_rules! if_visit {
+                        ({ $($used: expr)* } else { $($unused: expr)* }) => {
+                            {
+                                $($used;)*
+                            }
+                        }
+                    }
+
+                    #visit_self
+                    #tokens
+                    #visit_self_end
+                }
+            }
+
+            #[allow(unused_macros)]
+            impl #impl_generics crate::visitors::VisitMut for #input_ident #ty_generics #where_clause {
+                fn visit_mut<V: crate::visitors::VisitorMut>(mut self, visitor: &mut V) -> Self {
+                    macro_rules! visit {
+                        ($visit_what: expr, $visitor: expr) => {
+                            $visit_what = $visit_what.visit_mut($visitor);
+                        }
+                    }
+
+                    macro_rules! visit_self {
+                        ($name: ident) => {
+                            self = visitor.$name(self);
+                        }
+                    }
+
+                    macro_rules! set_self {
+                        ($value: expr) => {
+                            self = $value;
+                        }
+                    }
+
+                    macro_rules! if_visit {
+                        ({ $($unused: expr)* } else { $($used: expr)* }) => {
+                            $($used)*
+                        }
+                    }
+
+                    #visit_self
+                    #tokens
+                    #visit_self_end
+                    self
+                }
+            }
+        }
+    }
+}
+
+impl StructGenerator for VisitGenerator {
+    fn generate(_: &syn::Ident, strukt: &syn::DataStruct) -> TokenStream {
+        Self::visit_fields(&strukt.fields, quote! {self.})
+    }
+}
+
+impl MatchEnumGenerator for VisitGenerator {
+    fn complete(input: TokenStream) -> TokenStream {
+        quote! {
+            set_self!(#input);
+        }
+    }
+
+    fn case_named(input: &syn::Ident, variant: &syn::Ident, named: &syn::FieldsNamed) -> TokenStream {
+        let fields: Vec<_> = named.named.iter().map(|field| field.ident.as_ref().unwrap()).collect();
+
+        quote! {
+            #input::#variant {
+                #(#fields,)*
+            } => {
+                if_visit!({
+                    #(
+                        #fields.visit(visitor)
+                    )*
+                } else {
+                    #input::#variant {
+                        #(
+                            #fields: #fields.visit_mut(visitor),
+                        )*
+                    }
+                })
+            }
+        }
+    }
+
+    fn case_unnamed(input: &syn::Ident, variant: &syn::Ident, fields: &syn::FieldsUnnamed) -> TokenStream {
+        let fields: Vec<_> = fields
+            .unnamed
+            .iter()
+            .enumerate()
+            .map(|(index, _)| format_ident!("__self_{}", index))
+            .collect();
+        let fields = &fields;
+
+        quote! {
+            #input::#variant(
+                #(#fields,)*
+            ) => {
+                if_visit!({
+                    #(
+                        #fields.visit(visitor)
+                    )*
+                } else {
+                    #input::#variant(
+                        #(
+                            #fields.visit_mut(visitor),
+                        )*
+                    )
+                })
+            }
+        }
+    }
+}
diff --git a/src/Rust/vvs_procmacro/Cargo.toml b/src/Rust/vvs_procmacro/Cargo.toml
index 3e99f27c4f2c4e3f9b13b4b8108390ba1fc94874..a2e00d0e0d56768f33c529876d51decc8c0d35fc 100644
--- a/src/Rust/vvs_procmacro/Cargo.toml
+++ b/src/Rust/vvs_procmacro/Cargo.toml
@@ -1,15 +1,17 @@
 [package]
-name = "vvs_procmacro"
+name              = "vvs_procmacro"
+description       = "The procmacro utility crate for VVS"
 version.workspace = true
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
-description = "The procmacro utility crate for VVS"
 
 [lib]
 proc-macro = true
 
 [dependencies]
-syn = { version = "2.0", features = ["full"] }
-quote = "1.0"
-proc-macro2 = "1.0"
+quote.workspace       = true
+proc-macro2.workspace = true
+anyhow.workspace      = true
+
+syn = { version = "2", features = ["full"] }
diff --git a/src/Rust/vvs_procmacro/src/enums.rs b/src/Rust/vvs_procmacro/src/enums.rs
new file mode 100644
index 0000000000000000000000000000000000000000..54d115eda51068d501bfc5706f1e939fbd3b8f4f
--- /dev/null
+++ b/src/Rust/vvs_procmacro/src/enums.rs
@@ -0,0 +1,62 @@
+//! Implement what is needed to make life easier with C-like enums in Rust.
+
+use proc_macro2::*;
+use quote::*;
+
+pub(crate) fn impl_derive_enum_variant_count(syn_item: syn::DeriveInput) -> TokenStream {
+    let (len, name) = match syn_item.data {
+        syn::Data::Enum(enum_item) => (
+            enum_item.variants.len(),
+            Ident::new(&format!("{}_LENGTH", syn_item.ident.to_string().to_uppercase()), syn_item.ident.span()),
+        ),
+        _ => panic!("EnumVariantCount only works on Enums"),
+    };
+    quote! { pub const #name : usize = #len; }
+}
+
+pub(crate) fn impl_derive_enum_variant_iter(syn_item: syn::DeriveInput) -> TokenStream {
+    let (enum_name, name, content) = match syn_item.data {
+        syn::Data::Enum(enum_item) => {
+            let variants = enum_item
+                .variants
+                .into_iter()
+                .map(|variant| format!("{}::{}", syn_item.ident, variant.ident));
+            let variants = variants.collect::<Vec<_>>().join(", ");
+            (
+                syn_item.ident.clone(),
+                Ident::new(&format!("{}_VALUES", syn_item.ident.to_string().to_uppercase()), syn_item.ident.span()),
+                syn::parse_str::<syn::Expr>(&format!("&[ {variants} ]"))
+                    .expect("failed generation of enum's variant list"),
+            )
+        }
+        _ => panic!("EnumVariantIter only works on Enums"),
+    };
+    quote! { pub const #name : &[#enum_name] = #content; }
+}
+
+pub(crate) fn impl_derive_enum_variant_from_str(syn_item: syn::DeriveInput) -> TokenStream {
+    let enum_item = match syn_item.data {
+        syn::Data::Enum(enum_item) => enum_item,
+        _ => panic!("EnumVariantFromStr only works on Enums"),
+    };
+    let name = syn_item.ident;
+    let match_branches = enum_item
+        .variants
+        .into_iter()
+        .map(|variant| format!("{:?} => Ok({name}::{}),", variant.ident.to_string().to_lowercase(), variant.ident))
+        .chain(Some("_ => Err(format!(\"unknown field '{{s}}'\")),".to_string()))
+        .collect::<Vec<_>>()
+        .join("");
+    let match_branches =
+        syn::parse_str::<syn::Expr>(&format!("match s.trim().to_lowercase().as_str() {{ {match_branches} }}"))
+            .expect("failed generation of enum's FromStr implementation");
+    quote! {
+        impl std::str::FromStr for #name {
+            type Err = std::string::String;
+            fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+                #match_branches
+            }
+
+        }
+    }
+}
diff --git a/src/Rust/vvs_procmacro/src/lib.rs b/src/Rust/vvs_procmacro/src/lib.rs
index 64bbd40ddfc3d205048f3e5b2ecc4bb5eb0800f6..3085206b376fbe293412f6efffd2524b691d8618 100644
--- a/src/Rust/vvs_procmacro/src/lib.rs
+++ b/src/Rust/vvs_procmacro/src/lib.rs
@@ -1,85 +1,63 @@
-#![forbid(unsafe_code)]
+mod enums;
+mod vvrt;
 
 use proc_macro::TokenStream;
-use proc_macro2::*;
-use quote::*;
-use syn::{parse_macro_input, DeriveInput};
+use quote::quote;
+use syn::parse_macro_input;
 
 #[proc_macro_derive(EnumVariantCount)]
 pub fn derive_enum_variant_count(input: TokenStream) -> TokenStream {
-    let syn_item = parse_macro_input!(input as DeriveInput);
-    let (len, name) = match syn_item.data {
-        syn::Data::Enum(enum_item) => (
-            enum_item.variants.len(),
-            Ident::new(
-                &format!("{}_LENGTH", syn_item.ident.to_string().to_uppercase()),
-                syn_item.ident.span(),
-            ),
-        ),
-        _ => panic!("EnumVariantCount only works on Enums"),
-    };
-    quote! { pub const #name : usize = #len; }.into()
+    let input = parse_macro_input!(input as syn::DeriveInput);
+    enums::impl_derive_enum_variant_count(input).into()
 }
 
 #[proc_macro_derive(EnumVariantIter)]
 pub fn derive_enum_variant_iter(input: TokenStream) -> TokenStream {
-    let syn_item = parse_macro_input!(input as DeriveInput);
-    let (enum_name, name, content) = match syn_item.data {
-        syn::Data::Enum(enum_item) => (
-            syn_item.ident.clone(),
-            Ident::new(
-                &format!("{}_VALUES", syn_item.ident.to_string().to_uppercase()),
-                syn_item.ident.span(),
-            ),
-            syn::parse_str::<syn::Expr>(&format!(
-                "&[ {} ]",
-                enum_item
-                    .variants
-                    .into_iter()
-                    .map(|variant| format!("{}::{}", syn_item.ident, variant.ident))
-                    .collect::<Vec<_>>()
-                    .join(", "),
-            ))
-            .expect("failed generation of enum's variant list"),
-        ),
-        _ => panic!("EnumVariantIter only works on Enums"),
-    };
-    quote! { pub const #name : &[#enum_name] = #content; }.into()
+    let input = parse_macro_input!(input as syn::DeriveInput);
+    enums::impl_derive_enum_variant_iter(input).into()
 }
 
 #[proc_macro_derive(EnumVariantFromStr)]
 pub fn derive_enum_variant_from_str(input: TokenStream) -> TokenStream {
-    let syn_item = parse_macro_input!(input as DeriveInput);
-    let enum_item = match syn_item.data {
-        syn::Data::Enum(enum_item) => enum_item,
-        _ => panic!("EnumVariantFromStr only works on Enums"),
-    };
-    let name = syn_item.ident;
-    let match_branches = enum_item
-        .variants
-        .into_iter()
-        .map(|variant| {
-            format!(
-                "{:?} => Ok({name}::{}),",
-                variant.ident.to_string().to_lowercase(),
-                variant.ident
-            )
-        })
-        .chain(Some("_ => Err(format!(\"unknown field '{{s}}'\")),".to_string()))
-        .collect::<Vec<_>>()
-        .join("");
-    let match_branches = syn::parse_str::<syn::Expr>(&format!(
-        "match s.trim().to_lowercase().as_str() {{ {match_branches} }}"
-    ))
-    .expect("failed generation of enum's FromStr implementation");
-    quote! {
-        impl std::str::FromStr for #name {
-            type Err = std::string::String;
-            fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
-                #match_branches
-            }
+    let input = parse_macro_input!(input as syn::DeriveInput);
+    enums::impl_derive_enum_variant_from_str(input).into()
+}
+
+/// Processes everything to create the export rule for LLVM. We will rename the functions
+/// accordingly.
+///
+/// You need to have the `ManageFunctions` and `Properties` in scope to use this macro.
+///
+/// Re-export what is inside the module for `super`. With the name passed as argument we export the
+/// function `{name}_llvm_properties` that will returns the properties for LLVM.
+#[proc_macro_attribute]
+pub fn vvrt_bridge(arg: TokenStream, input: TokenStream) -> TokenStream {
+    let name = parse_macro_input!(arg as syn::Ident);
+    let module = parse_macro_input!(input as syn::ItemMod);
+
+    let (module, funcs) = vvrt::impl_vvrt_bridge(name.to_string(), module).unwrap();
+    let module_name = &module.ident;
 
-        }
+    let has_clone = funcs.iter().any(|(_, role, ..)| {
+        role.as_ref()
+            .map(|role| matches!(role, vvrt::Role::Clone))
+            .unwrap_or_default()
+    });
+    let has_drop = funcs.iter().any(|(_, role, ..)| {
+        role.as_ref()
+            .map(|role| matches!(role, vvrt::Role::Drop))
+            .unwrap_or_default()
+    });
+    if has_clone ^ has_drop {
+        panic!("you can't have a drop implementation without the clone one, or the other way around")
+    }
+
+    let funcs = vvrt::gen_method_infos(name, funcs).unwrap();
+
+    quote! {
+        #module
+        pub(super) use self::#module_name::*;
+        #funcs
     }
     .into()
 }
diff --git a/src/Rust/vvs_procmacro/src/vvrt/gen.rs b/src/Rust/vvs_procmacro/src/vvrt/gen.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6ad18aa2ffb8269090d0957a633ac03792a89a9b
--- /dev/null
+++ b/src/Rust/vvs_procmacro/src/vvrt/gen.rs
@@ -0,0 +1,134 @@
+use crate::vvrt::{MethodInfo, Role, Type};
+use anyhow::bail;
+use proc_macro2::TokenStream;
+use quote::quote;
+
+fn gen_type_call(ty: &Type, arg: &syn::Ident) -> TokenStream {
+    match ty {
+        Type::None => quote! { LLVMVoidTypeInContext(#arg) },
+        Type::Integer => quote! { LLVMInt32TypeInContext(#arg) },
+        Type::Floating => quote! { LLVMFloatTypeInContext(#arg) },
+        Type::Boolean => quote! { LLVMInt1TypeInContext(#arg) },
+        Type::StrPtr => quote! { LLVMPointerTypeInContext(#arg, 0) },
+        Type::VVRT(vvrt) => {
+            let vvrt = syn::Ident::new(vvrt, arg.span());
+            quote! { #vvrt::llvm_type(#arg) }
+        }
+    }
+}
+
+fn get_asttype(ty: &Type) -> TokenStream {
+    match ty {
+        Type::None => quote! { ASTType::Nil },
+        Type::Integer => quote! { ASTType::Integer },
+        Type::Floating => quote! { ASTType::Floating },
+        Type::Boolean => quote! { ASTType::Boolean },
+        Type::StrPtr => quote! { ASTType::String },
+        Type::VVRT("VVRTString") => quote! { ASTType::String },
+        Type::VVRT("VVRTTable") => quote! { ASTType::AnyTable },
+        Type::VVRT("VVRTSeq") => quote! { ASTType::AnySequence },
+        Type::VVRT("VVRTAny") => quote! { ASTType::Any },
+        Type::VVRT("VVRTVariant") => quote! { ASTType::Variant },
+        Type::VVRT("VVRTType") => quote! { ASTType::Integer },
+        Type::VVRT("VVRTLine") => quote! { ASTType::Line },
+        Type::VVRT("VVRTSyllabe") => quote! { ASTType::Syllabe },
+        ty => unreachable!("unknown type {ty:?}"),
+    }
+}
+
+pub(crate) fn gen_method_infos(name: syn::Ident, infos: Vec<MethodInfo>) -> anyhow::Result<TokenStream> {
+    macro_rules! get_manage {
+        ($role: ident) => {
+            infos
+                .iter()
+                .find_map(|(name, role, ..)| matches!(role, Some(Role::$role)).then_some(name.as_str()))
+        };
+    }
+
+    macro_rules! opt_string {
+        ($expr: expr) => {
+            match $expr {
+                None => quote! { None },
+                Some(str) => quote! { Some(#str) },
+            }
+        };
+    }
+
+    macro_rules! quote_vec {
+        ($inner: expr) => {
+            match $inner {
+                Some(inner) => quote! { vec![#inner] },
+                None => quote! { vec![] },
+            }
+        };
+    }
+
+    let arg = syn::Ident::new("c", name.span());
+
+    let manage_len = opt_string!(get_manage!(Len));
+    let manage_eq = opt_string!(get_manage!(Eq));
+
+    let manage = match (get_manage!(Drop), get_manage!(Clone)) {
+        (None, None) => quote! { None },
+        (Some(drop), Some(clone)) => quote! {
+            Some(ManageFunctions {
+                clone: #clone,
+                drop: #drop,
+            })
+        },
+        _ => bail!("clone and drop functions must be present at the same time, or none of them"),
+    };
+
+    let methods = infos.into_iter().map(|(name, _, args, returns)| {
+        let llvm_returns = gen_type_call(&returns, &arg);
+        let llvm_args_len: u32 = args.len().try_into().expect("too many arguments");
+        let llvm_args = quote_vec!(args
+            .iter()
+            .map(|ty| gen_type_call(ty, &arg))
+            .reduce(|acc, item| quote! { #acc, #item }));
+
+        let ast_returns = get_asttype(&returns);
+        let ast_args = quote_vec!(args
+            .into_iter()
+            .map(|ty| get_asttype(&ty))
+            .reduce(|acc, item| quote! { #acc, #item }));
+
+        let func = syn::Ident::new(&name, arg.span());
+
+        quote! {{
+            let func: unsafe extern "C" fn() = unsafe { std::mem::transmute(#func as *const ()) };
+            let mut llvm_args = #llvm_args; // We compute the vector here for safety.
+            let ast_type = ASTType::Function(#ast_args, Box::new(#ast_returns)); // Also needs the ast type.
+            let functy = vvs_llvm::LLVMFunctionType(
+                #llvm_returns,                          // Should be Ok there.
+                llvm_args.as_mut_ptr(), #llvm_args_len, // We pre-computed the length here.
+                0                                       // No variadic functions there.
+            );
+            (#name, (func, functy, ast_type))
+        }}
+    });
+    let methods = quote_vec!(methods.reduce(|acc, item| quote! { #acc, #item }));
+
+    Ok(quote! {
+        impl LLVMExported for #name {
+            unsafe fn llvm_type(c: LLVMContextRef) -> LLVMTypeRef {
+                #[allow(dead_code)]
+                static SIZE_IS_VALID: () = {
+                    assert!(std::mem::size_of::<#name>() == 8);
+                    assert!(std::mem::align_of::<#name>() == 8);
+                };
+                LLVMPointerTypeInContext(c, 0)
+            }
+
+            unsafe fn llvm_properties(c: LLVMContextRef) -> Properties {
+                use vvs_lang::ast::ASTType;
+                Properties {
+                    manage: #manage,
+                    equality: #manage_eq,
+                    len: #manage_len,
+                    methods: hashbrown::HashMap::from_iter(#methods),
+                }
+            }
+        }
+    })
+}
diff --git a/src/Rust/vvs_procmacro/src/vvrt/mod.rs b/src/Rust/vvs_procmacro/src/vvrt/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d4b671d0f4a778d3859f02f966f915c83d7bbd8d
--- /dev/null
+++ b/src/Rust/vvs_procmacro/src/vvrt/mod.rs
@@ -0,0 +1,75 @@
+//! Utility macros used in the Vivy Script Runtime.
+
+mod gen;
+mod structs;
+
+pub(crate) use self::{gen::*, structs::*};
+
+use anyhow::anyhow;
+use proc_macro2::{Ident, TokenStream, TokenTree};
+use quote::quote;
+use quote::ToTokens;
+use syn::{
+    token::{Pub, Unsafe},
+    Generics, Visibility,
+};
+
+fn handle_function(name: &str, func: &mut syn::ItemFn) -> anyhow::Result<MethodInfo> {
+    func.vis = Visibility::Public(Pub::default());
+    func.sig.asyncness = None;
+    func.sig.unsafety = Some(Unsafe::default());
+    func.sig.constness = None;
+    func.sig.variadic = None;
+    func.sig.generics = Generics::default();
+
+    let func_name = func.sig.ident.to_string().to_lowercase();
+    let role = Role::try_from(func_name.as_str()).ok();
+    let func_name = format!("{name}_{}", func_name);
+    func.sig.ident = Ident::new(&func_name, func.sig.ident.span());
+
+    let args = func.sig.inputs.iter().map(|inputs| {
+        Type::try_from(
+            syn::parse2::<syn::Type>(
+                inputs
+                    .to_token_stream()
+                    .into_iter()
+                    .skip_while(|tok| !matches!(tok, TokenTree::Punct(p) if p.as_char() == ':'))
+                    .skip(1)
+                    .collect::<TokenStream>(),
+            )
+            .unwrap(),
+        )
+    });
+    let args = args.collect::<Result<Vec<_>, _>>()?;
+
+    // Skip the arrow
+    let returns = if func.sig.output.to_token_stream().into_iter().count().eq(&0) {
+        Type::None
+    } else {
+        let returns = func.sig.output.to_token_stream().into_iter().skip(2);
+        Type::try_from(syn::parse2::<syn::Type>(returns.collect())?)?
+    };
+
+    Ok((func_name, role, args, returns))
+}
+
+pub(crate) fn impl_vvrt_bridge(
+    name: String,
+    mut module: syn::ItemMod,
+) -> anyhow::Result<(syn::ItemMod, Vec<MethodInfo>)> {
+    if let Some((_, items)) = module.content.as_mut() {
+        let funcs = items.iter_mut().map(|item| match item {
+            syn::Item::Fn(item) => handle_function(&name, item).map(Some),
+            _ => Ok(None),
+        });
+        let funcs = funcs
+            .collect::<Result<Vec<_>, _>>()?
+            .into_iter()
+            .flatten()
+            .collect::<Vec<_>>();
+        items.push(syn::parse2(quote! { use super::*; })?);
+        Ok((module, funcs))
+    } else {
+        Err(anyhow!("expected a module"))
+    }
+}
diff --git a/src/Rust/vvs_procmacro/src/vvrt/structs.rs b/src/Rust/vvs_procmacro/src/vvrt/structs.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3ca09db62b4602723394d731e83309ef21c19def
--- /dev/null
+++ b/src/Rust/vvs_procmacro/src/vvrt/structs.rs
@@ -0,0 +1,69 @@
+use anyhow::anyhow;
+use quote::ToTokens;
+
+pub(crate) type MethodInfo = (String, Option<Role>, Vec<Type>, Type);
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub(crate) enum Role {
+    Clone,
+    Eq,
+    Drop,
+    Len,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[allow(clippy::upper_case_acronyms)]
+pub(crate) enum Type {
+    /// Void, None, Null, etc.
+    None,
+
+    /// Special type for the `*const u8` type. We only have const pointers here. This is used to
+    /// create strings from static slices...
+    StrPtr,
+
+    /// Integers, we use 32 bit integers.
+    Integer,
+
+    /// Floating numbers, we use 32 bit floats.
+    Floating,
+
+    /// Boolean.
+    Boolean,
+
+    /// A builtin VVRT type (Vivy Script Runtime)
+    VVRT(&'static str),
+}
+
+impl TryFrom<&str> for Role {
+    type Error = anyhow::Error;
+    fn try_from(value: &str) -> Result<Self, Self::Error> {
+        match value.to_lowercase().as_ref() {
+            "clone" => Ok(Self::Clone),
+            "eq" => Ok(Self::Eq),
+            "drop" => Ok(Self::Drop),
+            "len" => Ok(Self::Len),
+            str => Err(anyhow!("unknown role `{str}`")),
+        }
+    }
+}
+
+impl TryFrom<syn::Type> for Type {
+    type Error = anyhow::Error;
+    fn try_from(value: syn::Type) -> Result<Self, Self::Error> {
+        match value {
+            syn::Type::Path(path) => match &path.path.require_ident()?.to_string()[..] {
+                str if str.starts_with("VVRT") => Ok(Type::VVRT(String::leak(str.to_string()))),
+                "i32" => Ok(Type::Integer),
+                "f32" => Ok(Type::Floating),
+                "bool" => Ok(Type::Boolean),
+                "()" => Ok(Type::None),
+                str => Err(anyhow!("unknown type `{str}`")),
+            },
+            syn::Type::Ptr(inner) => match *inner.elem {
+                syn::Type::Path(ty) if ty.path.require_ident()? == "u8" => Ok(Type::StrPtr),
+                ty => Err(anyhow!("expected u8 to form string pointer, got: {}", ty.into_token_stream().to_string())),
+            },
+            ty => Err(anyhow!("type can't be casted into base_type: {}", ty.into_token_stream().to_string())),
+        }
+    }
+}
diff --git a/src/Rust/vvs_runtime/Cargo.toml b/src/Rust/vvs_runtime/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..fe6bd029299748f0c4045f9e40e4902b66806479
--- /dev/null
+++ b/src/Rust/vvs_runtime/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name              = "vvs_runtime"
+description       = "The runtime for Vivy Script"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+
+[dependencies]
+log.workspace        = true
+anyhow.workspace     = true
+serde.workspace      = true
+serde_json.workspace = true
+
+vvs_runtime_types.workspace = true
+vvs_utils.workspace         = true
+vvs_llvm.workspace          = true
+
+[build-dependencies]
+anyhow.workspace = true
+vvs_llvm = { workspace = true, features = ["link"] }
diff --git a/src/Rust/vvs_runtime/build.rs b/src/Rust/vvs_runtime/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a01480722a65c2a0de92058e860bdc41610328d4
--- /dev/null
+++ b/src/Rust/vvs_runtime/build.rs
@@ -0,0 +1,3 @@
+fn main() -> anyhow::Result<()> {
+    vvs_llvm::build::llvm_link()
+}
diff --git a/src/Rust/vvs_runtime/src/jit.rs b/src/Rust/vvs_runtime/src/jit.rs
new file mode 100644
index 0000000000000000000000000000000000000000..953bc4aeb79ac6995deb15747a908c75aaf8f72e
--- /dev/null
+++ b/src/Rust/vvs_runtime/src/jit.rs
@@ -0,0 +1,157 @@
+use crate::workers::Workers;
+use anyhow::{bail, Context};
+use std::{
+    ffi::{c_int, c_void, CStr, CString},
+    ptr,
+    sync::{
+        atomic::{AtomicU64, Ordering},
+        Arc,
+    },
+};
+use vvs_llvm::*;
+use vvs_runtime_types::VVRTSymbol;
+
+#[allow(dead_code)]
+pub struct JIT {
+    jit: *mut LLVMOrcOpaqueLLJIT,
+    es: *mut LLVMOrcOpaqueExecutionSession,
+
+    tsctx: *mut LLVMOrcOpaqueThreadSafeContext,
+
+    irtl: *mut LLVMOrcOpaqueIRTransformLayer,
+    objl: *mut LLVMOrcOpaqueObjectLayer,
+    dylib: *mut LLVMOrcOpaqueJITDylib,
+
+    workers: Workers,
+}
+
+macro_rules! llvm_expect {
+    (unsafe $err: expr, $msg: literal $(, $arg: expr)* $(,)?) => {{
+        unsafe { llvm_expect!($err, $msg $(, $arg)*) }
+    }};
+
+    ($err: expr, $msg: literal $(, $arg: expr)* $(,)?) => {{
+        let err = $err;
+        if !err.is_null() {
+            let msg = std::ffi::CStr::from_ptr(LLVMGetErrorMessage(err))
+                .to_string_lossy()
+                .to_string();
+            LLVMConsumeError(err);
+            bail!("{}: {}", format_args!($msg, $(, $arg)*), msg)
+        }
+    }};
+}
+
+/// This function should be visible because it starts with `VVRT`
+#[allow(non_snake_case)]
+pub extern "C" fn VVRTHelloWorld() {
+    println!("Hello World from LLVM JIT");
+}
+
+/// This function should not be visible because it doesn't start with `VVRT`
+pub extern "C" fn hello_world() {
+    println!("wtf !?");
+}
+
+extern "C" fn orc_sym_filter(_: *mut c_void, sym: LLVMOrcSymbolStringPoolEntryRef) -> c_int {
+    eprintln!("toto");
+    let Ok(sym) = unsafe { CStr::from_ptr(LLVMOrcSymbolStringPoolEntryStr(sym)) }.to_str() else {
+        log::error!("got a symbol which name was not valid utf8 from orc");
+        return 0;
+    };
+    sym.starts_with("VVRT") as c_int
+}
+
+impl JIT {
+    /// Create a new JIT thingy to execute Vivy Script code.
+    pub fn new() -> anyhow::Result<JIT> {
+        if let Err(err) = vvs_llvm::initialize_llvm() {
+            log::error!("{err}");
+        }
+
+        unsafe {
+            // Create the jit.
+            let mut jit = ptr::null_mut();
+            let mut tmb = ptr::null_mut();
+            llvm_expect!(LLVMOrcJITTargetMachineBuilderDetectHost(&mut tmb), "failed to create orc jit builder");
+
+            let jit_builder = LLVMOrcCreateLLJITBuilder();
+            LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(jit_builder, tmb);
+            llvm_expect!(LLVMOrcCreateLLJIT(&mut jit, jit_builder), "failed to create the orc jit");
+
+            log::debug!("got data layout: {}", CStr::from_ptr(LLVMOrcLLJITGetDataLayoutStr(jit)).to_string_lossy());
+
+            // Create things, in this order.
+            let es = LLVMOrcLLJITGetExecutionSession(jit);
+            let objl = LLVMOrcCreateRTDyldObjectLinkingLayerWithSectionMemoryManager(es);
+            let irtl = LLVMOrcLLJITGetIRTransformLayer(jit);
+            let dylib = LLVMOrcExecutionSessionCreateBareJITDylib(es, b"<main>\0".as_ptr() as *const _);
+
+            // Allow to search for symbols in the current process, only if they start with `VVRT`.
+            let mut dg = std::ptr::null_mut();
+            llvm_expect!(
+                LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(
+                    &mut dg,
+                    LLVMOrcLLJITGetGlobalPrefix(jit),
+                    Some(orc_sym_filter),
+                    std::ptr::null_mut()
+                ),
+                "failed to create an orc dylib search generator for the current process"
+            );
+            LLVMOrcJITDylibAddGenerator(dylib, dg);
+
+            // Ok. Create workers and return the struct.
+            let tsctx = LLVMOrcCreateNewThreadSafeContext();
+            let workers = Workers::new(|flag: Arc<AtomicU64>| loop {
+                match flag.load(Ordering::SeqCst) {
+                    0 => std::thread::yield_now(),
+                    u64::MAX => return Ok(()),
+                    x => bail!("won't handle work package n°{x}"),
+                }
+            })?;
+            Ok(JIT { jit, es, dylib, tsctx, irtl, objl, workers })
+        }
+    }
+
+    /// Get the context out of the JIT thingy. Used to create a LLVM module to be used latter by
+    /// the JIT.
+    pub fn ctx(&self) -> LLVMContextRef {
+        unsafe { LLVMOrcThreadSafeContextGetContext(self.tsctx) }
+    }
+
+    /// Add a new module to the JIT engine.
+    ///
+    /// # Safety
+    /// The passed module ([LLVMModuleRef]) must not be a null pointer and must be a valid LLVM
+    /// module with valid code for the runtime. This module should be created by the [vvs_codegen]
+    /// crate or you can have problems executing it...
+    pub unsafe fn add_module(&self, module: LLVMModuleRef) -> anyhow::Result<()> {
+        let tsm = LLVMOrcCreateNewThreadSafeModule(module, self.tsctx);
+        let rc = LLVMOrcLLJITAddLLVMIRModule(self.jit, self.dylib, tsm);
+        llvm_expect!(rc, "failed to add the module into the jit");
+        Ok(())
+    }
+
+    /// LookUp a symbol defined in the JIT.
+    pub fn lookup<'a>(&self, name: &'a str) -> anyhow::Result<VVRTSymbol<'a>> {
+        let mut addr = Default::default();
+        let symbol = VVRTSymbol::try_from(name)?;
+        let str = CString::new(name).with_context(|| "CString::new failed")?;
+        llvm_expect!(unsafe
+            LLVMOrcLLJITLookup(self.jit, &mut addr, str.as_ptr()),
+            "failed to lookup symbol `{name}`"
+        );
+        Ok(symbol.with_addr(addr))
+    }
+}
+
+impl Drop for JIT {
+    fn drop(&mut self) {
+        self.workers.pre_drop();
+        unsafe {
+            LLVMOrcDisposeThreadSafeContext(self.tsctx);
+            LLVMOrcDisposeLLJIT(self.jit);
+            LLVMOrcDisposeObjectLayer(self.objl);
+        }
+    }
+}
diff --git a/src/Rust/vvs_runtime/src/lib.rs b/src/Rust/vvs_runtime/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4eb83d6c59bb490ee381fbdd0305f3bf5a72c620
--- /dev/null
+++ b/src/Rust/vvs_runtime/src/lib.rs
@@ -0,0 +1,6 @@
+mod jit;
+mod workers;
+
+// Re-exports
+pub use crate::jit::*;
+pub use vvs_runtime_types::types;
diff --git a/src/Rust/vvs_runtime/src/workers.rs b/src/Rust/vvs_runtime/src/workers.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9c69cad1ffc5327b75d15e8b5c7c5141c8959d62
--- /dev/null
+++ b/src/Rust/vvs_runtime/src/workers.rs
@@ -0,0 +1,106 @@
+//! A simple implementation of worker threads, unix only for now. HWloc seems to have difficulties
+//! on MacOS, so this should be Ok for Linux and BSDs...
+
+use anyhow::{bail, Context, Result};
+use std::{
+    cell::Cell,
+    sync::{
+        atomic::{AtomicU64, Ordering},
+        Arc,
+    },
+    thread::JoinHandle,
+};
+
+thread_local! {
+    pub static WORKER_THREAD_IDX: Cell<u16> = const { Cell::new(u16::MAX) };
+}
+
+/// Contains worker threads, we bind one per physical core. We can distribute work to those threads
+/// and wait for the distributed work to be done.
+pub(crate) struct Workers {
+    handles: Vec<(JoinHandle<()>, Arc<AtomicU64>)>,
+}
+
+fn join_handles<T>(handles: impl Iterator<Item = JoinHandle<T>>) {
+    for handle in handles {
+        if let Err(err) = handle.join() {
+            let idx = WORKER_THREAD_IDX.get();
+            log::error!("failed to join thread n°{idx} with error: {err:?}")
+        }
+    }
+}
+
+fn cancel_threads(handles: impl Iterator<Item = Arc<AtomicU64>>) {
+    for atomic in handles {
+        atomic.store(u64::MAX, Ordering::SeqCst);
+    }
+}
+
+impl Workers {
+    /// Create new worker threads. We use a closure passed by the user. When work is asked for the
+    /// workers the passed integer is set to a non-zero constant (you can't assume it's value),
+    /// when the thread has finish it's work the atomic must be set to 0.
+    ///
+    /// If we want to cancel the thread, the passed atomic will be set to `U64_MAX`.
+    pub fn new(user_func: impl Fn(Arc<AtomicU64>) -> Result<()> + Send + Clone + 'static) -> Result<Self> {
+        let thread_count = std::thread::available_parallelism()
+            .map(std::num::NonZeroUsize::get)
+            .unwrap_or(1);
+        (0..thread_count)
+            .map(|idx| Self::launch_thread(user_func.clone(), idx))
+            .try_fold(vec![], |mut acc, item| match item {
+                Err(err) => Err((acc, err)),
+                Ok(item) => {
+                    acc.push(item);
+                    Ok(acc)
+                }
+            })
+            .map(|handles| Self { handles })
+            .map_err(|(handles, err)| {
+                cancel_threads(handles.iter().map(|(_, rc)| rc.clone()));
+                join_handles(handles.into_iter().map(|(hdl, _)| hdl));
+                err
+            })
+    }
+
+    /// Launch a thread with a user function on a core of the topology.
+    fn launch_thread(
+        user_func: impl Fn(Arc<AtomicU64>) -> Result<()> + Send + 'static,
+        idx: usize,
+    ) -> Result<(JoinHandle<()>, Arc<AtomicU64>)> {
+        let flag = Arc::new(AtomicU64::new(0));
+        let ret_flag = flag.clone();
+
+        let idx_i16: u16 = idx.try_into().with_context(|| "try to launch to many threads")?;
+        if idx_i16 == u16::MAX {
+            bail!("try to launch to many threads");
+        }
+
+        let handle = std::thread::Builder::new()
+            .name(format!("VVRT-Worker-{idx}"))
+            .spawn(move || {
+                WORKER_THREAD_IDX.set(idx_i16);
+                log::debug!("start thread n°{idx}");
+                if let Err(err) = user_func(flag.clone()) {
+                    log::error!("thread n°{idx} exits with error: {err}");
+                }
+                flag.store(0, Ordering::SeqCst);
+                log::debug!("exit thread n°{idx}");
+            })?;
+
+        Ok((handle, ret_flag))
+    }
+
+    /// Pre-drop all the threads and cancel the work to do.
+    pub fn pre_drop(&mut self) {
+        let handles = std::mem::take(&mut self.handles);
+        cancel_threads(handles.iter().map(|(_, rc)| rc.clone()));
+        join_handles(handles.into_iter().map(|(hdl, _)| hdl));
+    }
+}
+
+impl Drop for Workers {
+    fn drop(&mut self) {
+        self.pre_drop();
+    }
+}
diff --git a/src/Rust/vvs_runtime_types/Cargo.toml b/src/Rust/vvs_runtime_types/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..1e1ab1a6e6608f0d5b0a8555c1b0643a481a43e7
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name              = "vvs_runtime_types"
+description       = "The types for the runtime for Vivy Script"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+
+[dependencies]
+log.workspace        = true
+serde.workspace      = true
+serde_json.workspace = true
+anyhow.workspace     = true
+hashbrown.workspace  = true
+
+unicode-segmentation.workspace = true
+
+vvs_procmacro.workspace = true
+vvs_utils.workspace     = true
+vvs_lang.workspace      = true
+vvs_llvm.workspace      = true
+vvs_ass.workspace       = true
+
+[build-dependencies]
+anyhow.workspace = true
+vvs_llvm = { workspace = true, features = ["link"] }
diff --git a/src/Rust/vvs_runtime_types/build.rs b/src/Rust/vvs_runtime_types/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a01480722a65c2a0de92058e860bdc41610328d4
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/build.rs
@@ -0,0 +1,3 @@
+fn main() -> anyhow::Result<()> {
+    vvs_llvm::build::llvm_link()
+}
diff --git a/src/Rust/vvs_runtime_types/src/lib.rs b/src/Rust/vvs_runtime_types/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..b5950e8b5d87bc12146a1de535ebf0e52b18c80f
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/lib.rs
@@ -0,0 +1,13 @@
+//! Here we have the types that will be used by the runtime, with their description so that the
+//! codegen can correctly use them.
+
+mod mangle;
+mod pointer;
+
+pub mod types;
+pub mod vvll;
+
+pub use self::{mangle::*, pointer::*};
+
+#[cfg(any(test, doctest))]
+mod tests;
diff --git a/src/Rust/vvs_runtime_types/src/mangle.rs b/src/Rust/vvs_runtime_types/src/mangle.rs
new file mode 100644
index 0000000000000000000000000000000000000000..2945a3349eaefef9ebe9afff27d8d80a50576230
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/mangle.rs
@@ -0,0 +1,163 @@
+use anyhow::{anyhow, bail};
+use std::{ffi::CString, str::FromStr};
+use vvs_lang::ast::ASTType;
+use vvs_llvm::*;
+
+/// Materialize which type of symbol we have.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum VVRTSymbolType {
+    Constant,
+    Function,
+    Option,
+    Method,
+}
+
+/// Describes a symbol. Can specify an ORCv2 execution address.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct VVRTSymbol<'a> {
+    pub sym: VVRTSymbolType,
+    pub module: &'a str,
+    pub name: &'a str,
+    addr: Option<LLVMOrcExecutorAddress>,
+}
+
+impl VVRTSymbolType {
+    /// Get the string representation of the symbol type.
+    pub fn as_str(&self) -> &'static str {
+        match self {
+            VVRTSymbolType::Constant => "Constant",
+            VVRTSymbolType::Function => "Function",
+            VVRTSymbolType::Option => "Option",
+            VVRTSymbolType::Method => "Method",
+        }
+    }
+}
+
+impl FromStr for VVRTSymbolType {
+    type Err = anyhow::Error;
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s.trim() {
+            "Constant" => Ok(VVRTSymbolType::Constant),
+            "Function" => Ok(VVRTSymbolType::Function),
+            "Option" => Ok(VVRTSymbolType::Option),
+            "Method" => Ok(VVRTSymbolType::Method),
+            s => Err(anyhow!("unknown symbol type `{s}`")),
+        }
+    }
+}
+
+impl std::fmt::Display for VVRTSymbolType {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_str(self.as_str())
+    }
+}
+
+impl AsRef<str> for VVRTSymbolType {
+    fn as_ref(&self) -> &str {
+        self.as_str()
+    }
+}
+
+impl<'a> VVRTSymbol<'a> {
+    /// Create a new symbol.
+    pub fn new(ty: VVRTSymbolType, module: &'a str, name: &'a str) -> anyhow::Result<Self> {
+        if let Some(idx) = module.find(|c: char| !c.is_alphanumeric()) {
+            bail!("invalid character found in module name at position `{idx}`: {module}")
+        }
+        if let Some(idx) = name.find(|c: char| c.is_whitespace() || c == '\0') {
+            bail!("invalid character found in name at position `{idx}`: {name}")
+        }
+        Ok(Self { sym: ty, module, name, addr: None })
+    }
+
+    pub fn method(ty: &ASTType, name: &'a str) -> anyhow::Result<Self> {
+        let module = match ty {
+            ASTType::Any => "Any",
+            ASTType::Line => "Line",
+            ASTType::String => "String",
+            ASTType::Syllabe => "Syllabe",
+            ty if ty.is_variant() => "Variant",
+            ty if ty.is_table() => "Table",
+            ty if ty.is_sequence() => "Sequence",
+            ty => bail!("can't have methods for type `{ty}`"),
+        };
+        Ok(VVRTSymbol { sym: VVRTSymbolType::Method, module, name, addr: None })
+    }
+
+    /// Builder-like syntax to take a symbol and associate it to an execution address gotten from
+    /// the JIT engine. We ignore any previous address.
+    pub fn with_addr(mut self, addr: LLVMOrcExecutorAddress) -> Self {
+        self.addr = Some(addr);
+        self
+    }
+
+    /// Mangle the symbol to get the name of it for the JIT engine or to find the symbol in the
+    /// LLVM module. This is a heavy operation.
+    ///
+    /// If the symbol was not valid we panic. If the symbol was correctly constructed/parsed this
+    /// should not happen.
+    pub fn mangle(&self) -> CString {
+        CString::new(self.to_string()).expect("invalid symbol")
+    }
+}
+
+impl<'a> std::fmt::Display for VVRTSymbol<'a> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let Self { sym, module, name, .. } = self;
+        match sym {
+            // Some shenanigans for builtin symbols...
+            VVRTSymbolType::Method => {
+                let mut module = unicode_segmentation::UnicodeSegmentation::graphemes(*module, true);
+                let first = module.next().map(|str| str.to_uppercase()).unwrap_or_default();
+                let tail = module.as_str();
+                write!(f, "VV{first}{tail}_{}", name.to_lowercase())
+            }
+
+            // A simple rule for symbols generated from users' code.
+            _ => write!(f, "_VV{sym}_{module}_{name}"),
+        }
+    }
+}
+
+impl<'a> TryFrom<&'a str> for VVRTSymbol<'a> {
+    type Error = anyhow::Error;
+    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
+        const CORRECT_SYMBOLS: &str = "`_VV{{sym}}_{{module}}_{{name}}` or `VV{{builtin_type}}_{{name}}`";
+
+        let trimmed_value = value.trim();
+        if let Some(pos) = trimmed_value.find('\0') {
+            bail!("invalid symbol name `{trimmed_value}`, found null byte at {pos}")
+        }
+
+        let Some((sym, value)) = (match trimmed_value.strip_prefix("_VV") {
+            Some(trimmed_value) => trimmed_value.split_once('_'),
+            None => match trimmed_value.strip_prefix("VV") {
+                Some(trimmed_value) => Some((VVRTSymbolType::Method.as_str(), trimmed_value)),
+                None => bail!("invalid symbol name `{trimmed_value}`, didn't start with `_VV` or `VV`"),
+            },
+        }) else {
+            bail!("invalid symbol name `{trimmed_value}`, should be {CORRECT_SYMBOLS}")
+        };
+
+        let Some((module, name)) = value.split_once('_') else {
+            bail!("invalid symbol name `{trimmed_value}`, should be {CORRECT_SYMBOLS}")
+        };
+
+        Self::new(sym.parse()?, module, name)
+    }
+}
+
+#[test]
+fn test_vvrt_symbol() {
+    use vvs_utils::*;
+
+    assert_eq!(
+        assert_ok!(VVRTSymbol::try_from("_VVConstant_retime_start")),
+        VVRTSymbol { sym: VVRTSymbolType::Constant, module: "retime", name: "start", addr: None }
+    );
+
+    assert_eq!(
+        "_VVFunction_tag_syl_modulo".to_string(),
+        VVRTSymbol { sym: VVRTSymbolType::Function, module: "tag", name: "syl_modulo", addr: None }.to_string()
+    );
+}
diff --git a/src/Rust/vvs_runtime_types/src/pointer.rs b/src/Rust/vvs_runtime_types/src/pointer.rs
new file mode 100644
index 0000000000000000000000000000000000000000..68f689ccc3c04e34046b3511263a1508bd8ac626
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/pointer.rs
@@ -0,0 +1,140 @@
+use std::{
+    cmp::Ordering,
+    hash::{Hash, Hasher},
+    marker::PhantomData,
+    mem::{align_of, size_of},
+    ptr::NonNull,
+};
+
+/// A tagged pointer: a space-efficient representation of a pointer that smuggles an integer tag
+/// into it.
+///
+/// `BITS` specifies how many bits are used for the tag. The alignment of `T` must be large enough
+/// to store this many bits.
+///
+/// # Safety
+/// The passed pointers, at construction time and each time you modify this struct, should all be
+/// properly aligned, or your code may panic. The passed pointer must also be dereferenceable.
+#[repr(transparent)]
+pub struct TaggedPtr<T, const BITS: u8>(NonNull<u8>, PhantomData<NonNull<T>>);
+
+impl<T, const BITS: u8> TaggedPtr<T, BITS> {
+    const ASSERT: () = {
+        assert!(size_of::<usize>() == size_of::<u64>(), "we only work with 64 bits architectures");
+        assert!(align_of::<T>().is_power_of_two(), "expected alignment of `T` to be a power of 2");
+        assert!(
+            match size_of::<T>() {
+                0 => true,
+                n => n >= align_of::<T>(),
+            },
+            "expected size of non-ZST `T` to be at least alignment"
+        );
+        assert!(size_of::<T>() % align_of::<T>() == 0, "expected size of `T` to be multiple of alignment");
+        assert!(1_usize.checked_shl(BITS as u32).is_some(), "`1 << BITS` doesn't fit in a `usize`");
+        assert!(align_of::<T>().trailing_zeros() >= BITS as u32, "alignment of `T` must be at least `1 << BITS`");
+    };
+
+    const ALIGNMENT: usize = 1_usize.wrapping_shl(BITS as u32);
+    const MASK: usize = Self::ALIGNMENT - 1;
+
+    /// Creates a new tagged pointer. Only the lower `BITS` bits of `tag` are stored.
+    ///
+    /// If build in debug, a check is performed at compile time to ensure that the alignment of `T`
+    /// is sufficient to smuggle the tag.
+    #[allow(path_statements, clippy::no_effect)]
+    #[inline]
+    pub fn new(ptr: NonNull<T>, tag: usize) -> Self {
+        Self::ASSERT; // Static assert!
+        let ptr = ptr.as_ptr().cast::<u8>();
+
+        let offset = ptr.align_offset(Self::ALIGNMENT);
+        debug_assert!(offset != usize::MAX, "align offset failed");
+        debug_assert!(offset & Self::MASK == 0, "`ptr` is not aligned enough");
+
+        let ptr = ptr.wrapping_add(tag & Self::MASK);
+        Self(unsafe { NonNull::new_unchecked(ptr) }, PhantomData)
+    }
+
+    /// Gets the pointer and tag stored by the tagged pointer.
+    #[inline]
+    pub fn get(self) -> (NonNull<T>, usize) {
+        let ptr = self.0.as_ptr();
+        let tag = Self::ALIGNMENT.wrapping_sub(ptr.align_offset(Self::ALIGNMENT)) & Self::MASK;
+        let ptr = ptr.wrapping_sub(tag).cast::<T>();
+
+        // SAFETY: ptr + 1 - 1 == ptr
+        (unsafe { NonNull::new_unchecked(ptr) }, tag)
+    }
+
+    /// Get the address of the pointed thing as an integer. Here for moar reasons we only work with
+    /// 64 bit architectures, thus the `usize == u64`.
+    #[inline]
+    pub fn addr(self) -> u64 {
+        self.ptr().as_ptr() as u64
+    }
+
+    /// Gets the pointer stored by the tagged pointer, without the tag.
+    #[inline]
+    pub fn ptr(self) -> NonNull<T> {
+        self.get().0
+    }
+
+    /// Gets the tag stored by the tagged pointer.
+    #[inline]
+    pub fn tag(self) -> usize {
+        self.get().1
+    }
+
+    /// Sets the pointer without modifying the tag.
+    #[inline]
+    pub fn set_ptr(&mut self, ptr: NonNull<T>) {
+        *self = Self::new(ptr, self.tag());
+    }
+
+    /// Sets the tag without modifying the pointer.
+    #[inline]
+    pub fn set_tag(&mut self, tag: usize) {
+        *self = Self::new(self.ptr(), tag);
+    }
+}
+
+impl<T, const BITS: u8> Copy for TaggedPtr<T, BITS> {}
+impl<T, const BITS: u8> Clone for TaggedPtr<T, BITS> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<T, const BITS: u8> Eq for TaggedPtr<T, BITS> {}
+impl<T, const BITS: u8> PartialEq for TaggedPtr<T, BITS> {
+    fn eq(&self, other: &Self) -> bool {
+        self.0 == other.0
+    }
+}
+
+impl<T, const BITS: u8> PartialOrd for TaggedPtr<T, BITS> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+impl<T, const BITS: u8> Ord for TaggedPtr<T, BITS> {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.0.cmp(&other.0)
+    }
+}
+
+impl<T, const BITS: u8> Hash for TaggedPtr<T, BITS> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
+        self.0.hash(state);
+    }
+}
+
+impl<T, const BITS: u8> std::fmt::Debug for TaggedPtr<T, BITS> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let (ptr, tag) = self.get();
+        f.debug_struct("TaggedPtr")
+            .field("ptr", &ptr)
+            .field("tag", &tag)
+            .finish()
+    }
+}
diff --git a/src/Rust/vvs_runtime_types/src/tests.rs b/src/Rust/vvs_runtime_types/src/tests.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ab13f1258ea84c34d314d6624db46f9751f78d01
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/tests.rs
@@ -0,0 +1,136 @@
+use hashbrown::HashMap;
+
+use crate::{
+    types::{VVRTAny, VVRTType},
+    TaggedPtr,
+};
+use core::{mem::size_of, ptr::NonNull};
+use std::mem::align_of;
+
+#[test]
+fn test_ptr_size() {
+    assert_eq!(size_of::<usize>(), size_of::<u64>());
+    assert_eq!(size_of::<*const u64>(), size_of::<u64>());
+}
+
+#[test]
+fn test_ptr_align() {
+    assert_eq!(size_of::<NonNull<u64>>(), 8);
+    assert_eq!(align_of::<NonNull<u64>>(), 8);
+    assert_eq!(align_of::<NonNull<HashMap<Box<str>, VVRTAny>>>(), 8);
+    assert_eq!(align_of::<NonNull<Vec<VVRTAny>>>(), 8);
+}
+
+#[test]
+fn test_type_sizes() {
+    use std::mem::size_of;
+    assert_eq!(size_of::<VVRTAny>(), 8);
+    assert_eq!(size_of::<VVRTType>(), 1);
+}
+
+#[repr(align(2))]
+#[derive(Debug, Eq, PartialEq)]
+struct Align2(pub u16);
+
+#[repr(align(4))]
+#[derive(Debug, Eq, PartialEq)]
+struct Align4(pub u32);
+
+#[repr(align(8))]
+#[derive(Debug, Eq, PartialEq)]
+struct Align8(pub u64);
+
+#[test]
+#[allow(clippy::let_unit_value)]
+fn check_ptr_basic() {
+    for i in 0..64 {
+        let x = i as u8 * 3;
+        let tp = TaggedPtr::<_, 0>::new((&x).into(), i);
+        assert_eq!(tp.get(), ((&x).into(), 0));
+        assert_eq!(*unsafe { tp.ptr().as_ref() }, x);
+
+        let x = Align2(i as u16 * 5);
+        let tp = TaggedPtr::<_, 1>::new((&x).into(), i);
+        assert_eq!(tp.get(), ((&x).into(), i & 0b1));
+        assert_eq!(*unsafe { tp.ptr().as_ref() }, x);
+
+        let mut x = Align4(i as u32 * 7);
+        let ptr = NonNull::from(&mut x);
+        let tp = TaggedPtr::<_, 2>::new(ptr, i);
+        assert_eq!(tp.get(), (ptr, i & 0b11));
+        unsafe { tp.ptr().as_mut() }.0 += 1;
+        assert_eq!(x.0, i as u32 * 7 + 1);
+
+        let x = Align8(i as u64 * 11);
+        let tp = TaggedPtr::<_, 3>::new((&x).into(), i);
+        assert_eq!(tp.get(), ((&x).into(), i & 0b111));
+        assert_eq!(*unsafe { tp.ptr().as_ref() }, x);
+    }
+}
+
+#[test]
+#[allow(clippy::let_unit_value)]
+fn check_ptr_overaligned() {
+    for i in 0..64 {
+        let x = Align2(i as u16 * 3);
+        let tp = TaggedPtr::<_, 0>::new((&x).into(), i);
+        assert_eq!(tp.get(), ((&x).into(), 0));
+        assert_eq!(*unsafe { tp.ptr().as_ref() }, x);
+
+        let x = Align4(i as u32 * 5);
+        let tp = TaggedPtr::<_, 1>::new((&x).into(), i);
+        assert_eq!(tp.get(), ((&x).into(), i & 0b1));
+        assert_eq!(*unsafe { tp.ptr().as_ref() }, x);
+
+        let x = Align8(i as u64 * 7);
+        let tp = TaggedPtr::<_, 2>::new((&x).into(), i);
+        assert_eq!(tp.get(), ((&x).into(), i & 0b11));
+        assert_eq!(*unsafe { tp.ptr().as_ref() }, x);
+    }
+}
+
+#[test]
+#[allow(clippy::let_unit_value)]
+fn check_ptr_zst() {
+    for i in 0..8 {
+        let x = ();
+        let tp = TaggedPtr::<_, 0>::new((&x).into(), i);
+        assert_eq!(tp.get(), ((&x).into(), 0));
+    }
+}
+
+#[test]
+fn check_ptr_size() {
+    assert_eq!(size_of::<TaggedPtr<u64, 3>>(), size_of::<core::ptr::NonNull<u64>>());
+    assert_eq!(size_of::<TaggedPtr<u64, 3>>(), size_of::<Option<TaggedPtr<u64, 3>>>());
+}
+
+#[test]
+fn check_ptr_not_entirely_dereferenceable() {
+    #[repr(align(8))]
+    #[allow(dead_code)]
+    struct Type(u64, u64, u64);
+
+    let a = Type(1, 2, 3);
+    let mut tp = TaggedPtr::<_, 2>::new((&a).into(), 0b10);
+    assert_eq!(tp.get(), ((&a).into(), 0b10));
+
+    let mut b = Align4(0);
+    let ptr = NonNull::from(&mut b).cast();
+    tp.set_ptr(ptr);
+    assert_eq!(tp.ptr(), ptr);
+    tp.set_tag(0b11);
+    assert_eq!(tp.tag(), 0b11);
+    unsafe { tp.ptr().cast::<Align4>().as_mut() }.0 = 1234;
+    assert_eq!(b.0, 1234);
+}
+
+#[test]
+#[should_panic]
+fn runtime_ptr_not_aligned_enough() {
+    let ptr: *mut Align2 = &mut Align2(0);
+    let ptr = unsafe { (ptr as *mut u8).add(1) };
+    let ptr = ptr as *mut Align2;
+    let ptr = unsafe { NonNull::new_unchecked(ptr) };
+    TaggedPtr::<_, 1>::new(ptr, 0);
+}
diff --git a/src/Rust/vvs_runtime_types/src/types/any.rs b/src/Rust/vvs_runtime_types/src/types/any.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1771dc8c21b9621776becd28aa89786a4a513f7e
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/types/any.rs
@@ -0,0 +1,318 @@
+//! Contains definitions for the [VVRTAny] runtime object and its associated methods.
+
+/// Implement [TryFrom<VVRTAny>] and [TryFrom<&VVRTAny>] for a given object that can be contained
+/// inside [VVRTAny].
+macro_rules! impl_try_from_any {
+    ($vvrtty: ident => $struct: ident) => {
+        impl TryFrom<crate::types::VVRTAny> for $struct {
+            #[inline]
+            fn try_from(value: crate::types::VVRTAny) -> Result<Self, Self::Error> {
+                unsafe { VVRTAny_is_ty(value, VVRTType::$vvrtty) }
+                    .then_some(Self(value.ptr()))
+                    .ok_or(value.ty())
+            }
+            type Error = crate::types::VVRTType;
+        }
+
+        impl TryFrom<&crate::types::VVRTAny> for $struct {
+            #[inline]
+            fn try_from(value: &crate::types::VVRTAny) -> Result<Self, Self::Error> {
+                (*value).try_into()
+            }
+            type Error = crate::types::VVRTType;
+        }
+    };
+}
+pub(super) use impl_try_from_any;
+
+use crate::{types::*, TaggedPtr};
+use std::{
+    mem::{align_of, transmute},
+    ptr::NonNull,
+};
+
+/// We represent the *any* Vivy Script type by an enum. We try to fit this bad boi into 8 bytes
+/// with a tagged pointer. With 3 bits for the tag we have values from 0 to 7, is enaugh to store
+/// the [VVRTType]. We store the [VVRTType::Nil] as [None] so we can gain one slot.
+///
+/// Nil is all zero, which is Ok even if we have a non-null thingy (at least I hope).
+#[derive(Debug, Clone, Copy)]
+#[repr(transparent)]
+pub struct VVRTAny(Option<TaggedPtr<u64, 3>>);
+
+impl VVRTAny {
+    /// Get the real type of the object inside the `any` container.
+    #[inline]
+    pub fn ty(&self) -> VVRTType {
+        self.map_or_default(|this| unsafe { transmute(this.tag() as u8 + 1) })
+    }
+
+    /// Map on the inner tagged pointer, or return the specified default.
+    #[inline]
+    pub fn map_or<U, F: FnOnce(TaggedPtr<u64, 3>) -> U>(self, default: U, f: F) -> U {
+        self.0.map_or(default, f)
+    }
+
+    /// Map on the inner tagger pointer, or return the default value for the returned type.
+    #[inline]
+    pub fn map_or_default<U: Default, F: FnOnce(TaggedPtr<u64, 3>) -> U>(self, f: F) -> U {
+        self.0.map_or(U::default(), f)
+    }
+
+    /// Get the pointer out of the tagged pointer, or a dangling pointer in the case where we store
+    /// a value of type [VVRTType::Nil].
+    #[inline]
+    pub(crate) fn ptr<T: Sized>(&self) -> NonNull<T> {
+        debug_assert_eq!(align_of::<T>(), 8);
+        self.map_or(NonNull::dangling(), |this| unsafe {
+            NonNull::new_unchecked(this.ptr().as_ptr() as *mut T)
+        })
+    }
+
+    /// Build the [VVRTAny] from a pointer assumed to be not null and the type of such pointer.
+    #[inline]
+    unsafe fn from_parts(ptr: *mut u64, ty: VVRTType) -> Self {
+        Self((ty != VVRTType::Nil).then(|| TaggedPtr::new(NonNull::new_unchecked(ptr), ty as usize - 1)))
+    }
+
+    /// Tells whever the contained type is a floating number or not.
+    #[inline]
+    pub fn number_is_f32(&self) -> bool {
+        (self.ty() == VVRTType::Number) && VVRTNumber::from(*self).is_f32()
+    }
+
+    /// Tells whever the contained type is an integer number or not.
+    #[inline]
+    pub fn number_is_i32(&self) -> bool {
+        (self.ty() == VVRTType::Number) && VVRTNumber::from(*self).is_i32()
+    }
+}
+
+impl Default for VVRTAny {
+    /// By default, [VVRTAny] contains an object of type [VVRTType::Nil].
+    #[inline]
+    fn default() -> Self {
+        Self(None)
+    }
+}
+
+impl From<VVRTAny> for VVRTNumber {
+    fn from(value: VVRTAny) -> Self {
+        value.map_or_default(|ptr| VVRTNumber::from_number_be_bytes(ptr.addr().to_be_bytes()))
+    }
+}
+
+impl From<VVRTNumber> for VVRTAny {
+    fn from(value: VVRTNumber) -> Self {
+        unsafe { Self::from_parts(value.as_ptr(), VVRTType::Number) }
+    }
+}
+
+impl From<VVRTAny> for bool {
+    #[inline]
+    fn from(this: VVRTAny) -> Self {
+        Into::<i32>::into(this) != 0
+    }
+}
+
+impl From<VVRTAny> for i32 {
+    #[inline]
+    fn from(this: VVRTAny) -> Self {
+        VVRTNumber::from(this).into()
+    }
+}
+
+impl From<VVRTAny> for f32 {
+    #[inline]
+    fn from(this: VVRTAny) -> Self {
+        VVRTNumber::from(this).into()
+    }
+}
+
+impl From<VVRTVariant> for VVRTAny {
+    #[inline]
+    fn from(ptr: VVRTVariant) -> Self {
+        unsafe { Self::from_parts(ptr.as_ptr(), VVRTType::Variant) }
+    }
+}
+
+impl From<VVRTString> for VVRTAny {
+    #[inline]
+    fn from(ptr: VVRTString) -> Self {
+        unsafe { Self::from_parts(ptr.as_ptr(), VVRTType::String) }
+    }
+}
+
+impl From<VVRTTable> for VVRTAny {
+    #[inline]
+    fn from(ptr: VVRTTable) -> Self {
+        unsafe { Self::from_parts(ptr.as_ptr(), VVRTType::Table) }
+    }
+}
+
+impl From<VVRTSeq> for VVRTAny {
+    #[inline]
+    fn from(ptr: VVRTSeq) -> Self {
+        unsafe { Self::from_parts(ptr.as_ptr(), VVRTType::Seq) }
+    }
+}
+
+impl From<VVRTLine> for VVRTAny {
+    #[inline]
+    fn from(ptr: VVRTLine) -> Self {
+        unsafe { Self::from_parts(ptr.as_ptr(), VVRTType::ASSLine) }
+    }
+}
+
+impl From<VVRTSyllabe> for VVRTAny {
+    #[inline]
+    fn from(ptr: VVRTSyllabe) -> Self {
+        unsafe { Self::from_parts(ptr.as_ptr(), VVRTType::ASSSyllabe) }
+    }
+}
+
+impl From<i32> for VVRTAny {
+    #[inline]
+    fn from(value: i32) -> Self {
+        unsafe { Self::from_parts(VVRTNumber::from(value).as_ptr(), VVRTType::Number) }
+    }
+}
+
+impl From<bool> for VVRTAny {
+    #[inline]
+    fn from(value: bool) -> Self {
+        (value as i32).into()
+    }
+}
+
+impl From<f32> for VVRTAny {
+    #[inline]
+    fn from(value: f32) -> Self {
+        unsafe { Self::from_parts(VVRTNumber::from(value).as_ptr(), VVRTType::Number) }
+    }
+}
+
+impl Eq for VVRTAny {}
+impl PartialEq for VVRTAny {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        unsafe {
+            macro_rules! into {
+                ($what: expr) => {
+                    self.try_into().unwrap_unchecked()
+                };
+            }
+            match self.ty() {
+                ty if ty != other.ty() => false,
+                VVRTType::Nil => true,
+                VVRTType::Number => self.0.unwrap_unchecked().addr() == other.0.unwrap_unchecked().addr(),
+                VVRTType::ASSSyllabe => VVRTSyllabe_eq(into!(self), into!(other)),
+                VVRTType::ASSLine => VVRTLine_eq(into!(self), into!(other)),
+                VVRTType::Variant => VVRTVariant_eq(into!(self), into!(other)),
+                VVRTType::String => VVRTString_eq(into!(self), into!(other)),
+                VVRTType::Table => VVRTTable_eq(into!(self), into!(other)),
+                VVRTType::Seq => VVRTSeq_eq(into!(self), into!(other)),
+            }
+        }
+    }
+}
+
+/// Module used to define functions to be exported for the JIT.
+#[allow(clippy::missing_safety_doc)]
+#[vvs_procmacro::vvrt_bridge(VVRTAny)]
+mod ffi {
+    #[no_mangle]
+    pub unsafe extern "C" fn nil() -> VVRTAny {
+        Default::default()
+    }
+
+    #[no_mangle]
+    pub unsafe extern "C" fn ty(any: VVRTAny) -> VVRTType {
+        any.ty()
+    }
+
+    #[no_mangle]
+    pub unsafe extern "C" fn is_ty(any: VVRTAny, ty: VVRTType) -> bool {
+        any.ty() == ty
+    }
+
+    #[no_mangle]
+    pub unsafe extern "C" fn is_nil(any: VVRTAny) -> bool {
+        any.0.is_none()
+    }
+
+    #[no_mangle]
+    pub unsafe extern "C" fn deep_clone(any: VVRTAny) -> VVRTAny {
+        match any.ty() {
+            // Shallow copy
+            VVRTType::Nil | VVRTType::Number => any,
+            VVRTType::String => VVRTString_clone(any.try_into().unwrap_unchecked()).into(),
+            VVRTType::Variant => VVRTVariant_clone(any.try_into().unwrap_unchecked()).into(),
+
+            // Deep copy
+            VVRTType::Seq => VVRTSeq_deep_clone(any.try_into().unwrap_unchecked()).into(),
+            VVRTType::Table => VVRTTable_deep_clone(any.try_into().unwrap_unchecked()).into(),
+            VVRTType::ASSLine => VVRTLine_deep_clone(any.try_into().unwrap_unchecked()).into(),
+            VVRTType::ASSSyllabe => VVRTSyllabe_deep_clone(any.try_into().unwrap_unchecked()).into(),
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern "C" fn clone(any: VVRTAny) -> VVRTAny {
+        match any.ty() {
+            VVRTType::Nil | VVRTType::Number => any,
+            VVRTType::Seq => VVRTSeq_clone(any.try_into().unwrap_unchecked()).into(),
+            VVRTType::Table => VVRTTable_clone(any.try_into().unwrap_unchecked()).into(),
+            VVRTType::String => VVRTString_clone(any.try_into().unwrap_unchecked()).into(),
+            VVRTType::Variant => VVRTVariant_clone(any.try_into().unwrap_unchecked()).into(),
+            VVRTType::ASSLine => VVRTLine_clone(any.try_into().unwrap_unchecked()).into(),
+            VVRTType::ASSSyllabe => VVRTSyllabe_clone(any.try_into().unwrap_unchecked()).into(),
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern "C" fn drop(any: VVRTAny) {
+        match any.ty() {
+            VVRTType::Nil | VVRTType::Number => {}
+            VVRTType::Seq => VVRTSeq_drop(any.try_into().unwrap_unchecked()),
+            VVRTType::Table => VVRTTable_drop(any.try_into().unwrap_unchecked()),
+            VVRTType::String => VVRTString_drop(any.try_into().unwrap_unchecked()),
+            VVRTType::Variant => VVRTVariant_drop(any.try_into().unwrap_unchecked()),
+            VVRTType::ASSLine => VVRTLine_drop(any.try_into().unwrap_unchecked()),
+            VVRTType::ASSSyllabe => VVRTSyllabe_drop(any.try_into().unwrap_unchecked()),
+        }
+    }
+
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn eq(this: VVRTAny, other: VVRTAny) -> bool { this == other }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ne(this: VVRTAny, other: VVRTAny) -> bool { this != other }
+
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn from_boolean (o: bool)        -> VVRTAny { o.into() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn from_integer (o: i32)         -> VVRTAny { o.into() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn from_floating(o: f32)         -> VVRTAny { o.into() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn from_string  (o: VVRTString)  -> VVRTAny { o.into() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn from_table   (o: VVRTTable)   -> VVRTAny { o.into() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn from_seq     (o: VVRTSeq)     -> VVRTAny { o.into() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn from_variant (o: VVRTVariant) -> VVRTAny { o.into() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn from_line    (o: VVRTLine)    -> VVRTAny { o.into() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn from_syllabe (o: VVRTSyllabe) -> VVRTAny { o.into() }
+
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn as_boolean (any: VVRTAny) -> bool        { any.into() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn as_integer (any: VVRTAny) -> i32         { any.into() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn as_floating(any: VVRTAny) -> f32         { any.into() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn as_string  (any: VVRTAny) -> VVRTString  { any.try_into().unwrap_unchecked() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn as_table   (any: VVRTAny) -> VVRTTable   { any.try_into().unwrap_unchecked() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn as_seq     (any: VVRTAny) -> VVRTSeq     { any.try_into().unwrap_unchecked() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn as_variant (any: VVRTAny) -> VVRTVariant { any.try_into().unwrap_unchecked() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn as_line    (any: VVRTAny) -> VVRTLine    { any.try_into().unwrap_unchecked() }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn as_syllabe (any: VVRTAny) -> VVRTSyllabe { any.try_into().unwrap_unchecked() }
+
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn maybe_as_boolean (any: VVRTAny) -> bool        { VVRTAny_as_boolean(any) }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn maybe_as_integer (any: VVRTAny) -> i32         { VVRTAny_as_integer(any) }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn maybe_as_floating(any: VVRTAny) -> f32         { VVRTAny_as_floating(any) }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn maybe_as_string  (any: VVRTAny) -> VVRTString  { any.try_into().unwrap_or(VVRTString ::dangling()) }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn maybe_as_table   (any: VVRTAny) -> VVRTTable   { any.try_into().unwrap_or(VVRTTable  ::dangling()) }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn maybe_as_seq     (any: VVRTAny) -> VVRTSeq     { any.try_into().unwrap_or(VVRTSeq    ::dangling()) }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn maybe_as_variant (any: VVRTAny) -> VVRTVariant { any.try_into().unwrap_or(VVRTVariant::dangling()) }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn maybe_as_line    (any: VVRTAny) -> VVRTLine    { any.try_into().unwrap_or(VVRTLine   ::dangling()) }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn maybe_as_syllabe (any: VVRTAny) -> VVRTSyllabe { any.try_into().unwrap_or(VVRTSyllabe::dangling()) }
+}
diff --git a/src/Rust/vvs_runtime_types/src/types/line.rs b/src/Rust/vvs_runtime_types/src/types/line.rs
new file mode 100644
index 0000000000000000000000000000000000000000..79dfd2bd3879f92eca0e8b69aebeec5f4b10513e
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/types/line.rs
@@ -0,0 +1,90 @@
+use crate::types::*;
+use std::{ptr::NonNull, rc::Rc};
+use vvs_ass::ASSLine;
+
+/// Represent a line, in an ffi-safe way. We represent if the line was create by using an Rc or was
+/// built from a reference.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct VVRTLine(NonNull<ASSLine<VVRTTable>>);
+crate::types::any::impl_try_from_any! { ASSLine => VVRTLine }
+
+impl VVRTLine {
+    #[inline]
+    pub fn dangling() -> Self {
+        Self(NonNull::dangling())
+    }
+
+    #[inline]
+    pub fn as_ptr(self) -> *mut u64 {
+        self.0.as_ptr() as *mut _
+    }
+
+    #[inline]
+    pub fn is_rc(&self) -> bool {
+        !self.as_ref().aux.rt_infos().is_ass_borrowed
+    }
+}
+
+impl From<ASSLine<VVRTTable>> for VVRTLine {
+    fn from(mut value: ASSLine<VVRTTable>) -> Self {
+        value.aux.rt_infos_mut().is_ass_borrowed = false;
+        let ptr = Rc::into_raw(Rc::new(value)) as *mut _;
+        VVRTLine(unsafe { NonNull::new_unchecked(ptr) })
+    }
+}
+
+impl AsRef<ASSLine<VVRTTable>> for VVRTLine {
+    fn as_ref(&self) -> &ASSLine<VVRTTable> {
+        unsafe { self.0.as_ref() }
+    }
+}
+
+impl AsMut<ASSLine<VVRTTable>> for VVRTLine {
+    fn as_mut(&mut self) -> &mut ASSLine<VVRTTable> {
+        unsafe { self.0.as_mut() }
+    }
+}
+
+impl Eq for VVRTLine {}
+impl PartialEq for VVRTLine {
+    fn eq(&self, other: &Self) -> bool {
+        self.as_ref().eq(other.as_ref())
+    }
+}
+
+/// Module used to defined functions to be exported to the JIT.
+#[allow(clippy::missing_safety_doc)]
+#[vvs_procmacro::vvrt_bridge(VVRTLine)]
+mod ffi {
+    #[no_mangle]
+    pub unsafe extern "C" fn deep_clone(this: VVRTLine) -> VVRTLine {
+        this.as_ref().clone().into()
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn clone(this @ VVRTLine(ptr): VVRTLine) -> VVRTLine {
+        match this.is_rc() {
+            false => VVRTLine_deep_clone(this),
+            true => {
+                Rc::increment_strong_count(ptr.as_ptr());
+                this
+            }
+        }
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn drop(this @ VVRTLine(ptr): VVRTLine) {
+        if this.is_rc() {
+            Rc::decrement_strong_count(ptr.as_ptr())
+        }
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn len(this: VVRTLine) -> i32 {
+        this.as_ref().content.len().clamp(0, i32::MAX as usize) as i32
+    }
+
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn eq(this: VVRTLine, other: VVRTLine) -> bool { PartialEq::eq(&this, &other) }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ne(this: VVRTLine, other: VVRTLine) -> bool { PartialEq::ne(&this, &other) }
+}
diff --git a/src/Rust/vvs_runtime_types/src/types/mod.rs b/src/Rust/vvs_runtime_types/src/types/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1e8972a6cfcf7456903aba3263eda46071f3ac71
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/types/mod.rs
@@ -0,0 +1,178 @@
+//! Here we have the base types for the runtime.
+
+/// Get the list of all the builtin types.
+macro_rules! builtin_types {
+    ($macro: ident) => {
+        $macro!(any, sequence, string, table, variant, line, syllabe);
+    };
+}
+
+/// Declare the modules associated with the builtin types.
+macro_rules! decl_modules {
+    ($mod: ident $(,)?) => {
+        mod $mod;
+    };
+    ($mod: ident, $($mods: ident),+ $(,)?) => {
+        decl_modules!($mod);
+        decl_modules!($($mods),+);
+    };
+}
+builtin_types!(decl_modules);
+
+mod number;
+
+use self::{any::*, line::*, number::*, sequence::*, string::*, syllabe::*, table::*, variant::*};
+use crate::vvll::*;
+use std::sync::OnceLock;
+use vvs_llvm::*;
+
+#[cfg(test)]
+mod test;
+
+pub use self::{
+    any::VVRTAny, line::VVRTLine, sequence::VVRTSeq, string::VVRTString, syllabe::VVRTSyllabe, table::VVRTTable,
+    variant::VVRTVariant,
+};
+
+/// Get the builtin types
+pub fn builtin_types() -> &'static [&'static str] {
+    #[allow(dead_code)]
+    static NUMBERS_ARE_COHERENT: () = {
+        assert!(
+            std::mem::size_of::<f32>() == std::mem::size_of::<i32>(),
+            "we need for the layout of the numbers to be the same to do our shenanigans"
+        );
+        assert!(
+            std::mem::align_of::<f32>() == std::mem::align_of::<i32>(),
+            "we need for the layout of the numbers to be the same to do our shenanigans"
+        );
+    };
+
+    static TYPES: OnceLock<Vec<&'static str>> = OnceLock::new();
+    TYPES
+        .get_or_init(|| {
+            let mut ret = vec![];
+            macro_rules! decl_hashmap {
+                ($mod: ident $(,)?) => {{
+                    ret.push(stringify!($mod));
+                }};
+                ($mod: ident, $($mods: ident),+ $(,)?) => {{
+                    decl_hashmap!($mod);
+                    decl_hashmap!($($mods),+);
+                }};
+            }
+            builtin_types!(decl_hashmap);
+            ret
+        })
+        .as_slice()
+}
+
+/// Represent every types.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+#[repr(u8)]
+pub enum VVRTType {
+    /// Null, we ensure that [Option<VVRTAny>::None] is 0.
+    Nil = 0,
+
+    /// Numbers are floats or integers
+    Number = 1,
+
+    /// An immutable string
+    String = 2,
+
+    /// Table, a container indexed by string.
+    Table = 3,
+
+    /// A sequence, a container indexed by integer, items are pushed or poped.
+    Seq = 4,
+
+    /// A variant.
+    Variant = 5,
+
+    /// An ASS Line
+    ASSLine = 6,
+
+    /// An ASS Syllabe
+    ASSSyllabe = 7,
+}
+
+impl Default for VVRTType {
+    fn default() -> Self {
+        #[allow(dead_code)]
+        const SMUGGLE_TYPE: () = match VVRTType::Nil {
+            t @ VVRTType::Nil
+            | t @ VVRTType::String
+            | t @ VVRTType::Number
+            | t @ VVRTType::Table
+            | t @ VVRTType::Seq
+            | t @ VVRTType::ASSLine
+            | t @ VVRTType::ASSSyllabe
+            | t @ VVRTType::Variant => assert!(t as usize <= 8),
+        };
+        #[rustfmt::skip] #[allow(dead_code)]
+        const TYPE_ABI: () = {
+            // Non-managed
+            assert!((VVRTType::Number     as usize - 1) == 0b000);
+
+            // Managed
+            assert!((VVRTType::String     as usize - 1) == 0b001);
+            assert!((VVRTType::Table      as usize - 1) == 0b010);
+            assert!((VVRTType::Seq        as usize - 1) == 0b011);
+            assert!((VVRTType::Variant    as usize - 1) == 0b100);
+            assert!((VVRTType::ASSLine    as usize - 1) == 0b101);
+            assert!((VVRTType::ASSSyllabe as usize - 1) == 0b110);
+
+            // We want to use 0b111 for user types in the future...
+        };
+        VVRTType::Nil
+    }
+}
+
+impl VVRTType {
+    /// Get the type as a constant to be used in LLVM codegen.
+    ///
+    /// # Safety
+    /// The [LLVMContextRef] must be valid.
+    #[inline]
+    pub unsafe fn as_llvm_const(&self, c: LLVMContextRef) -> LLVMValueRef {
+        LLVMConstInt(LLVMInt8TypeInContext(c), *self as u64, 0)
+    }
+}
+
+impl LLVMExported for VVRTType {
+    unsafe fn llvm_type(c: LLVMContextRef) -> LLVMTypeRef {
+        #[allow(dead_code)]
+        const TYPE_IS_VALID: () = {
+            assert!(std::mem::size_of::<VVRTType>() == 1);
+            assert!(std::mem::align_of::<VVRTType>() == 1);
+        };
+        LLVMInt8TypeInContext(c)
+    }
+
+    unsafe fn llvm_properties(_: LLVMContextRef) -> Properties {
+        Default::default()
+    }
+}
+
+impl AsRef<str> for VVRTType {
+    #[inline]
+    fn as_ref(&self) -> &str {
+        match self {
+            VVRTType::Nil => "nil",
+            VVRTType::String => "string",
+            VVRTType::Number => "number",
+            VVRTType::Table => "table",
+            VVRTType::Seq => "seq",
+            VVRTType::Variant => "variant",
+            VVRTType::ASSLine => "line",
+            VVRTType::ASSSyllabe => "line",
+        }
+    }
+}
+
+impl std::fmt::Display for VVRTType {
+    #[inline]
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_str(self.as_ref())
+    }
+}
diff --git a/src/Rust/vvs_runtime_types/src/types/number.rs b/src/Rust/vvs_runtime_types/src/types/number.rs
new file mode 100644
index 0000000000000000000000000000000000000000..dead33bedb2318f1d52ff6185b7e302aa3b00e57
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/types/number.rs
@@ -0,0 +1,116 @@
+//! Contains utility to manipulate numbers from the runtime.
+
+use vvs_utils::either;
+
+/// Wrapper type for numbers that is intended to be used only for the [crate::types::VVRTAny]
+/// and [crate::types::VVRTVariant] structs.
+#[derive(Clone, Copy)]
+#[repr(transparent)]
+pub struct VVRTNumber(u64);
+
+impl VVRTNumber {
+    const FLT_TAG: u8 = 1;
+    const INT_TAG: u8 = !Self::FLT_TAG;
+
+    /// Cast the number as a pointer. We ensure by construction that this pointer is never null.
+    /// You may never deref this pointer!
+    #[inline]
+    pub fn as_ptr(&self) -> *mut u64 {
+        self.0 as *mut _
+    }
+
+    /// In debug mode, assert that the passed bytes are a valid number representation. In case of
+    /// success re-return those bytes.
+    ///
+    /// In release build this function is a NoOp.
+    #[inline]
+    fn assert_is_number(bytes: [u8; 8]) -> [u8; 8] {
+        let [.., flag, z1, z2, z3] = bytes;
+        debug_assert!(z1 == z2 && z2 == z3 && z3 == 0, "invalid number");
+        debug_assert!(flag == Self::INT_TAG || flag == Self::FLT_TAG, "invalid tag");
+        bytes
+    }
+
+    /// Get the byte representation of the number we store.
+    fn as_bytes(&self) -> (u8, [u8; 4]) {
+        let [b1, b2, b3, b4, flag, _, _, _] = Self::assert_is_number(self.0.to_be_bytes());
+        (flag, [b1, b2, b3, b4])
+    }
+
+    /// Create [VVRTAny] from bytes assumed to be a valid number representation.
+    #[inline]
+    pub fn from_number_be_bytes(bytes: [u8; 8]) -> Self {
+        Self(u64::from_be_bytes(Self::assert_is_number(bytes)))
+    }
+
+    /// Tells whever the contained type is a floating number or not.
+    #[inline]
+    pub fn is_f32(&self) -> bool {
+        self.as_bytes().0 == Self::FLT_TAG
+    }
+
+    /// Tells whever the contained type is an integer number or not.
+    #[inline]
+    pub fn is_i32(&self) -> bool {
+        !self.is_f32()
+    }
+}
+
+impl Default for VVRTNumber {
+    fn default() -> Self {
+        0_i32.into()
+    }
+}
+
+impl From<VVRTNumber> for i32 {
+    fn from(value: VVRTNumber) -> Self {
+        let (flag, bytes) = value.as_bytes();
+        either!(flag == VVRTNumber::INT_TAG
+            => i32::from_be_bytes(bytes)
+            ;  f32::from_be_bytes(bytes) as i32
+        )
+    }
+}
+
+impl From<VVRTNumber> for f32 {
+    fn from(value: VVRTNumber) -> Self {
+        let (flag, bytes) = value.as_bytes();
+        either!(flag == VVRTNumber::INT_TAG
+            => i32::from_be_bytes(bytes) as f32
+            ;  f32::from_be_bytes(bytes)
+        )
+    }
+}
+
+impl From<i32> for VVRTNumber {
+    fn from(value: i32) -> Self {
+        let [b1, b2, b3, b4] = value.to_be_bytes();
+        VVRTNumber::from_number_be_bytes([b1, b2, b3, b4, VVRTNumber::INT_TAG, 0, 0, 0])
+    }
+}
+
+impl From<f32> for VVRTNumber {
+    fn from(value: f32) -> Self {
+        let [b1, b2, b3, b4] = value.to_be_bytes();
+        VVRTNumber::from_number_be_bytes([b1, b2, b3, b4, VVRTNumber::FLT_TAG, 0, 0, 0])
+    }
+}
+
+impl std::fmt::Debug for VVRTNumber {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let (flag, bytes) = self.as_bytes();
+        f.debug_struct("VVRTNumber")
+            .field("flag", &flag)
+            .field("bytes", &bytes)
+            .finish()
+    }
+}
+
+impl std::fmt::Display for VVRTNumber {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self.is_f32() {
+            true => write!(f, "{}", Into::<f32>::into(*self)),
+            false => write!(f, "{}", Into::<i32>::into(*self)),
+        }
+    }
+}
diff --git a/src/Rust/vvs_runtime_types/src/types/sequence.rs b/src/Rust/vvs_runtime_types/src/types/sequence.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3d315014ec52852e3805f4dcbcb1eae831ce0d62
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/types/sequence.rs
@@ -0,0 +1,107 @@
+use crate::types::*;
+use std::{ptr::NonNull, rc::Rc};
+
+#[derive(Debug, Clone, Copy)]
+#[repr(transparent)]
+pub struct VVRTSeq(NonNull<Vec<VVRTAny>>);
+crate::types::any::impl_try_from_any! { Seq => VVRTSeq }
+
+impl VVRTSeq {
+    #[inline]
+    pub fn dangling() -> Self {
+        Self(NonNull::dangling())
+    }
+
+    #[inline]
+    pub fn as_ptr(self) -> *mut u64 {
+        self.0.as_ptr() as *mut _
+    }
+
+    #[inline]
+    fn as_slice(&self) -> &[VVRTAny] {
+        unsafe { self.0.as_ref() }.as_slice()
+    }
+
+    #[inline]
+    fn from_vec(content: Vec<VVRTAny>) -> Self {
+        unsafe { Self(NonNull::new_unchecked(Rc::into_raw(Rc::new(content)) as *mut _)) }
+    }
+}
+
+impl Default for VVRTSeq {
+    #[inline]
+    fn default() -> Self {
+        Self::from_vec(Default::default())
+    }
+}
+
+impl Eq for VVRTSeq {}
+impl PartialEq for VVRTSeq {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.as_slice() == other.as_slice()
+    }
+}
+
+/// Module used to defined functions to be exported to the JIT.
+#[allow(clippy::missing_safety_doc)]
+#[vvs_procmacro::vvrt_bridge(VVRTSeq)]
+mod ffi {
+    #[no_mangle]
+    pub unsafe extern "C" fn new() -> VVRTSeq {
+        Default::default()
+    }
+
+    /// Here we decrement the count of each child because we owned them. We don't support cyclic
+    /// references...
+    #[no_mangle]
+    pub unsafe extern "C" fn drop(this @ VVRTSeq(ptr): VVRTSeq) {
+        this.as_slice().iter().for_each(|child| VVRTAny_drop(*child));
+        Rc::decrement_strong_count(ptr.as_ptr());
+    }
+
+    /// Here we increment the count of each child because we owned them. We don't support cyclic
+    /// references...
+    #[no_mangle]
+    pub unsafe extern "C" fn clone(this @ VVRTSeq(ptr): VVRTSeq) -> VVRTSeq {
+        this.as_slice().iter().for_each(|child| {
+            let _ = VVRTAny_clone(*child);
+        });
+        Rc::increment_strong_count(ptr.as_ptr());
+        VVRTSeq(ptr)
+    }
+
+    #[no_mangle]
+    pub unsafe extern "C" fn deep_clone(VVRTSeq(ptr): VVRTSeq) -> VVRTSeq {
+        let mut content = Vec::with_capacity(ptr.as_ref().len());
+        ptr.as_ref().iter().for_each(|e| content.push(VVRTAny_deep_clone(*e)));
+        VVRTSeq::from_vec(content)
+    }
+
+    /// Get an item from the sequence, clone it.
+    #[no_mangle]
+    pub unsafe extern "C" fn get(this: VVRTSeq, idx: i32) -> VVRTAny {
+        this.as_slice()
+            .get(idx.clamp(0, i32::MAX) as usize)
+            .map(|item| VVRTAny_clone(*item))
+            .unwrap_or_default()
+    }
+
+    /// Push an item into the sequence, we take ownership of the item.
+    #[no_mangle]
+    pub unsafe extern "C" fn push(VVRTSeq(mut this): VVRTSeq, item: VVRTAny) {
+        debug_assert!(
+            !matches!(item.ty(), VVRTType::Table | VVRTType::Seq),
+            "can't store container in containers"
+        );
+        this.as_mut().push(item);
+    }
+
+    #[no_mangle]
+    pub unsafe extern "C" fn len(seq: VVRTSeq) -> i32 {
+        seq.as_slice().len().try_into().expect("sequence to big")
+    }
+
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn eq(this: VVRTSeq, other: VVRTSeq) -> bool { PartialEq::eq(&this, &other) }
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn ne(this: VVRTSeq, other: VVRTSeq) -> bool { PartialEq::ne(&this, &other) }
+}
diff --git a/src/Rust/vvs_runtime_types/src/types/string.rs b/src/Rust/vvs_runtime_types/src/types/string.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e6525f71dd3f57b27312ad6c8c270cd3aa0eca64
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/types/string.rs
@@ -0,0 +1,122 @@
+use crate::types::*;
+use std::{hash::Hash, ptr::NonNull, rc::Rc};
+
+/// We represent a string, in an FFI-Safe way because slices are not FFI-Safe...
+#[derive(Debug, Clone, Copy)]
+#[repr(transparent)]
+pub struct VVRTString(NonNull<Vec<u8>>);
+crate::types::any::impl_try_from_any! { String => VVRTString }
+
+impl VVRTString {
+    #[inline]
+    pub fn dangling() -> Self {
+        Self(NonNull::dangling())
+    }
+
+    #[inline]
+    pub fn as_ptr(self) -> *mut u64 {
+        self.0.as_ptr() as *mut _
+    }
+
+    #[inline]
+    pub fn as_str(&self) -> &str {
+        unsafe { std::str::from_utf8_unchecked(self.as_bytes()) }
+    }
+
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        unsafe { self.0.as_ref().as_slice() }
+    }
+
+    #[inline]
+    pub fn from_bytes(bytes: &[u8]) -> Self {
+        Self::from_vec(bytes.to_vec())
+    }
+
+    #[inline]
+    pub fn from_vec(bytes: Vec<u8>) -> Self {
+        unsafe { VVRTString(NonNull::new_unchecked(Rc::into_raw(Rc::new(bytes)) as *mut _)) }
+    }
+}
+
+impl Default for VVRTString {
+    fn default() -> Self {
+        Self::from_vec(Default::default())
+    }
+}
+
+impl AsRef<str> for VVRTString {
+    #[inline]
+    fn as_ref(&self) -> &str {
+        self.as_str()
+    }
+}
+
+impl Eq for VVRTString {}
+impl PartialEq for VVRTString {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.as_str() == other.as_str()
+    }
+}
+
+impl Hash for VVRTString {
+    #[inline]
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.as_str().hash(state);
+    }
+}
+
+impl PartialOrd for VVRTString {
+    #[inline]
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        PartialOrd::partial_cmp(self.as_str(), other.as_str())
+    }
+}
+
+/// Module used to defined functions to be exported to the JIT.
+#[allow(clippy::missing_safety_doc)]
+#[vvs_procmacro::vvrt_bridge(VVRTString)]
+mod ffi {
+    #[no_mangle]
+    unsafe extern "C" fn new_from_raw(ptr: *const u8, len: i32) -> VVRTString {
+        let len: usize = len.try_into().expect("string too big");
+        VVRTString::from_bytes(std::slice::from_raw_parts(ptr, len))
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn cat(left: VVRTString, right: VVRTString) -> VVRTString {
+        let mut res = left.as_bytes().to_vec();
+        res.extend_from_slice(right.as_bytes());
+        VVRTString::from_vec(res)
+    }
+
+    #[no_mangle]
+    pub unsafe extern "C" fn deep_clone(this: VVRTString) -> VVRTString {
+        VVRTString_clone(this)
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn clone(VVRTString(ptr): VVRTString) -> VVRTString {
+        Rc::increment_strong_count(ptr.as_ptr());
+        VVRTString(ptr)
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn drop(VVRTString(ptr): VVRTString) {
+        Rc::decrement_strong_count(ptr.as_ptr())
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn len(str: VVRTString) -> i32 {
+        str.as_str().len().try_into().expect("string too long")
+    }
+
+    use std::cmp::Ordering::*;
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn eq(a: VVRTString, b: VVRTString) -> bool { PartialEq::eq(&a, &b) }
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn ne(a: VVRTString, b: VVRTString) -> bool { PartialEq::ne(&a, &b) }
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn lt(a: VVRTString, b: VVRTString) -> bool { matches!(a.partial_cmp(&b), Some(Less           )) }
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn gt(a: VVRTString, b: VVRTString) -> bool { matches!(a.partial_cmp(&b), Some(Greater        )) }
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn le(a: VVRTString, b: VVRTString) -> bool { matches!(a.partial_cmp(&b), Some(Less    | Equal)) }
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn ge(a: VVRTString, b: VVRTString) -> bool { matches!(a.partial_cmp(&b), Some(Greater | Equal)) }
+}
diff --git a/src/Rust/vvs_runtime_types/src/types/syllabe.rs b/src/Rust/vvs_runtime_types/src/types/syllabe.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4fedf77492776567bcaf3f2f9b3d4f3ac8b2c322
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/types/syllabe.rs
@@ -0,0 +1,91 @@
+use crate::types::*;
+use std::{ptr::NonNull, rc::Rc};
+use vvs_ass::ASSSyllabe;
+
+/// Represent a syllabe, in an ffi-safe way. We represent if the syllabe was create by using an Rc
+/// or was built from a reference.
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+pub struct VVRTSyllabe(NonNull<ASSSyllabe<VVRTTable>>);
+crate::types::any::impl_try_from_any! { ASSSyllabe => VVRTSyllabe }
+
+impl VVRTSyllabe {
+    #[inline]
+    pub fn dangling() -> Self {
+        Self(NonNull::dangling())
+    }
+
+    #[inline]
+    pub fn as_ptr(self) -> *mut u64 {
+        self.0.as_ptr() as *mut _
+    }
+
+    #[inline]
+    pub fn is_rc(&self) -> bool {
+        !self.as_ref().aux.rt_infos().is_ass_borrowed
+    }
+}
+
+impl From<ASSSyllabe<VVRTTable>> for VVRTSyllabe {
+    fn from(mut value: ASSSyllabe<VVRTTable>) -> Self {
+        value.aux.rt_infos_mut().is_ass_borrowed = false;
+        let ptr = Rc::into_raw(Rc::new(value)) as *mut _;
+        VVRTSyllabe(unsafe { NonNull::new_unchecked(ptr) })
+    }
+}
+
+impl AsRef<ASSSyllabe<VVRTTable>> for VVRTSyllabe {
+    fn as_ref(&self) -> &ASSSyllabe<VVRTTable> {
+        unsafe { self.0.as_ref() }
+    }
+}
+
+impl AsMut<ASSSyllabe<VVRTTable>> for VVRTSyllabe {
+    fn as_mut(&mut self) -> &mut ASSSyllabe<VVRTTable> {
+        unsafe { self.0.as_mut() }
+    }
+}
+
+
+impl Eq for VVRTSyllabe {}
+impl PartialEq for VVRTSyllabe {
+    fn eq(&self, other: &Self) -> bool {
+        self.as_ref().eq(other.as_ref())
+    }
+}
+
+/// Module used to defined functions to be exported to the JIT.
+#[allow(clippy::missing_safety_doc)]
+#[vvs_procmacro::vvrt_bridge(VVRTSyllabe)]
+mod ffi {
+    #[no_mangle]
+    pub unsafe extern "C" fn deep_clone(this: VVRTSyllabe) -> VVRTSyllabe {
+        this.as_ref().clone().into()
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn clone(this @ VVRTSyllabe(ptr): VVRTSyllabe) -> VVRTSyllabe {
+        match this.is_rc() {
+            false => VVRTSyllabe_deep_clone(this),
+            true => {
+                Rc::increment_strong_count(ptr.as_ptr());
+                this
+            }
+        }
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn drop(this @ VVRTSyllabe(ptr): VVRTSyllabe) {
+        if this.is_rc() {
+            Rc::decrement_strong_count(ptr.as_ptr())
+        }
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn len(this: VVRTSyllabe) -> i32 {
+        this.as_ref().content.len().clamp(0, i32::MAX as usize) as i32
+    }
+
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn eq(this: VVRTSyllabe, other: VVRTSyllabe) -> bool { PartialEq::eq(&this, &other) }
+    #[rustfmt::skip] #[no_mangle] pub unsafe extern "C" fn ne(this: VVRTSyllabe, other: VVRTSyllabe) -> bool { PartialEq::ne(&this, &other) }
+}
diff --git a/src/Rust/vvs_runtime_types/src/types/table.rs b/src/Rust/vvs_runtime_types/src/types/table.rs
new file mode 100644
index 0000000000000000000000000000000000000000..fa89182e36116a1b3c267123a9de797cf93eda6e
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/types/table.rs
@@ -0,0 +1,171 @@
+use crate::types::*;
+use hashbrown::HashMap;
+use std::{ptr::NonNull, rc::Rc};
+
+/// Aux struct used to store infos about runtime types that imbark a VVRTTable and where we don't
+/// have enaugh space in the trailing zeros of the pointer to store them...
+#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
+pub struct VVRTInfos {
+    pub is_ass_borrowed: bool,
+}
+
+/// A table, really just a hashmap.
+///
+/// NOTE: Needs to be clone to be able to be used in the ASS things...
+///
+/// In a table we also embark an AUX structure to store runtime informations about ass types that
+/// owns this table, or any other thing that may be necessary latter down the line... When
+/// comparing tables we don't compare the [VVRTInfos] struct.
+#[derive(Debug, Clone, Copy)]
+#[repr(transparent)]
+pub struct VVRTTable(NonNull<(HashMap<VVRTString, VVRTAny>, VVRTInfos)>);
+crate::types::any::impl_try_from_any! { Table => VVRTTable }
+
+impl VVRTTable {
+    #[inline]
+    pub fn dangling() -> Self {
+        Self(NonNull::dangling())
+    }
+
+    #[inline]
+    pub fn as_ptr(self) -> *mut u64 {
+        self.0.as_ptr() as *mut _
+    }
+
+    #[inline]
+    pub fn iter(&self) -> hashbrown::hash_map::Iter<VVRTString, VVRTAny> {
+        unsafe { self.0.as_ref() }.0.iter()
+    }
+
+    #[inline]
+    pub fn iter_mut(&mut self) -> hashbrown::hash_map::IterMut<VVRTString, VVRTAny> {
+        unsafe { self.0.as_mut() }.0.iter_mut()
+    }
+
+    #[inline]
+    pub fn rt_infos(&self) -> &VVRTInfos {
+        &unsafe { self.0.as_ref() }.1
+    }
+
+    #[inline]
+    pub fn rt_infos_mut(&mut self) -> &mut VVRTInfos {
+        &mut unsafe { self.0.as_mut() }.1
+    }
+}
+
+impl AsMut<HashMap<VVRTString, VVRTAny>> for VVRTTable {
+    fn as_mut(&mut self) -> &mut HashMap<VVRTString, VVRTAny> {
+        &mut unsafe { self.0.as_mut() }.0
+    }
+}
+
+impl AsRef<HashMap<VVRTString, VVRTAny>> for VVRTTable {
+    fn as_ref(&self) -> &HashMap<VVRTString, VVRTAny> {
+        &unsafe { self.0.as_ref() }.0
+    }
+}
+
+impl vvs_ass::AuxTable for VVRTTable {
+    #[inline]
+    fn deep_clone(&self) -> Self {
+        unsafe { VVRTTable_deep_clone(*self) }
+    }
+}
+
+impl Default for VVRTTable {
+    #[inline]
+    fn default() -> Self {
+        HashMap::<VVRTString, VVRTAny>::default().into()
+    }
+}
+
+impl From<HashMap<VVRTString, VVRTAny>> for VVRTTable {
+    #[inline]
+    fn from(value: HashMap<VVRTString, VVRTAny>) -> Self {
+        Self(unsafe { NonNull::new_unchecked(Rc::into_raw(Rc::new(value)) as *mut _) })
+    }
+}
+
+impl Eq for VVRTTable {}
+impl PartialEq for VVRTTable {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        self.as_ref().eq(other.as_ref())
+    }
+}
+
+/// Module used to define functions to be exported for the JIT.
+#[allow(clippy::missing_safety_doc)]
+#[vvs_procmacro::vvrt_bridge(VVRTTable)]
+mod ffi {
+    #[no_mangle]
+    pub unsafe extern "C" fn new() -> VVRTTable {
+        Default::default()
+    }
+
+    /// Deeply clone the table.
+    #[no_mangle]
+    pub unsafe extern "C" fn deep_clone(this: VVRTTable) -> VVRTTable {
+        this.as_ref()
+            .iter()
+            .map(|(k, v)| (VVRTString_clone(*k), VVRTAny_deep_clone(*v)))
+            .collect::<HashMap<_, _>>()
+            .into()
+    }
+
+    /// Increment the count of each child because we own them. This function is not-reentrent and
+    /// we don't support cyclic references...
+    #[no_mangle]
+    pub unsafe extern "C" fn clone(this @ VVRTTable(ptr): VVRTTable) -> VVRTTable {
+        this.iter().for_each(|(key, value)| {
+            let _ = VVRTString_clone(*key);
+            let _ = VVRTAny_clone(*value);
+        });
+        Rc::increment_strong_count(ptr.as_ptr());
+        VVRTTable(ptr)
+    }
+
+    // Decrement the count of each child because we own them. We don't support cyclic references...
+    #[no_mangle]
+    pub unsafe extern "C" fn drop(this @ VVRTTable(ptr): VVRTTable) {
+        this.iter().for_each(|(key, value)| {
+            VVRTString_drop(*key);
+            VVRTAny_drop(*value);
+        });
+        Rc::decrement_strong_count(ptr.as_ptr())
+    }
+
+    /// Insert something into the table. Any old present value will be dropped. The key and value
+    /// are consumed by this function.
+    #[no_mangle]
+    pub unsafe extern "C" fn insert(mut table: VVRTTable, key: VVRTString, value: VVRTAny) {
+        debug_assert!(
+            !matches!(value.ty(), VVRTType::Table | VVRTType::Seq),
+            "can't store container in containers"
+        );
+        if let Some(old) = table.as_mut().insert(key, value) {
+            VVRTAny_drop(old)
+        }
+    }
+
+    /// Insert something into the table. Any old present value will be dropped. The value is
+    /// consumed by this function. The key string will be used to create a new string.
+    #[no_mangle]
+    pub unsafe extern "C" fn insert_from_raw_key(table: VVRTTable, key: *const u8, len: i32, value: VVRTAny) {
+        let key = VVRTString_new_from_raw(key, len);
+        VVRTTable_insert(table, key, value);
+    }
+
+    /// Get the content of of the table. The thing is cloned when getted from the table.
+    #[no_mangle]
+    pub unsafe extern "C" fn get(table: VVRTTable, key: VVRTString) -> VVRTAny {
+        table
+            .as_ref()
+            .get(&key)
+            .map(|item| VVRTAny_clone(*item))
+            .unwrap_or_default()
+    }
+
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn eq(this: VVRTTable, other: VVRTTable) -> bool { PartialEq::eq(&this, &other) }
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn ne(this: VVRTTable, other: VVRTTable) -> bool { PartialEq::ne(&this, &other) }
+}
diff --git a/src/Rust/vvs_runtime_types/src/types/test.rs b/src/Rust/vvs_runtime_types/src/types/test.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f10738bf74b413051d629b592744fb4473541963
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/types/test.rs
@@ -0,0 +1,30 @@
+use super::*;
+use std::mem::size_of;
+
+#[test]
+fn nil_and_options() {
+    let nil = unsafe { VVRTAny_nil() };
+    assert_eq!(nil.ty(), VVRTType::Nil, "invalid type");
+    assert_eq!(size_of::<VVRTType>(), size_of::<Option<VVRTType>>());
+}
+
+#[test]
+fn any_integer() {
+    unsafe {
+        let zero = Into::<VVRTAny>::into(0i32);
+        assert!(VVRTAny_is_ty(zero, VVRTType::Number));
+        assert!(!zero.number_is_f32());
+        assert!(zero.number_is_i32());
+        assert_eq!(VVRTAny_as_integer(zero), 0);
+        assert_eq!(VVRTAny_as_floating(zero), 0.0);
+
+        let zero = Into::<VVRTAny>::into(0f32);
+        assert!(VVRTAny_is_ty(zero, VVRTType::Number));
+        assert!(zero.number_is_f32());
+        assert!(!zero.number_is_i32());
+        assert_eq!(VVRTAny_as_integer(zero), 0);
+        assert_eq!(VVRTAny_as_floating(zero), 0.0);
+
+        assert!(VVRTAny_ne(Into::<VVRTAny>::into(0f32), Into::<VVRTAny>::into(0i32)));
+    }
+}
diff --git a/src/Rust/vvs_runtime_types/src/types/variant.rs b/src/Rust/vvs_runtime_types/src/types/variant.rs
new file mode 100644
index 0000000000000000000000000000000000000000..92da9f775f9b113fdfe44d95a7d4e3159c6e55b8
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/types/variant.rs
@@ -0,0 +1,361 @@
+use crate::types::*;
+use anyhow::{anyhow, bail, ensure};
+use std::{
+    alloc,
+    mem::{size_of, transmute},
+    ptr::NonNull,
+    slice, str,
+};
+
+/// Store all the registered variants. We share variants between colors and movements.
+static mut VARIANTS: Vec<VariantDescription> = Vec::new();
+
+struct VariantDescription {
+    /// The name of the variant family in the AST, like color or movement.
+    ast_name: &'static str,
+
+    /// The name of the variant in its family, like `rgb`, `move`, etc.
+    variant_name: &'static str,
+
+    /// The content of this variant, we store the runtime types here.
+    arguments: Vec<VVRTType>,
+
+    /// The layout of this variant. If we have a string we don't store the content of said string
+    /// here, we only take into account the integer used to store the length of the string.
+    layout: alloc::Layout,
+
+    /// The layouts of the content of this variant. Note that we also store the offset of the
+    /// discriminent in this vector. Because of that, we have the following:
+    /// `assert!(arguments.len() == offsets.len() + 1)`;
+    offsets: Vec<usize>,
+}
+
+unsafe fn get_variant_argument_count_by_discriminent(discriminent: usize) -> i32 {
+    VARIANTS[discriminent].arguments.len() as i32
+}
+
+unsafe fn get_variant_desc_by_name(
+    ast: &str,
+    var: &str,
+) -> (usize, &'static alloc::Layout, &'static [usize], &'static [VVRTType]) {
+    VARIANTS
+        .iter()
+        .enumerate()
+        .find_map(
+            |(idx, VariantDescription { ast_name, variant_name, layout, offsets, arguments })| {
+                (*ast_name == ast && *variant_name == var).then_some((idx, layout, &**offsets, &**arguments))
+            },
+        )
+        .expect("asked to build an invalid variant")
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(transparent)]
+pub struct VVRTVariant(NonNull<u64>);
+crate::types::any::impl_try_from_any! { Variant => VVRTVariant }
+
+impl VVRTVariant {
+    #[inline]
+    pub fn dangling() -> Self {
+        Self(NonNull::dangling())
+    }
+
+    #[inline]
+    pub fn discriminent(&self) -> usize {
+        unsafe { *transmute::<*mut u64, *const usize>(self.0.as_ptr()) }
+    }
+
+    /// # Safety
+    /// This function is not thread safe.
+    pub unsafe fn register_runtime_variant(
+        ast_name: &'static str,
+        variant_name: &'static str,
+        arguments: Vec<VVRTType>,
+    ) -> anyhow::Result<()> {
+        use VVRTType::*;
+        let name = format!("{ast_name}.{variant_name}");
+
+        if let [heads @ .., last] = &arguments[..] {
+            heads.iter().copied().enumerate().try_for_each(|(idx, ty)| {
+                (!matches!(ty, Number))
+                    .then_some(())
+                    .ok_or_else(|| anyhow!("found invalid argument type `{ty}` at position {idx} in variant `{name}`"))
+            })?;
+            ensure!(
+                matches!(last, String | Number),
+                "found invalid argument type `{last}` at last position in variant `{name}`"
+            );
+        }
+
+        (!VARIANTS
+            .iter()
+            .any(|desc| desc.ast_name == ast_name && desc.variant_name == variant_name))
+        .then(|| -> anyhow::Result<()> {
+            let (layout, offsets) = VVRTVariant::layout(&arguments)?;
+            VARIANTS.push(VariantDescription { ast_name, variant_name, arguments, layout, offsets });
+            Ok(())
+        })
+        .ok_or_else(|| anyhow!("redefinition of variant {name}"))?
+    }
+
+    /// Get the location of the variant.
+    #[inline]
+    pub fn as_ptr(self) -> *mut u64 {
+        self.0.as_ptr()
+    }
+
+    /// Get the base of the memory corresponding to the passed index along side the type of this
+    /// memory location.
+    unsafe fn offset_of_index(&self, idx: i32) -> (*const u8, VVRTType) {
+        let VariantDescription { arguments, offsets, .. } =
+            VARIANTS.get(self.discriminent()).expect("variant was not valid");
+
+        debug_assert!(arguments.len() == offsets.len() + 1, "invalid variant");
+        debug_assert!(arguments.len() > idx as usize, "invalid index");
+
+        // In the offsets we store the initial index for the discriminent in the offsets also!
+        let ptr: *const u8 = self.0.as_ptr().byte_add(offsets[idx as usize + 1]) as *const _;
+        (ptr, arguments[idx as usize])
+    }
+
+    /// Compute the layout for the content of a variant. Because of how we represent strings in a
+    /// variant, a vairant is immutable, like strings. Here we don't put the space for the content
+    /// of the string because we can't know it.
+    fn layout(body: &[VVRTType]) -> anyhow::Result<(alloc::Layout, Vec<usize>)> {
+        // We need the first element to be the discriminent of the variant. The discriminent is
+        // the index in the variant vector, thus we need a usize.
+        let init = (alloc::Layout::new::<usize>(), vec![0]);
+
+        // We fold the body into the layout.
+        let fold = |(body, mut offsets): (alloc::Layout, Vec<usize>), elem: VVRTType| {
+            let (body, next) = body.extend(match elem {
+                // Only the length. Because of the alignement, the next two bytes are always
+                // allocated for the content of the string, so we don't waste too much space.
+                VVRTType::String => alloc::Layout::new::<i32>(),
+
+                // For numbers we directly use an any.
+                VVRTType::Number => alloc::Layout::new::<VVRTAny>(),
+
+                _ => bail!("invalid type `{elem}` in variant"),
+            })?;
+            offsets.push(next);
+            Ok::<_, anyhow::Error>((body, offsets))
+        };
+
+        body.iter()
+            .copied()
+            .try_fold(init, fold)
+            .map(|(layout, offsets)| (layout.pad_to_align(), offsets))
+    }
+
+    /// Get the layout for the current value. In this layout we have the space for the content of
+    /// the string.
+    fn get_value_layout(&self) -> alloc::Layout {
+        let VariantDescription { arguments, layout, offsets, .. } = unsafe { &VARIANTS[self.discriminent()] };
+
+        match (arguments.last(), offsets.last()) {
+            (Some(VVRTType::String), Some(offset)) => {
+                // Get the memory layout for where we store the string.
+                let str_len = unsafe { *(self.0.as_ptr().add(*offset) as *const i32) as usize };
+                let str_layout = alloc::Layout::array::<u8>(str_len);
+
+                // Get the total layout. Just assert we are not doing things too big.
+                let layout = layout.extend(str_layout.expect("too big")).expect("too big").0;
+
+                // Because of C things, we must pad the layout up to the align value, which should
+                // be the same as `*mut u64`.
+                layout.pad_to_align()
+            }
+
+            _ => *layout,
+        }
+    }
+
+    /// Like [VVRTVariant_get] but for [VVRTNumber]. Return default on type error.
+    fn get_number(&self, idx: i32) -> VVRTNumber {
+        match unsafe { self.offset_of_index(idx) } {
+            (ptr, VVRTType::Number) => Into::into(unsafe { *(ptr as *const VVRTAny) }),
+            _ => Default::default(),
+        }
+    }
+
+    /// Like [self::VVRTVariant_get] but for the string in the variant. Return default on type
+    /// error. Here we don't have an index because we know that we have only one string in the
+    /// variant and that it's at the last index.
+    fn get_string(&self) -> &str {
+        match unsafe { self.offset_of_index(get_variant_argument_count_by_discriminent(self.discriminent()) - 1) } {
+            (ptr, VVRTType::String) => unsafe {
+                str::from_utf8_unchecked(slice::from_raw_parts(
+                    ptr.byte_add(size_of::<i32>()),
+                    *(ptr as *const i32) as usize,
+                ))
+            },
+            _ => Default::default(),
+        }
+    }
+}
+
+impl AsRef<[u8]> for VVRTVariant {
+    #[inline]
+    fn as_ref(&self) -> &[u8] {
+        unsafe { slice::from_raw_parts(self.0.as_ptr() as *const u8, self.get_value_layout().size()) }
+    }
+}
+
+impl Eq for VVRTVariant {}
+impl PartialEq for VVRTVariant {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        (self.discriminent() == other.discriminent()) && (self.as_ref() == other.as_ref())
+    }
+}
+
+/// Module used to defined functions to be exported to the JIT.
+#[allow(clippy::missing_safety_doc)]
+#[vvs_procmacro::vvrt_bridge(VVRTVariant)]
+mod ffi {
+    use std::borrow::Cow;
+
+    #[no_mangle]
+    unsafe extern "C" fn new(
+        ast_ptr: *const u8,
+        ast_len: i32,
+        var_ptr: *const u8,
+        var_len: i32,
+        str_ptr: *const u8,
+        str_len: i32,
+    ) -> VVRTVariant {
+        let ast = str::from_utf8_unchecked(slice::from_raw_parts(ast_ptr, ast_len as usize));
+        let var = str::from_utf8_unchecked(slice::from_raw_parts(var_ptr, var_len as usize));
+        let (discriminent, layout, offsets, types) = get_variant_desc_by_name(ast, var);
+
+        // Get the layout for the variant to allocate.
+        let (layout, string_offset) = match types {
+            [body @ .., _] if body.iter().copied().any(|t| t == VVRTType::String) => {
+                unreachable!("strings must be in last position in variants")
+            }
+            [.., VVRTType::String] => {
+                let (layout, next) = layout
+                    .extend(alloc::Layout::array::<u8>(str_len as usize).expect("too big"))
+                    .expect("too big");
+                (layout.pad_to_align(), Some(next))
+            }
+            _ => (*layout, None),
+        };
+
+        // Create and initialize the variant. Pay attention that the unit of the pointer is a byte
+        // (a u8...)
+        let ptr: NonNull<u8> = NonNull::new(alloc::alloc(layout)).expect("out of memory");
+        *transmute::<*mut u8, *mut usize>(ptr.as_ptr()) = discriminent;
+        slice::from_raw_parts_mut(ptr.as_ptr(), layout.size())
+            .iter_mut()
+            .skip(size_of::<usize>())
+            .for_each(|byte: &mut u8| std::ptr::write(byte, 0));
+
+        // If we have a string we must copy it.
+        if let Some(string_offset) = string_offset {
+            std::ptr::write(
+                ptr.as_ptr().byte_add(*offsets.last().expect("invalid variant")) as *mut i32,
+                str_len,
+            );
+            std::ptr::copy_nonoverlapping(str_ptr, ptr.as_ptr().byte_add(string_offset), str_len as usize);
+        }
+
+        // Ok, we can return the thing.
+        VVRTVariant(NonNull::new_unchecked(ptr.as_ptr() as *mut _))
+    }
+
+    /// Create a new string from the content of the variant.
+    #[no_mangle]
+    unsafe extern "C" fn to_string(var: VVRTVariant) -> VVRTString {
+        let discriminent = var.discriminent();
+        let VariantDescription { ast_name, variant_name, arguments, .. } = &VARIANTS[discriminent];
+        let mut pretty = format!("#({ast_name}.{variant_name}");
+
+        arguments.iter().copied().enumerate().for_each(|(idx, arg)| {
+            pretty.push_str(if idx == 0 { " " } else { ", " });
+            pretty.push_str(&match arg {
+                VVRTType::Number => Cow::Owned(format!("{}", var.get_number(idx as i32))),
+                VVRTType::String => Cow::Borrowed(var.get_string()),
+                ty => unreachable!("invalid variant {ast_name}.{variant_name} at idx {idx}, got type: {ty}"),
+            });
+        });
+
+        pretty.push(')');
+        VVRTString::from_vec(pretty.into())
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn clone(this: VVRTVariant) -> VVRTVariant {
+        let layout = this.get_value_layout(); // Get the layout of the value, because we need to
+                                              // take into account the string part if any.
+        let ptr = NonNull::new(alloc::alloc(layout) as *mut u64).expect("out of memory");
+        std::ptr::copy_nonoverlapping(this.0.as_ptr() as *const u8, ptr.as_ptr() as *mut u8, layout.size());
+        VVRTVariant(ptr)
+    }
+
+    /// Like [self::VVRTVariant_get] but for the string in the variant. Return default on type
+    /// error. Here we don't have an index because we know that we have only one string in the
+    /// variant and that it's at the last index. The string is allocated here and the codegen will
+    /// need to insert a drop call...
+    #[no_mangle]
+    pub unsafe extern "C" fn get_string(this: VVRTVariant) -> VVRTString {
+        Into::into(VVRTString::from_bytes(this.get_string().as_bytes()))
+    }
+
+    /// Like [self::VVRTVariant_get] but for i32. Return default on type error.
+    #[no_mangle]
+    pub unsafe extern "C" fn get_i32(this: VVRTVariant, idx: i32) -> i32 {
+        this.get_number(idx).into()
+    }
+
+    /// Like [self::VVRTVariant_get] but for f32. Return default on type error.
+    #[no_mangle]
+    pub unsafe extern "C" fn get_f32(this: VVRTVariant, idx: i32) -> f32 {
+        this.get_number(idx).into()
+    }
+
+    /// Clone the result, may be freed by the user.
+    #[no_mangle]
+    pub unsafe extern "C" fn get(this: VVRTVariant, idx: i32) -> VVRTAny {
+        match this.offset_of_index(idx) {
+            // For numbers we use directly the any to store them. Because of the discriminent
+            // everything is already aligned in a good way.
+            (ptr, VVRTType::Number) => *(ptr as *const VVRTAny),
+
+            // We have a string, the first 4 bytes are the length of said string, the next things
+            // are the content of said string.
+            (ptr, VVRTType::String) => Into::into(VVRTString::from_bytes(slice::from_raw_parts(
+                ptr.byte_add(size_of::<i32>()),
+                *(ptr as *const i32) as usize,
+            ))),
+
+            _ => unreachable!("variant was not valid"),
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern "C" fn deep_clone(this: VVRTVariant) -> VVRTVariant {
+        VVRTVariant_clone(this)
+    }
+
+    /// Creates a new string!
+    #[no_mangle]
+    unsafe extern "C" fn get_variant_name(ptr: VVRTVariant) -> VVRTString {
+        VVRTString::from_bytes(VARIANTS[ptr.discriminent()].variant_name.as_bytes())
+    }
+
+    /// Creates a new string!
+    #[no_mangle]
+    unsafe extern "C" fn get_ast_name(ptr: VVRTVariant) -> VVRTString {
+        VVRTString::from_bytes(VARIANTS[ptr.discriminent()].ast_name.as_bytes())
+    }
+
+    #[no_mangle]
+    unsafe extern "C" fn drop(var @ VVRTVariant(ptr): VVRTVariant) {
+        alloc::dealloc(ptr.as_ptr() as *mut _, var.get_value_layout());
+    }
+
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn eq(this: VVRTVariant, other: VVRTVariant) -> bool { PartialEq::eq(&this, &other) }
+    #[rustfmt::skip] #[no_mangle] unsafe extern "C" fn ne(this: VVRTVariant, other: VVRTVariant) -> bool { PartialEq::ne(&this, &other) }
+}
diff --git a/src/Rust/vvs_runtime_types/src/vvll.rs b/src/Rust/vvs_runtime_types/src/vvll.rs
new file mode 100644
index 0000000000000000000000000000000000000000..cbaaeed35e945b95d92cd7dc7d398fb06730550a
--- /dev/null
+++ b/src/Rust/vvs_runtime_types/src/vvll.rs
@@ -0,0 +1,101 @@
+#![allow(non_snake_case)]
+
+use hashbrown::{HashMap, HashSet};
+use std::{ffi::CString, sync::OnceLock};
+use vvs_lang::ast::ASTType;
+use vvs_llvm::*;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct ManageFunctions {
+    pub clone: &'static str,
+    pub drop: &'static str,
+}
+
+/// Store properties about a type and the associated functions.
+#[derive(Debug, Default)]
+pub struct Properties {
+    /// The drop/clone functions if present for this type. If [None], then we don't need to manage
+    /// the memory for this type. The drop function takes the thing, and the clone a const pointer
+    /// to the thing.
+    pub manage: Option<ManageFunctions>,
+
+    /// The function to call to check the equality. Must take only two arguments, const pointers to
+    /// the same type, and return a boolean. This function doesn't consume the arguments.
+    pub equality: Option<&'static str>,
+
+    /// The function to call to get the length of the item. Must take one argument, a const pointer
+    /// to the thing. This function doesn't consume the arguments. This function returns an
+    /// integer.
+    pub len: Option<&'static str>,
+
+    /// Stores all the methods with some informations about them.
+    pub methods: HashMap<&'static str, (unsafe extern "C" fn(), LLVMTypeRef, ASTType)>,
+}
+
+/// Trait used to give to the codegen the layout and functions associated with a type that is
+/// present in the runtime and that must be handled in the codegen.
+pub trait LLVMExported {
+    /// Get the layout of the type.
+    ///
+    /// # Safety
+    /// The [LLVMContextRef] must be valid.
+    unsafe fn llvm_type(_: LLVMContextRef) -> LLVMTypeRef;
+
+    /// Get all the functions associated with a type and some properties of this type. For example,
+    /// integers and floating numbers can be copied without having to clone them, but strings, any,
+    /// table, sequences, etc, must be cloned and dropped when no longer used.
+    ///
+    /// # Safety
+    /// The [LLVMContextRef] must be valid.
+    unsafe fn llvm_properties(_: LLVMContextRef) -> Properties;
+}
+
+/// Tells if a type is managed or not.
+///
+/// # Safety
+/// - All the managed types must have been exported into at least one module
+/// - This function is not thread-safe
+pub unsafe fn LLVMTypeIsManaged(ty: LLVMTypeRef) -> bool {
+    managed_types().contains(&ty)
+}
+
+unsafe fn managed_types() -> &'static mut HashSet<LLVMTypeRef> {
+    static mut MANAGED_TYPES: OnceLock<HashSet<LLVMTypeRef>> = OnceLock::new();
+    MANAGED_TYPES.get_or_init(HashSet::new);
+    MANAGED_TYPES.get_mut().expect(" should have been created")
+}
+
+/// Register all the exported types and functions into a module.
+///
+/// # Safety
+/// - The [LLVMContextRef] must be valid
+/// - the [LLVMModuleRef] must be valid
+/// - This function is not thread-safe
+pub unsafe fn LLVMRegisterExportedIntoModule(
+    c: LLVMContextRef,
+    m: LLVMModuleRef,
+) -> Vec<(&'static str, ASTType, LLVMValueRef, LLVMTypeRef)> {
+    let mut ret = Vec::default();
+
+    macro_rules! handle {
+        ($ty: ty, $($tys: ty),+ $(,)?) => {
+            handle!($ty);
+            handle!($($tys),+);
+        };
+        ($ty: ty) => {
+            let Properties { manage, equality: _, len: _, methods } = <$ty>::llvm_properties(c);
+            if manage.is_some() {
+                managed_types().insert(<$ty>::llvm_type(c));
+            }
+            for (name, (_, ty, asttype)) in methods {
+                let cstr = CString::new(name).expect("invalid function name");
+                let function = unsafe { LLVMAddFunction(m, cstr.as_ptr(), ty) };
+                ret.push((name, asttype, function, ty));
+            }
+        };
+    }
+
+    use crate::types::*;
+    handle!(VVRTType, VVRTAny, VVRTSeq, VVRTString, VVRTTable);
+    ret
+}
diff --git a/src/Rust/vvs_utils/Cargo.toml b/src/Rust/vvs_utils/Cargo.toml
index b27c119fe14e52d7e91e34e794d9dcaf1f1cb131..557198c6ce57cb1bd2fa64533ce398ca6936b602 100644
--- a/src/Rust/vvs_utils/Cargo.toml
+++ b/src/Rust/vvs_utils/Cargo.toml
@@ -1,12 +1,13 @@
 [package]
-name = "vvs_utils"
+name              = "vvs_utils"
+description       = "Utility crate for VVS"
 version.workspace = true
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
-description = "Utility crate for VVS"
 
 [dependencies]
 thiserror.workspace = true
-serde.workspace = true
-log.workspace = true
+anyhow.workspace    = true
+serde.workspace     = true
+log.workspace       = true
diff --git a/src/Rust/vvs_utils/src/angles.rs b/src/Rust/vvs_utils/src/angles.rs
index 53424bca73c2b29483bc6bcba1bb6678334b9af6..4a2ecc70577ca6497cc7f7d3ac17c9c0e0e8e6de 100644
--- a/src/Rust/vvs_utils/src/angles.rs
+++ b/src/Rust/vvs_utils/src/angles.rs
@@ -1,17 +1,21 @@
 use core::{f32::consts::PI as PI_32, f64::consts::PI as PI_64};
 
+#[inline]
 pub fn f64_randians_clamp(rad: f64) -> f64 {
     rad % (2.0 * PI_64)
 }
 
+#[inline]
 pub fn f64_degres_clamp(rad: f64) -> f64 {
     rad % 360.0
 }
 
+#[inline]
 pub fn f32_randians_clamp(rad: f32) -> f32 {
     rad % (2.0 * PI_32)
 }
 
+#[inline]
 pub fn f32_degres_clamp(rad: f32) -> f32 {
     rad % 360.0
 }
diff --git a/src/Rust/vvs_utils/src/assert.rs b/src/Rust/vvs_utils/src/assert.rs
index 2f34f04cd47f83eac41e4a55613b88aec263c874..13f886d0f8aced3f8038d62ce07043c36f45962e 100644
--- a/src/Rust/vvs_utils/src/assert.rs
+++ b/src/Rust/vvs_utils/src/assert.rs
@@ -33,7 +33,7 @@ macro_rules! assert_ok {
     ($x: expr) => {
         match $x {
             Ok(x) => x,
-            Err(e) => panic!("failed '{}' with error '{e:?}'", stringify!($x)),
+            Err(e) => panic!("failed '{}' with error '{e}'", stringify!($x)),
         }
     };
 }
diff --git a/src/Rust/vvs_utils/src/conds.rs b/src/Rust/vvs_utils/src/conds.rs
index 98256e0c5a19d2e900f59dc6b6f3c1c68f9c8969..715b6cc216f259a116a1e0e911e3a42712ffd8e1 100644
--- a/src/Rust/vvs_utils/src/conds.rs
+++ b/src/Rust/vvs_utils/src/conds.rs
@@ -9,10 +9,12 @@ macro_rules! either {
     }};
 }
 
+#[inline]
 pub fn f64_epsilon_eq(a: f64, b: f64) -> bool {
     (a - b).abs() <= 10E-10
 }
 
+#[inline]
 pub fn f32_epsilon_eq(a: f32, b: f32) -> bool {
     (a - b).abs() <= 10E-7
 }
diff --git a/src/Rust/vvs_utils/src/file/lock.rs b/src/Rust/vvs_utils/src/file/lock.rs
index 4dfbdf3336da6f8e88110a5b8f065b8b21a8ed14..9d17fdc9729c443e0af46dad42b24242129ddf47 100644
--- a/src/Rust/vvs_utils/src/file/lock.rs
+++ b/src/Rust/vvs_utils/src/file/lock.rs
@@ -28,6 +28,7 @@ pub type LockResult<T> = Result<T, LockError>;
 pub struct LockFile(File);
 
 impl LockFile {
+    #[inline]
     fn handle_xdg_error(err: XDGError) -> LockError {
         match err {
             XDGError::ConfigIO(_, _, err) => Self::handle_io_error(err),
@@ -35,6 +36,7 @@ impl LockFile {
         }
     }
 
+    #[inline]
     fn handle_io_error(err: IoError) -> LockError {
         match err.kind() {
             std::io::ErrorKind::AlreadyExists => LockError::AlreadyLocked,
@@ -42,6 +44,7 @@ impl LockFile {
         }
     }
 
+    #[inline]
     fn create(app: impl AsRef<str>, file: String) -> LockResult<Self> {
         match XDGFolder::RuntimeDir
             .find(app, file, XDGFindBehaviour::NonExistingOnly)
@@ -58,6 +61,7 @@ impl LockFile {
     }
 
     /// Create a lock file for another file.
+    #[inline]
     pub fn for_file(app: impl AsRef<str>, path: impl AsRef<Path>) -> LockResult<Self> {
         let mut s = DefaultHasher::new();
         path.as_ref().hash(&mut s);
@@ -65,6 +69,7 @@ impl LockFile {
     }
 
     /// Create a lock file for an hashable ressource.
+    #[inline]
     pub fn for_resource(app: impl AsRef<str>, rsc: impl Hash) -> LockResult<Self> {
         let mut s = DefaultHasher::new();
         rsc.hash(&mut s);
@@ -72,12 +77,14 @@ impl LockFile {
     }
 
     /// Create a lock file for an ID.
+    #[inline]
     pub fn for_id(app: impl AsRef<str>, id: u64) -> LockResult<Self> {
         Self::create(app, format!("{id:#X}.id.lock"))
     }
 }
 
 impl Drop for LockFile {
+    #[inline]
     fn drop(&mut self) {
         todo!("drop {:?}", self.0)
     }
diff --git a/src/Rust/vvs_utils/src/file/temp.rs b/src/Rust/vvs_utils/src/file/temp.rs
index 63537b834459f8c4d73abea7ae3b9ff02d762563..0a5dcd0ba2bab984dff3724dc7b9662c2595e679 100644
--- a/src/Rust/vvs_utils/src/file/temp.rs
+++ b/src/Rust/vvs_utils/src/file/temp.rs
@@ -32,18 +32,21 @@ pub struct TempFile(File);
 impl Deref for TempFile {
     type Target = File;
 
+    #[inline]
     fn deref(&self) -> &Self::Target {
         &self.0
     }
 }
 
 impl DerefMut for TempFile {
+    #[inline]
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.0
     }
 }
 
 impl TempFile {
+    #[inline]
     fn handle_xdg_error(err: XDGError) -> TempError {
         match err {
             XDGError::ConfigIO(_, _, err) => Self::handle_io_error(err),
@@ -51,6 +54,7 @@ impl TempFile {
         }
     }
 
+    #[inline]
     fn handle_io_error(err: IoError) -> TempError {
         match err.kind() {
             std::io::ErrorKind::AlreadyExists => TempError::Duplicate,
@@ -59,6 +63,7 @@ impl TempFile {
     }
 
     #[cfg(unix)]
+    #[inline]
     fn create(app: impl AsRef<str>, file: impl AsRef<str>) -> TempResult<PathBuf> {
         let list = XDGFolder::RuntimeDir
             .find(app, file, XDGFindBehaviour::NonExistingOnly)
@@ -83,10 +88,7 @@ impl TempFile {
         if !folder.is_dir() {
             Err(IoError::new(
                 IoErrorKind::NotFound,
-                format!(
-                    "folder doesn't exists or is not a directory: {}",
-                    folder.to_string_lossy()
-                ),
+                format!("folder doesn't exists or is not a directory: {}", folder.to_string_lossy()),
             )
             .into())
         } else {
@@ -98,6 +100,7 @@ impl TempFile {
     /// Create a new temporary file somewhere. Note that the creation pattern is predictible and
     /// not secure in any way. Moreover we depend on the fact that PID from dead processes are not
     /// reused between reboots, and that temp folder are cleared at reboots...
+    #[inline]
     pub fn new(app: impl AsRef<str>) -> TempResult<Self> {
         let (pid, rand) = (std::process::id(), crate::rand());
         let file = OpenOptions::new()
diff --git a/src/Rust/vvs_utils/src/lib.rs b/src/Rust/vvs_utils/src/lib.rs
index 9a351c5015a64094cb67947f3d13930905882e7f..f7dc73802457f9a185e9eb49983d53e3718c36b2 100644
--- a/src/Rust/vvs_utils/src/lib.rs
+++ b/src/Rust/vvs_utils/src/lib.rs
@@ -8,7 +8,6 @@ pub mod file;
 pub mod xdg;
 
 pub use angles::*;
-pub use assert::*;
 pub use conds::*;
 pub use minmax::*;
 pub use rand::*;
diff --git a/src/Rust/vvs_utils/src/rand.rs b/src/Rust/vvs_utils/src/rand.rs
index 9833b2e57278368b56f5a114d89c2864f8da35c7..8b10f723b7d7e0081548de65cf78d61c98cbeccb 100644
--- a/src/Rust/vvs_utils/src/rand.rs
+++ b/src/Rust/vvs_utils/src/rand.rs
@@ -11,10 +11,11 @@ struct MersenneTwister {
 
 thread_local! {
     /// We do our things here.
-    static MERSENNE: OnceLock<RefCell<MersenneTwister>> = OnceLock::new();
+    static MERSENNE: OnceLock<RefCell<MersenneTwister>> = const { OnceLock::new() };
 }
 
 /// Get the seed for the thread.
+#[inline]
 fn get_seed() -> u64 {
     f64::to_bits(
         std::time::SystemTime::now()
@@ -43,6 +44,7 @@ impl MersenneTwister {
     const LOWER_MASK: u64 = (1_u64 << MersenneTwister::R).overflowing_sub(1_u64).0;
     const UPPER_MASK: u64 = !Self::LOWER_MASK;
 
+    #[inline]
     fn twist(&mut self) {
         (0..Self::N).for_each(|i| {
             let index = i as usize;
@@ -54,6 +56,7 @@ impl MersenneTwister {
         self.index = 0;
     }
 
+    #[inline]
     fn extract_number(&mut self) -> u64 {
         if self.index >= Self::N as usize {
             self.twist();
@@ -69,6 +72,7 @@ impl MersenneTwister {
 }
 
 /// Get next pseudo random number with our homebrew mersenne twister.
+#[inline]
 pub fn rand() -> u64 {
     MERSENNE.with(|mt| {
         mt.get_or_init(|| {
diff --git a/src/Rust/vvs_utils/src/xdg/config.rs b/src/Rust/vvs_utils/src/xdg/config.rs
index 499ba276644a8d59e198bb3740efd6640d6c4f87..49339f5fcd76828effa3369f9c0d906be9132b5a 100644
--- a/src/Rust/vvs_utils/src/xdg/config.rs
+++ b/src/Rust/vvs_utils/src/xdg/config.rs
@@ -140,6 +140,7 @@ where
     const DEFAULT_FILE: &'static str = "config";
 
     /// Create a new [XDGConfig] helper.
+    #[inline]
     pub fn new(
         app: &'a str,
         deserialize: impl Fn(String) -> Result<Format, Box<dyn std::error::Error>> + 'static,
@@ -154,6 +155,7 @@ where
     }
 
     /// Change the file to resolve.
+    #[inline]
     pub fn file(&mut self, file: &'a str) -> &mut Self {
         self.file = Some(file);
         self
@@ -161,6 +163,7 @@ where
 
     /// Get the name of the config file that we will try to read. Returns the default if not set by
     /// the user.
+    #[inline]
     pub fn get_file(&self) -> &str {
         match self.file.as_ref() {
             Some(file) => file,
@@ -169,11 +172,13 @@ where
     }
 
     /// Search all config files in all locations...
+    #[inline]
     fn search_files(&self) -> Result<MaybeFolderList, XDGError> {
         XDGFolder::ConfigDirs.find(self.app, self.get_file(), XDGFindBehaviour::ExistingOnly)
     }
 
     /// Prepare config folders.
+    #[inline]
     pub fn prepare_folder(&self) -> impl IntoIterator<Item = <MaybeFolderList as IntoIterator>::Item> {
         XDGFolder::ConfigDirs.prepare_folder()
     }
@@ -186,10 +191,7 @@ where
     /// Try to read the config file and deserialize it.
     pub fn try_read(&self) -> Result<Format, XDGError> {
         let Some(file) = self.search_files()?.into_first() else {
-            return Err(XDGError::ConfigNotFound(
-                self.app.to_string(),
-                self.get_file().to_string(),
-            ));
+            return Err(XDGError::ConfigNotFound(self.app.to_string(), self.get_file().to_string()));
         };
         let file = std::fs::read_to_string(file)
             .map_err(|err| XDGError::ConfigIO(self.app.to_string(), self.get_file().to_string(), err))?;
@@ -205,6 +207,7 @@ where
     /// Try to read the config file and deserialize it. If an error is encountred at any point, log
     /// it and return the provided default. If needed the default value is written on the disk,
     /// note that this operation may fail silently.
+    #[inline]
     pub fn read_or(
         &self,
         serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
@@ -219,6 +222,7 @@ where
     /// Try to read the config file and deserialize it. If an error is encountred at any point, log
     /// it and return the provided default. If needed the default value is written on the disk,
     /// note that this operation may fail silently.
+    #[inline]
     pub fn read_or_else(
         &self,
         serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
@@ -248,16 +252,12 @@ where
             )
         };
 
-        match std::fs::create_dir_all(path.parent().ok_or(XDGError::ConfigFileHasNoParentFolder(
-            self.app.to_string(),
-            self.get_file().to_string(),
-        ))?) {
+        match std::fs::create_dir_all(
+            path.parent()
+                .ok_or(XDGError::ConfigFileHasNoParentFolder(self.app.to_string(), self.get_file().to_string()))?,
+        ) {
             Err(err) if !matches!(err.kind(), std::io::ErrorKind::AlreadyExists) => {
-                return Err(XDGError::ConfigIO(
-                    self.app.to_string(),
-                    self.get_file().to_string(),
-                    err,
-                ))
+                return Err(XDGError::ConfigIO(self.app.to_string(), self.get_file().to_string(), err))
             }
             _ => {}
         }
@@ -270,6 +270,7 @@ where
 
     /// Same as [XDGConfig::write] but log any error and fail silently, returning the value that
     /// was attempted to be written to disk.
+    #[inline]
     fn write_silent(
         &self,
         serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
@@ -289,6 +290,7 @@ where
     /// Try to read the config file and deserialize it. If an error is encountred at any point, log
     /// it and return the default. If needed the default value is written on the disk, note that
     /// this operation may fail silently.
+    #[inline]
     pub fn read_or_default(
         &self,
         serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
@@ -310,6 +312,7 @@ where
     /// When trying to read or write the default, we write the file with the same logic as the
     /// [XDGConfigFirst] variant, we add this function to reduce the code to write for the write
     /// logic...
+    #[inline]
     fn to_config_first(&self) -> XDGConfig<Format, XDGConfigFirst> {
         XDGConfig::<Format, XDGConfigFirst> {
             app: self.app,
@@ -325,6 +328,7 @@ where
     /// the merge was silent. If no config file where found this is an error. All the files are
     /// merged, this operation can't fail, implementations must fail silently or have sane defaults
     /// and prefer files with higher priority.
+    #[inline]
     pub fn try_read(&self) -> Result<Format, XDGError> {
         Merged::try_read(self)
     }
@@ -339,6 +343,7 @@ where
     /// log it and return the provided default if the merge was not silent, skip the file if it was
     /// silent. If needed the default value is written on the disk, note that this operation may
     /// fail silently.
+    #[inline]
     pub fn read_or(
         &self,
         serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
@@ -354,6 +359,7 @@ where
     /// log it and return the provided default if the merge was not silent, skip the file if it was
     /// silent. If needed the default value is written on the disk, note that this operation may
     /// fail silently.
+    #[inline]
     pub fn read_or_else(
         &self,
         serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
@@ -375,6 +381,7 @@ where
     /// log it and return the provided default if the merge was not silent, skip the file if it was
     /// silent. If needed the default value is written on the disk, note that this operation may
     /// fail silently.
+    #[inline]
     pub fn read_or_default(
         &self,
         serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
diff --git a/src/Rust/vvs_utils/src/xdg/folders.rs b/src/Rust/vvs_utils/src/xdg/folders.rs
index 4552b2c6ec1009c180c1fdc609e9166bfb809ba6..3933ddb5bcd836f5ee8854e8e45cfa4cfc02e9ca 100644
--- a/src/Rust/vvs_utils/src/xdg/folders.rs
+++ b/src/Rust/vvs_utils/src/xdg/folders.rs
@@ -109,9 +109,11 @@ impl XDGFolder {
     pub fn get_folder(&self) -> MaybeFolderList {
         #[cfg(unix)]
         mod variables {
+            #[inline]
             pub fn data_dirs(_: impl AsRef<std::path::Path>) -> super::MaybeFolderList {
                 super::MaybeFolderList::from_iter(["/usr/local/share", "/usr/share"])
             }
+            #[inline]
             pub fn config_dirs(_: impl AsRef<std::path::Path>) -> super::MaybeFolderList {
                 super::MaybeFolderList::from("/etc/xdg")
             }
@@ -232,27 +234,26 @@ impl XDGFolder {
 
             // The list that we want is empty, or all lists are empty, returns nothing -> should it
             // really be an error?
-            _ => Err(XDGError::NotFound(
-                *self,
-                app.as_ref().to_string(),
-                file.as_ref().to_string(),
-            )),
+            _ => Err(XDGError::NotFound(*self, app.as_ref().to_string(), file.as_ref().to_string())),
         }
     }
 
     /// Is this variable a folder list?
+    #[inline]
     pub fn is_list(&self) -> bool {
         use XDGFolder::*;
         matches!(self, DataDirs | ConfigDirs)
     }
 
     /// Get the env variable name associated with the folder or folder list.
+    #[inline]
     pub fn env_var_name(&self) -> &str {
         self.as_ref()
     }
 }
 
 impl AsRef<str> for XDGFolder {
+    #[inline]
     fn as_ref(&self) -> &str {
         match self {
             XDGFolder::DataHome => "XDG_DATA_HOME",
@@ -268,6 +269,7 @@ impl AsRef<str> for XDGFolder {
 }
 
 impl std::fmt::Display for XDGFolder {
+    #[inline]
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "${}", self.as_ref())
     }
diff --git a/src/Rust/vvs_utils/src/xdg/mod.rs b/src/Rust/vvs_utils/src/xdg/mod.rs
index bc1e04b27c284e24c064a55742a0f34d74008cec..54ca264481720bfadb95815200a862ca46c014a5 100644
--- a/src/Rust/vvs_utils/src/xdg/mod.rs
+++ b/src/Rust/vvs_utils/src/xdg/mod.rs
@@ -19,6 +19,7 @@ use thiserror::Error;
 
 /// Get the user's home folder. Panics if the env variable was not found or it can't be
 /// canonicalized.
+#[inline]
 pub fn home_folder() -> PathBuf {
     PathBuf::from(std::env::var("HOME").expect("failed to get the $HOME env variable"))
         .canonicalize()
diff --git a/src/Rust/vvs_utils/src/xdg/paths.rs b/src/Rust/vvs_utils/src/xdg/paths.rs
index a99eb333ec554708af14902c402072946d0e26e8..7eec911df4add0c483c191671f06ac92f02fc4bb 100644
--- a/src/Rust/vvs_utils/src/xdg/paths.rs
+++ b/src/Rust/vvs_utils/src/xdg/paths.rs
@@ -28,16 +28,19 @@ pub struct MaybeFolderListIterator<'a> {
 
 impl MaybeFolderList {
     /// Is there no folder?
+    #[inline]
     pub fn is_none(&self) -> bool {
         matches!(self, MaybeFolderList::Empty)
     }
 
     /// Is there folders?
+    #[inline]
     pub fn is_some(&self) -> bool {
         !self.is_none()
     }
 
     /// Get the first folder, or the last folder. If no folder is present just returns [None].
+    #[inline]
     pub fn first(&self) -> Option<&Path> {
         use MaybeFolderList::*;
         match self {
@@ -97,6 +100,7 @@ impl MaybeFolderList {
     /// Get the first folder, or the last folder. If no folder is present just returns [None]. The
     /// difference from the [MaybeFolderList::first] function is that this function consumes the
     /// [MaybeFolderList].
+    #[inline]
     pub fn into_first(self) -> Option<PathBuf> {
         use MaybeFolderList::*;
         match self {
@@ -106,6 +110,7 @@ impl MaybeFolderList {
     }
 
     /// Get an iterator over the contained folders.
+    #[inline]
     pub fn iter(&self) -> MaybeFolderListIterator {
         let (next, list): (_, &[_]) = match self {
             MaybeFolderList::Empty => (None, &[]),
@@ -116,6 +121,7 @@ impl MaybeFolderList {
     }
 
     /// Create a list of folders from a description string and a separator.
+    #[inline]
     pub(super) fn from_str_list(list: &str, separator: char) -> Self {
         let mut folders = list.split(separator);
         match folders.next() {
@@ -157,6 +163,7 @@ impl<'a, S> From<S> for MaybeFolderList
 where
     S: AsRef<str> + 'a,
 {
+    #[inline]
     fn from(value: S) -> Self {
         MaybeFolderList::Folder(PathBuf::from(value.as_ref()))
     }
@@ -166,14 +173,14 @@ impl<'a, P> FromIterator<P> for MaybeFolderList
 where
     P: AsRef<Path> + 'a,
 {
+    #[inline]
     fn from_iter<T: IntoIterator<Item = P>>(iter: T) -> Self {
         let mut folders = iter.into_iter();
         match folders.next() {
             None => MaybeFolderList::Empty,
-            Some(first) => MaybeFolderList::Many(
-                first.as_ref().to_path_buf(),
-                folders.map(|p| p.as_ref().to_path_buf()).collect(),
-            ),
+            Some(first) => {
+                MaybeFolderList::Many(first.as_ref().to_path_buf(), folders.map(|p| p.as_ref().to_path_buf()).collect())
+            }
         }
     }
 }
@@ -182,6 +189,7 @@ impl IntoIterator for MaybeFolderList {
     type Item = PathBuf;
     type IntoIter = <Vec<PathBuf> as IntoIterator>::IntoIter;
 
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         match self {
             MaybeFolderList::Empty => vec![].into_iter(),
@@ -197,6 +205,7 @@ impl IntoIterator for MaybeFolderList {
 impl<'a> Iterator for MaybeFolderListIterator<'a> {
     type Item = &'a PathBuf;
 
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         let next = self.next?;
         match self.list.split_first() {
diff --git a/utils/lua/sample-spec.module b/utils/lua/sample-spec.module
deleted file mode 100644
index b007d97a926900929530b3043f19f42f83e31958..0000000000000000000000000000000000000000
--- a/utils/lua/sample-spec.module
+++ /dev/null
@@ -1,54 +0,0 @@
---- Declaration
-
-local custom_opt = DeclareOption { option1 = false }
-local time_opt   = DeclareOption { preTime = -900, postTime = 300, }
-local color_opt  = DeclareOption { color1 = Vivy:newColor("#314159") }
-
-local module = DeclareModule {
-    name        = "sample-spec",
-    description = "Sample script used for the specification proposition",
-    author      = "Vivy",
-    revision    = "rev-1254",
-    imports     = { "utils" },
-    options     = { custom_opt, time_opt, color_opt },
-    functions   = {
-        DeclareFunction { "tripleCopySyl" },
-        DeclareFunction { "printFoo" },
-        ImportFunction  { "utils", "prettyPrint" },
-    },
-    jobs = {
-        DeclareJob { "set_retime", options = { time_opt } },
-        DeclareJob { "demultiply_syllabes" },
-        ImportJob  { "utils", "color_after_read_3", "utils", options = { color_opt } }
-    }
-}
-
---- Implementation
-
-local utils       = module:import { "utils" }
-local prettyPrint = module:import { "utils", "prettyPrint" }
-
-local tripleCopySyl = module:export { "tripleCopySyl", function (syl)
-    return { syl:copy(), syl:copy(), syl:copy() }
-end }
-
-module:export { "printFoo", function () prettyPrint ("Bar") end }
-
-module:export { "retime_lines", LINE, function (opt, line)
-    line.start  = line.start + opt.preTime
-    line.finish = line.start + opt.postTime
-    if line.start  <= Vivy:start()  then line.start  = Vivy:start()  end
-    if line.finish >= Vivy:finish() then line.finish = Vivy:finish() end
-    return line
-end }
-
-module:export { "create_syllabes", SYLLABE, function (opt, syl)
-    local newSyls     = tripleCopySyl(syl)
-    newSyls[1].start  = syl.line.start
-    newSyls[1].finish = syl.start
-    newSyls[3].finish = syl.line.finish
-    newSyls[3].start  = syl.finish
-    return newSyls
-end }
-
--- vim: ft=lua
diff --git a/utils/lua/simple.module b/utils/lua/simple.module
deleted file mode 100644
index 85439d803a08c8f063282d4428d5aa0a61577e04..0000000000000000000000000000000000000000
--- a/utils/lua/simple.module
+++ /dev/null
@@ -1,48 +0,0 @@
---- Declaration
-
-local custom_opt = DeclareOption { option1 = false }
-local time_opt   = DeclareOption { preTime = -900, postTime = 300, }
-local color_opt  = DeclareOption { color1 = Vivy:newColor("#314159") }
-
-local module = DeclareModule {
-    name        = "sample-spec",
-    description = "Sample script used for the specification proposition",
-    author      = "Vivy",
-    revision    = "rev-1254",
-    options     = { custom_opt, time_opt, color_opt },
-    functions   = {
-        DeclareFunction { "tripleCopySyl" },
-        DeclareFunction { "printFoo" },
-    },
-    jobs = {
-        DeclareJob { "set_retime", options = { time_opt } },
-        DeclareJob { "create_syllabes" },
-    }
-}
-
---- Implementation
-
-local tripleCopySyl = module:export { "tripleCopySyl", function (syl)
-    return { syl:copy(), syl:copy(), syl:copy() }
-end }
-
-module:export { "printFoo", function () prettyPrint ("Bar") end }
-
-module:export { "set_retime", LINE, function (opt, line)
-    line.start  = line.start + opt.preTime
-    line.finish = line.start + opt.postTime
-    if line.start  <= Vivy:start()  then line.start  = Vivy:start()  end
-    if line.finish >= Vivy:finish() then line.finish = Vivy:finish() end
-    return line
-end }
-
-module:export { "create_syllabes", SYLLABE, function (opt, syl)
-    local newSyls     = tripleCopySyl(syl)
-    newSyls[1].start  = syl.line.start
-    newSyls[1].finish = syl.start
-    newSyls[3].finish = syl.line.finish
-    newSyls[3].start  = syl.finish
-    return newSyls
-end }
-
--- vim: ft=lua
diff --git a/utils/samples/hwlock.rs b/utils/samples/hwlock.rs
new file mode 100644
index 0000000000000000000000000000000000000000..316a98cc87cd2e6aa5cf0666b2ee22b920ab32dd
--- /dev/null
+++ b/utils/samples/hwlock.rs
@@ -0,0 +1,64 @@
+#!/usr/bin/env cargo script
+
+//! ```cargo
+//! [package]
+//! name = "topo"
+//! version = "0.1.0"
+//! edition = "2021"
+//!
+//! [dependencies]
+//! hwlocality = { version = "1.0.0-alpha.1", features = ["hwloc-latest", "vendored"] }
+//! anyhow = "*"
+//! ```
+
+use anyhow::{anyhow, Result};
+use hwlocality::{
+    cpu::binding::CpuBindingFlags,
+    object::types::ObjectType,
+    topology::support::{DiscoverySupport, FeatureSupport},
+    Topology,
+};
+use std::os::unix::thread::JoinHandleExt;
+
+fn main() -> Result<()> {
+    let topology = Topology::new()?;
+    if !topology.supports(FeatureSupport::discovery, DiscoverySupport::pu_count) {
+        println!("This example needs accurate reporting of PU objects");
+        return Ok(());
+    }
+    let Some(cpu_support) = topology.feature_support().cpu_binding() else {
+        println!("This example requires CPU binding support");
+        return Ok(());
+    };
+    if !(cpu_support.get_thread() && cpu_support.set_thread()) {
+        println!("This example needs support for querying and setting thread CPU bindings");
+        return Ok(());
+    }
+
+    let core_depth = topology.depth_or_below_for_type(ObjectType::Core)?;
+    let mut handles: Vec<_> = Vec::new();
+
+    for (idx, core) in topology.objects_at_depth(core_depth).enumerate() {
+        let handle = std::thread::spawn(move || -> Result<()> {
+            // Worker thread
+            std::thread::sleep(std::time::Duration::from_secs_f64(3.0));
+            Ok(())
+        });
+        let tid = handle.as_pthread_t();
+
+        let mut bind_to = core
+            .cpuset()
+            .ok_or_else(|| anyhow!("CPU cores should have CpuSets"))?
+            .clone_target();
+        bind_to.singlify();
+
+        let before = topology.thread_cpu_binding(tid, CpuBindingFlags::empty())?;
+        topology.bind_thread_cpu(tid, &bind_to, CpuBindingFlags::empty())?;
+        let after = topology.thread_cpu_binding(tid, CpuBindingFlags::empty())?;
+
+        println!("- Thread {idx} binding: {before:?} -> {after:?}");
+        handles.push(handle);
+    }
+    Ok(())
+}
+
diff --git a/utils/scripts/build-libvivy.bash b/utils/scripts/build-libvivy.bash
new file mode 100755
index 0000000000000000000000000000000000000000..f6c321c12b6af81bb217836721512bfa89248ab9
--- /dev/null
+++ b/utils/scripts/build-libvivy.bash
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+set -e
+exec 5>&1
+cd "$(git rev-parse --show-toplevel)"
+
+FILES=$(cargo build --manifest-path src/Rust/Cargo.toml --workspace ${2} --message-format=json \
+    | jq -r 'select( .reason == "compiler-artifact" and ((.target.kind | index("staticlib")) or (.target.kind | index("bin"))) ) .filenames[0]' \
+    | tee >(cat - >&5))
+
+for FILE in ${FILES}; do
+    FILE=${FILE}
+    cp -u ${FILE} "${1}/$(basename ${FILE})"
+done