From 38635308d2cfb43c9451b7b88b4c1e68ee6e65de Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Mon, 18 May 2026 07:04:44 +0200 Subject: [PATCH 001/154] WIP: Parser From 0f5f061361a0109161254abc7eeddbe78ce3e592 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Mon, 18 May 2026 23:50:42 +0200 Subject: [PATCH 002/154] update --- src/ast/nodes.hpp | 36 +++++++ src/grammar/ast.hpp | 1 + src/grammar/lexer.hpp | 36 +++++++ src/grammar/lexer.re | 130 +++++++++++++++++++++++ src/types/stack.hpp | 23 ++++ src/types/variant.hpp | 239 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 465 insertions(+) create mode 100644 src/ast/nodes.hpp create mode 100644 src/grammar/ast.hpp create mode 100644 src/grammar/lexer.hpp create mode 100644 src/grammar/lexer.re create mode 100644 src/types/stack.hpp create mode 100644 src/types/variant.hpp diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp new file mode 100644 index 00000000..02fa90c0 --- /dev/null +++ b/src/ast/nodes.hpp @@ -0,0 +1,36 @@ +// nodes.hpp +#pragma once +#include +#include +#include +#include + +namespace ast { + +// 1. Forward declare a concrete struct for recursive pointers +struct Node; +using NodePtr = std::unique_ptr; + +// 2. Concrete AST types +struct IntNode { int val; }; +struct AddNode { NodePtr lhs, rhs; }; +struct CallNode { std::string name; std::vector args; }; + +// 3. Variant alias (different name to avoid clash) +using NodeVariant = std::variant; + +// 4. Wrapper that ties the pointer and variant together +struct Node { + NodeVariant data; + template explicit Node(T&& t) : data(std::forward(t)) {} +}; + +struct Evaluator { + int operator()(const IntNode& n) const { return n.val; } + int operator()(const AddNode& n) const { + return std::visit(*this, n.lhs->data) + std::visit(*this, n.rhs->data); + } + int operator()(const CallNode& n) const { return 0; } +}; + +} // namespace ast diff --git a/src/grammar/ast.hpp b/src/grammar/ast.hpp new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/grammar/ast.hpp @@ -0,0 +1 @@ + diff --git a/src/grammar/lexer.hpp b/src/grammar/lexer.hpp new file mode 100644 index 00000000..b2f96e5b --- /dev/null +++ b/src/grammar/lexer.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include + +namespace zane { +class Lexer { +public: + explicit Lexer(std::string source) + : source_(std::move(source)) {} + + int next(void* semanticValue); + + const char*& cursor() { + return cursor_; + } + + const char*& marker() { + return marker_; + } + + const char* limit() const { + return source_.data() + source_.size(); + } + + void reset() { + cursor_ = source_.data(); + marker_ = source_.data(); + } + +private: + std::string source_; + const char* cursor_ = nullptr; + const char* marker_ = nullptr; +}; + +} // namespace zane diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re new file mode 100644 index 00000000..a1794988 --- /dev/null +++ b/src/grammar/lexer.re @@ -0,0 +1,130 @@ +#include +#include +#include + +#include "lexer.hpp" +#include "parser.hpp" + +static char* dupRange(const char* begin, const char* end) { + const std::size_t size = static_cast(end - begin); + char* text = static_cast(std::malloc(size + 1)); + if (text == nullptr) { + throw std::bad_alloc(); + } + std::memcpy(text, begin, size); + text[size] = '\0'; + return text; +} + +int zane::Lexer::next(void* semanticValue) { + YYSTYPE* semantic = static_cast(semanticValue); + const char*& YYCURSOR = cursor(); + const char*& YYMARKER = marker(); + const char* YYLIMIT = limit(); + + for (;;) { + if (YYCURSOR >= YYLIMIT) { + return 0; + } + + const char* token = YYCURSOR; + + /**!re2c + re2c:define:YYCTYPE = char; + re2c:define:YYCURSOR = YYCURSOR; + re2c:define:YYLIMIT = YYLIMIT; + re2c:define:YYMARKER = YYMARKER; + re2c:yyfill:enable = 0; + + [ \t\r\n]+ { continue; } + "///" [^\n]* ("\n" "///" [^\n]*)* "\n"? { continue; } + "//" [^\n]* "\n"? { continue; } + + "package" { return PACKAGE; } + "import" { return IMPORT; } + "class" { return CLASS; } + "struct" { return STRUCT; } + "ref" { return REF; } + "implicit" { return IMPLICIT; } + "this" { return THIS; } + "mut" { return MUT; } + "if" { return IF; } + "elif" { return ELIF; } + "else" { return ELSE; } + "guard" { return GUARD; } + "loop" { return LOOP; } + "from" { return FROM; } + "to" { return TO; } + "return" { return RETURN; } + "abort" { return ABORT; } + "resolve" { return RESOLVE; } + "spawn" { return SPAWN; } + "init" { return INIT; } + "and" { return AND; } + "or" { return OR; } + "true" { return TRUE; } + "false" { return FALSE; } + + "=>" { return FAT_ARROW; } + "->" { return ARROW; } + "??" { return QQ; } + "==" { return EQEQ; } + "~=" { return NEQ; } + "<=" { return LE; } + ">=" { return GE; } + + "$" { return NAME_SEP; } + + "(" { return '('; } + ")" { return ')'; } + "{" { return '{'; } + "}" { return '}'; } + "[" { return '['; } + "]" { return ']'; } + "," { return ','; } + ":" { return ':'; } + "!" { return '!'; } + "." { return '.'; } + "?" { return '?'; } + "=" { return '='; } + "+" { return '+'; } + "-" { return '-'; } + "*" { return '*'; } + "/" { return '/'; } + "~" { return '~'; } + "<" { return '<'; } + ">" { return '>'; } + "|" { return '|'; } + "@" { return '@'; } + + "'" [A-Za-z_] [A-Za-z_0-9]* { + semantic->text = dupRange(token, YYCURSOR); + return TYPE_PARAM; + } + "\"" ([^"\\\n] | "\\" .)* "\"" { + semantic->text = dupRange(token + 1, YYCURSOR - 1); + return STRING; + } + [0-9]+ "." [0-9]+ { + semantic->text = dupRange(token, YYCURSOR); + return FLOAT; + } + [0-9]+ { + semantic->text = dupRange(token, YYCURSOR); + return INT; + } + [A-Za-z_] [A-Za-z_0-9]* { + semantic->text = dupRange(token, YYCURSOR); + return NAME; + } + * { + std::cerr << "unexpected character: " << *token << '\n'; + return 0; + } + **/ + } +} + +int yylex(YYSTYPE* yylval, zane::Lexer* lexer) { + return lexer->next(yylval); +} diff --git a/src/types/stack.hpp b/src/types/stack.hpp new file mode 100644 index 00000000..62e2eb90 --- /dev/null +++ b/src/types/stack.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +template +class Stack { + std::vector stack; +public: + Stack() = default; + void push(T element) { stack.push_back(element); } + bool empty() const { return stack.empty(); } + T& top() { return stack.back(); } + T top() const { return stack.back(); } + T pop() { + if (stack.empty()) return {}; + auto value = stack.back(); + stack.pop_back(); + return value; + } + auto rbegin() { return stack.rbegin(); } + auto rend() { return stack.rend(); } + auto begin() { return stack.begin(); } + auto end() { return stack.end(); } +}; diff --git a/src/types/variant.hpp b/src/types/variant.hpp new file mode 100644 index 00000000..1108fd9d --- /dev/null +++ b/src/types/variant.hpp @@ -0,0 +1,239 @@ +#pragma once + +#include +#include +#include +#include + +// Helper for overloading lambdas +template +struct overloaded : Ts... { + using Ts::operator()...; +}; + +template +overloaded(Ts...) -> overloaded; + +// Helper function to load a variant at a specific index +template +void loadVariantAt(std::size_t idx, std::variant& var, Archive& ar) { + if constexpr (I < sizeof...(Types)) { + if (I == idx) { + std::variant_alternative_t> val; + ar(val); + var = std::move(val); + } else { + loadVariantAt(idx, var, ar); + } + } +} + +// Returns invoke_result_t if invocable, otherwise void. +// Used by match() to probe what return type each callback produces. +template +struct safe_invoke_result { using type = void; }; +template +struct safe_invoke_result>> { + using type = std::invoke_result_t; +}; + +// Walks a type list and picks the first non-void type, or Default if all are void. +// Lets match() find the real return type even when some alternatives are unhandled. +template +struct first_non_void_or { using type = Default; }; +template +struct first_non_void_or { + using type = std::conditional_t, T, + typename first_non_void_or::type>; +}; + +template +struct Variant { + std::variant value; + + Variant() = default; + Variant(std::variant value) + : value(std::move(value)) {} + + template, Types> || ...)>> + Variant(T&& val) : value(std::forward(val)) {} + + template, Types> || ...)>> + Variant& operator=(T&& val) { + value = std::forward(val); + return *this; + } + + // visit: accepts a single callable (use match for multiple lambdas) + template + decltype(auto) visit(Callback&& callback) { + return std::visit(std::forward(callback), value); + } + + template + decltype(auto) visit(Callback&& callback) const { + return std::visit(std::forward(callback), value); + } + + template + bool is() const { + return (std::holds_alternative(value) || ...); + } + + template + T* getIf() { + return std::get_if(&value); + } + + template + const T* getIf() const { + return std::get_if(&value); + } + + // match: handles a subset of types; unhandled alternatives return R{} (or void). + // The catch-all return type is deduced from the provided callbacks so that + // returning a value (e.g. std::string) works without an explicit default case. + template + decltype(auto) match(Callbacks&&... callbacks) { + using Visitor = overloaded...>; + using R = typename first_non_void_or::type... + >::type; + + if constexpr (std::is_void_v) { + return std::visit( + overloaded{ std::forward(callbacks)..., [](auto&&) {} }, + value + ); + } else { + return std::visit( + overloaded{ std::forward(callbacks)..., [](auto&&) -> R { return R{}; } }, + value + ); + } + } + + template + decltype(auto) match(Callbacks&&... callbacks) const { + using Visitor = overloaded...>; + using R = typename first_non_void_or::type... + >::type; + + if constexpr (std::is_void_v) { + return std::visit( + overloaded{ std::forward(callbacks)..., [](auto&&) {} }, + value + ); + } else { + return std::visit( + overloaded{ std::forward(callbacks)..., [](auto&&) -> R { return R{}; } }, + value + ); + } + } + + template + void save(Archive& ar) const { + ar(value.index()); + std::visit([&ar](const auto& v) { ar(v); }, value); + } + + template + void load(Archive& ar) { + std::size_t idx; + ar(idx); + loadVariantAt<0>(idx, value, ar); + } + + bool operator==(const Variant&) const = default; +}; + +template class Wrapper, typename... Types> +struct WrappingVariant { + std::variant...> value; + + WrappingVariant() = default; + WrappingVariant(std::variant...> value) + : value(std::move(value)) {} + + template, Wrapper> || ...)>> + WrappingVariant(T&& val) : value(std::forward(val)) {} + + template, Wrapper> || ...)>> + WrappingVariant& operator=(T&& val) { + value = std::forward(val); + return *this; + } + + // visit: accepts a single callable (use match for multiple lambdas) + template + decltype(auto) visit(Callback&& callback) { + return std::visit(std::forward(callback), value); + } + + template + decltype(auto) visit(Callback&& callback) const { + return std::visit(std::forward(callback), value); + } + + // match: handles a subset of types; unhandled alternatives return R{} (or void). + template + decltype(auto) match(Callbacks&&... callbacks) { + using Visitor = overloaded...>; + using R = typename first_non_void_or&>::type... + >::type; + + if constexpr (std::is_void_v) { + return std::visit( + overloaded{ std::forward(callbacks)..., [](auto&&) {} }, + value + ); + } else { + return std::visit( + overloaded{ std::forward(callbacks)..., [](auto&&) -> R { return R{}; } }, + value + ); + } + } + + template + decltype(auto) match(Callbacks&&... callbacks) const { + using Visitor = overloaded...>; + using R = typename first_non_void_or&>::type... + >::type; + + if constexpr (std::is_void_v) { + return std::visit( + overloaded{ std::forward(callbacks)..., [](auto&&) {} }, + value + ); + } else { + return std::visit( + overloaded{ std::forward(callbacks)..., [](auto&&) -> R { return R{}; } }, + value + ); + } + } + + template + void save(Archive& ar) const { + ar(value.index()); + std::visit([&ar](const auto& v) { ar(v); }, value); + } + + template + void load(Archive& ar) { + std::size_t idx; + ar(idx); + loadVariantAt<0>(idx, value, ar); + } + + bool operator==(const WrappingVariant&) const = default; +}; From ce6948e0b0ae41465cced89f51c8060d7da74daa Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 20 May 2026 17:46:40 +0200 Subject: [PATCH 003/154] update --- meson.build | 29 +++ prompt.txt | 426 ++++++++++++++++++++++++++++++++++++++++++ src/ast/fwd.hpp | 6 + src/ast/logic.hpp | 16 ++ src/ast/node_list.def | 2 + src/ast/nodes.hpp | 39 +--- src/grammar/ast.hpp | 1 - src/grammar/lexer.hpp | 36 ---- src/grammar/lexer.re | 158 +++------------- src/grammar/parser.y | 40 ++++ src/main.cpp | 22 +++ 11 files changed, 577 insertions(+), 198 deletions(-) create mode 100644 meson.build create mode 100644 prompt.txt create mode 100644 src/ast/fwd.hpp create mode 100644 src/ast/logic.hpp create mode 100644 src/ast/node_list.def delete mode 100644 src/grammar/ast.hpp delete mode 100644 src/grammar/lexer.hpp create mode 100644 src/grammar/parser.y create mode 100644 src/main.cpp diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..238d6e30 --- /dev/null +++ b/meson.build @@ -0,0 +1,29 @@ +project('zane', 'cpp', + version: '0.1.0', + default_options: ['cpp_std=c++20', 'warning_level=3']) + +re2c = find_program('re2c', required: true) +bison = find_program('bison', required: true) + +parser_gen = custom_target('parser', + input: 'src/grammar/parser.y', + output: ['parser.cc', 'parser.tab.h'], + command: [bison, '-d', '-o', '@OUTPUT0@', '--defines=@OUTPUT1@', '@INPUT@'], + build_by_default: true, +) + +lexer_gen = custom_target('lexer', + input: 'src/grammar/lexer.re', + output: 'lexer.cc', + command: [re2c, '-o', '@OUTPUT@', '@INPUT@'], + build_by_default: true, + depends: [parser_gen], +) + +executable('zane', + 'src/main.cpp', + parser_gen[0], + lexer_gen, + include_directories: include_directories('src', '.'), + cpp_args: ['-Wall', '-Wextra'], +) diff --git a/prompt.txt b/prompt.txt new file mode 100644 index 00000000..146a88e8 --- /dev/null +++ b/prompt.txt @@ -0,0 +1,426 @@ +can you please fix this issue? but first explore the codebase. + manuel on  ~/projects/zane/compiler essential/parser +# devbox shell +Starting a devbox shell... +Welcome to devbox! + manuel on  ~/projects/zane/compiler essential/parser +# rm -rf build +CXX=clang++ CC=clang meson setup build --reconfigure +meson compile -C build +./build/zane "1 + 2" +The Meson build system +Version: 1.10.2 +Source dir: /home/manuel/projects/zane/compiler +Build dir: /home/manuel/projects/zane/compiler/build +Build type: native build +Project name: zane +Project version: 0.1.0 +C++ compiler for the host machine: clang++ (clang 21.1.8 "clang version 21.1.8") +C++ linker for the host machine: clang++ ld.bfd 2.46 +Host machine cpu family: x86_64 +Host machine cpu: x86_64 +Program re2c found: YES (/home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/re2c) +Program bison found: YES (/home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/bison) +Build targets in project: 3 + +Found ninja-1.13.1 at /home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/ninja +INFO: autodetecting backend as ninja +INFO: calculating backend command to run: /home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/ni +nja -C /home/manuel/projects/zane/compiler/build +ninja: Entering directory `/home/manuel/projects/zane/compiler/build' +[3/6] Compiling C++ object zane.p/src_main.cpp.o +FAILED: [code=1] zane.p/src_main.cpp.o +clang++ -Izane.p -I. -I.. -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra + -Wpedantic -std=c++20 -O0 -g -Wall -Wextra -MD -MQ zane.p/src_main.cpp.o -MF zane.p/src_main.cpp.o.d -o zane.p/ +src_main.cpp.o -c ../src/main.cpp +In file included from ../src/main.cpp:1: +In file included from ../src/ast/logic.hpp:2: +In file included from ../src/ast/nodes.hpp:2: +In file included from ../src/ast/fwd.hpp:2: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/memory:65: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/bits/memoryfwd.h +:50: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l +inux-gnu/bits/c++config.h:727: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l +inux-gnu/bits/os_defines.h:39: +/nix/store/fbbw928argckfii0j322346ihmllg7a7-glibc-2.42-61-dev/include/features.h:435:4: warning: _FORTIFY_SOURCE + requires compiling with optimization (-O) [-W#warnings] + 435 | # warning _FORTIFY_SOURCE requires compiling with optimization (-O) + | ^ +In file included from ../src/main.cpp:1: +In file included from ../src/ast/logic.hpp:2: +In file included from ../src/ast/nodes.hpp:6: +../src/ast/node_list.def:1:13: error: expected member name or ';' after declaration specifiers + 1 | X(IntNode, { int val; }) + | ^ +../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' + 5 | #define X(Name, Body) struct Name { Body }; + | ^ +In file included from ../src/main.cpp:1: +In file included from ../src/ast/logic.hpp:2: +In file included from ../src/ast/nodes.hpp:6: +../src/ast/node_list.def:2:13: error: expected member name or ';' after declaration specifiers + 2 | X(AddNode, { NodePtr lhs; NodePtr rhs; }) + | ^ +../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' + 5 | #define X(Name, Body) struct Name { Body }; + | ^ +In file included from ../src/main.cpp:1: +In file included from ../src/ast/logic.hpp:3: +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:246:13: error: field has incom +plete type 'void' + 246 | _Type _M_storage; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:429:30: note: in instantiation + of template class 'std::__detail::__variant::_Uninitialized' requested here + 429 | _Uninitialized<_First> _M_first; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requested here + 430 | _Variadic_union<__trivially_destructible, _Rest...> _M_rest; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requested here +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requeste +d here +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:511:41: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requested here + 511 | _Variadic_union _M_u; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:576:30: note: (skipping 2 cont +exts in backtrace; use -ftemplate-backtrace-limit=0 to see all) + 576 | struct _Copy_ctor_base : _Variant_storage_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:651:32: note: in instantiation + of template class 'std::__detail::__variant::_Move_ctor_base' requested here + 651 | struct _Copy_assign_base : _Move_ctor_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:703:32: note: in instantiation + of template class 'std::__detail::__variant::_Copy_assign_base' requested here + 703 | struct _Move_assign_base : _Copy_assign_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:757:28: note: in instantiation + of template class 'std::__detail::__variant::_Move_assign_base' requested here + 757 | struct _Variant_base : _Move_assign_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1426:15: note: in instantiatio +n of template class 'std::__detail::__variant::_Variant_base' +requested here + 1426 | : private __detail::__variant::_Variant_base<_Types...>, + | ^ +../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here + 15 | NodeVariant data; + | ^ +In file included from ../src/main.cpp:1: +In file included from ../src/ast/logic.hpp:3: +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1441:23: error: static asserti +on failed due to requirement 'std::is_object_v': variant alternatives must be non-array object types + 1441 | static_assert(((std::is_object_v<_Types> && !is_array_v<_Types>) && ...), + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here + 15 | NodeVariant data; + | ^ +../src/main.cpp:17:16: error: no matching constructor for initialization of 'yy::Parser' + 17 | yy::Parser parser; + | ^ +parser.tab.h:422:6: note: candidate constructor not viable: requires 1 argument, but 0 were provided + 422 | Parser (const Parser &) = delete; + | ^ ~~~~~~~~~~~~~~~ +parser.tab.h:417:6: note: candidate constructor not viable: requires 3 arguments, but 0 were provided + 417 | Parser (const char*& cursor_yyarg, const char*& marker_yyarg, const char* limit_yyarg); + | ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +../src/main.cpp:18:28: error: too many arguments to function call, expected 0, have 3 + 18 | int res = parser.parse(cursor, marker, limit); + | ~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~ +parser.tab.h:433:17: note: 'parse' declared here + 433 | virtual int parse (); + | ^ +1 warning and 6 errors generated. +[4/6] Compiling C++ object zane.p/meson-generated_.._parser.cc.o +FAILED: [code=1] zane.p/meson-generated_.._parser.cc.o +clang++ -Izane.p -I. -I.. -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra + -Wpedantic -std=c++20 -O0 -g -Wall -Wextra -MD -MQ zane.p/meson-generated_.._parser.cc.o -MF zane.p/meson-gener +ated_.._parser.cc.o.d -o zane.p/meson-generated_.._parser.cc.o -c parser.cc +In file included from parser.cc:41: +In file included from ../src/grammar/parser.y:9: +In file included from ../src/ast/logic.hpp:2: +In file included from ../src/ast/nodes.hpp:2: +In file included from ../src/ast/fwd.hpp:2: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/memory:65: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/bits/memoryfwd.h +:50: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l +inux-gnu/bits/c++config.h:727: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l +inux-gnu/bits/os_defines.h:39: +/nix/store/fbbw928argckfii0j322346ihmllg7a7-glibc-2.42-61-dev/include/features.h:435:4: warning: _FORTIFY_SOURCE + requires compiling with optimization (-O) [-W#warnings] + 435 | # warning _FORTIFY_SOURCE requires compiling with optimization (-O) + | ^ +In file included from parser.cc:41: +In file included from ../src/grammar/parser.y:9: +In file included from ../src/ast/logic.hpp:2: +In file included from ../src/ast/nodes.hpp:6: +../src/ast/node_list.def:1:13: error: expected member name or ';' after declaration specifiers + 1 | X(IntNode, { int val; }) + | ^ +../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' + 5 | #define X(Name, Body) struct Name { Body }; + | ^ +In file included from parser.cc:41: +In file included from ../src/grammar/parser.y:9: +In file included from ../src/ast/logic.hpp:2: +In file included from ../src/ast/nodes.hpp:6: +../src/ast/node_list.def:2:13: error: expected member name or ';' after declaration specifiers + 2 | X(AddNode, { NodePtr lhs; NodePtr rhs; }) + | ^ +../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' + 5 | #define X(Name, Body) struct Name { Body }; + | ^ +In file included from parser.cc:41: +In file included from ../src/grammar/parser.y:9: +In file included from ../src/ast/logic.hpp:3: +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:246:13: error: field has incom +plete type 'void' + 246 | _Type _M_storage; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:429:30: note: in instantiation + of template class 'std::__detail::__variant::_Uninitialized' requested here + 429 | _Uninitialized<_First> _M_first; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requested here + 430 | _Variadic_union<__trivially_destructible, _Rest...> _M_rest; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requested here +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requeste +d here +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:511:41: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requested here + 511 | _Variadic_union _M_u; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:576:30: note: (skipping 2 cont +exts in backtrace; use -ftemplate-backtrace-limit=0 to see all) + 576 | struct _Copy_ctor_base : _Variant_storage_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:651:32: note: in instantiation + of template class 'std::__detail::__variant::_Move_ctor_base' requested here + 651 | struct _Copy_assign_base : _Move_ctor_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:703:32: note: in instantiation + of template class 'std::__detail::__variant::_Copy_assign_base' requested here + 703 | struct _Move_assign_base : _Copy_assign_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:757:28: note: in instantiation + of template class 'std::__detail::__variant::_Move_assign_base' requested here + 757 | struct _Variant_base : _Move_assign_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1426:15: note: in instantiatio +n of template class 'std::__detail::__variant::_Variant_base' +requested here + 1426 | : private __detail::__variant::_Variant_base<_Types...>, + | ^ +../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here + 15 | NodeVariant data; + | ^ +In file included from parser.cc:41: +In file included from ../src/grammar/parser.y:9: +In file included from ../src/ast/logic.hpp:3: +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1441:23: error: static asserti +on failed due to requirement 'std::is_object_v': variant alternatives must be non-array object types + 1441 | static_assert(((std::is_object_v<_Types> && !is_array_v<_Types>) && ...), + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here + 15 | NodeVariant data; + | ^ +parser.cc:300:33: error: no member named 'state' in 'yy::Parser::stack_symbol_type' + 300 | : super_type (YY_MOVE (that.state), YY_MOVE (that.value), YY_MOVE (that.location)) + | ~~~~ ^ +parser.cc:300:55: error: no member named 'value' in 'yy::Parser::stack_symbol_type' + 300 | : super_type (YY_MOVE (that.state), YY_MOVE (that.value), YY_MOVE (that.location)) + | ~~~~ ^ +parser.cc:300:77: error: no member named 'location' in 'yy::Parser::stack_symbol_type' + 300 | : super_type (YY_MOVE (that.state), YY_MOVE (that.value), YY_MOVE (that.location)) + | ~~~~ ^ +parser.cc:300:7: error: type 'super_type' (aka 'basic_symbol') is not a direct or virtual base of 'yy: +:Parser::stack_symbol_type' + 300 | : super_type (YY_MOVE (that.state), YY_MOVE (that.value), YY_MOVE (that.location)) + | ^~~~~~~~~~ +parser.cc:304:10: error: no member named 'state' in 'yy::Parser::stack_symbol_type' + 304 | that.state = empty_state; + | ~~~~ ^ +parser.cc:304:18: error: use of undeclared identifier 'empty_state'; did you mean 'by_state::empty_state'? + 304 | that.state = empty_state; + | ^~~~~~~~~~~ + | by_state::empty_state +parser.tab.h:594:14: note: 'by_state::empty_state' declared here + 594 | enum { empty_state = 0 }; + | ^ +parser.cc:309:36: error: no member named 'value' in 'yy::Parser::symbol_type' + 309 | : super_type (s, YY_MOVE (that.value), YY_MOVE (that.location)) + | ~~~~ ^ +parser.cc:309:58: error: no member named 'location' in 'yy::Parser::symbol_type' + 309 | : super_type (s, YY_MOVE (that.value), YY_MOVE (that.location)) + | ~~~~ ^ +parser.cc:309:7: error: type 'super_type' (aka 'basic_symbol') is not a direct or virtual base of 'yy: +:Parser::stack_symbol_type' + 309 | : super_type (s, YY_MOVE (that.value), YY_MOVE (that.location)) + | ^~~~~~~~~~ +parser.cc:312:10: error: no member named 'kind_' in 'yy::Parser::symbol_type' + 312 | that.kind_ = symbol_kind::S_YYEMPTY; + | ~~~~ ^ +parser.cc:487:55: error: no member named 'state' in 'yy::Parser::stack_symbol_type' + 487 | YYCDEBUG << "Entering state " << int (yystack_[0].state) << '\n'; + | ~~~~~~~~~~~ ^ +parser.cc:491:21: error: no member named 'state' in 'yy::Parser::stack_symbol_type' + 491 | if (yystack_[0].state == yyfinal_) + | ~~~~~~~~~~~ ^ +parser.cc:502:32: error: no member named 'state' in 'yy::Parser::stack_symbol_type' + 502 | yyn = yypact_[+yystack_[0].state]; + | ~~~~~~~~~~~ ^ +parser.cc:507:14: error: no member named 'empty' in 'yy::Parser::symbol_type' + 507 | if (yyla.empty ()) + | ~~~~ ^ +parser.cc:514:18: error: no member named 'kind_' in 'yy::Parser::symbol_type' + 514 | yyla.kind_ = yytranslate_ (yylex (&yyla.value, &yyla.location, cursor, marker, limit)); + | ~~~~ ^ +fatal error: too many errors emitted, stopping now [-ferror-limit=] +1 warning and 20 errors generated. +[5/6] Compiling C++ object zane.p/meson-generated_.._lexer.cc.o +FAILED: [code=1] zane.p/meson-generated_.._lexer.cc.o +clang++ -Izane.p -I. -I.. -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra + -Wpedantic -std=c++20 -O0 -g -Wall -Wextra -MD -MQ zane.p/meson-generated_.._lexer.cc.o -MF zane.p/meson-genera +ted_.._lexer.cc.o.d -o zane.p/meson-generated_.._lexer.cc.o -c lexer.cc +In file included from ../src/grammar/lexer.re:9: +In file included from ../src/ast/logic.hpp:2: +In file included from ../src/ast/nodes.hpp:2: +In file included from ../src/ast/fwd.hpp:2: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/memory:65: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/bits/memoryfwd.h +:50: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l +inux-gnu/bits/c++config.h:727: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l +inux-gnu/bits/os_defines.h:39: +/nix/store/fbbw928argckfii0j322346ihmllg7a7-glibc-2.42-61-dev/include/features.h:435:4: warning: _FORTIFY_SOURCE + requires compiling with optimization (-O) [-W#warnings] + 435 | # warning _FORTIFY_SOURCE requires compiling with optimization (-O) + | ^ +In file included from ../src/grammar/lexer.re:9: +In file included from ../src/ast/logic.hpp:2: +In file included from ../src/ast/nodes.hpp:6: +../src/ast/node_list.def:1:13: error: expected member name or ';' after declaration specifiers + 1 | X(IntNode, { int val; }) + | ^ +../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' + 5 | #define X(Name, Body) struct Name { Body }; + | ^ +In file included from ../src/grammar/lexer.re:9: +In file included from ../src/ast/logic.hpp:2: +In file included from ../src/ast/nodes.hpp:6: +../src/ast/node_list.def:2:13: error: expected member name or ';' after declaration specifiers + 2 | X(AddNode, { NodePtr lhs; NodePtr rhs; }) + | ^ +../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' + 5 | #define X(Name, Body) struct Name { Body }; + | ^ +In file included from ../src/grammar/lexer.re:9: +In file included from ../src/ast/logic.hpp:3: +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:246:13: error: field has incom +plete type 'void' + 246 | _Type _M_storage; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:429:30: note: in instantiation + of template class 'std::__detail::__variant::_Uninitialized' requested here + 429 | _Uninitialized<_First> _M_first; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requested here + 430 | _Variadic_union<__trivially_destructible, _Rest...> _M_rest; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requested here +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requeste +d here +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:511:41: note: in instantiation + of template class 'std::__detail::__variant::_Variadic_union' requested here + 511 | _Variadic_union _M_u; + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:576:30: note: (skipping 2 cont +exts in backtrace; use -ftemplate-backtrace-limit=0 to see all) + 576 | struct _Copy_ctor_base : _Variant_storage_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:651:32: note: in instantiation + of template class 'std::__detail::__variant::_Move_ctor_base' requested here + 651 | struct _Copy_assign_base : _Move_ctor_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:703:32: note: in instantiation + of template class 'std::__detail::__variant::_Copy_assign_base' requested here + 703 | struct _Move_assign_base : _Copy_assign_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:757:28: note: in instantiation + of template class 'std::__detail::__variant::_Move_assign_base' requested here + 757 | struct _Variant_base : _Move_assign_alias<_Types...> + | ^ +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1426:15: note: in instantiatio +n of template class 'std::__detail::__variant::_Variant_base' +requested here + 1426 | : private __detail::__variant::_Variant_base<_Types...>, + | ^ +../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here + 15 | NodeVariant data; + | ^ +In file included from ../src/grammar/lexer.re:9: +In file included from ../src/ast/logic.hpp:3: +/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1441:23: error: static asserti +on failed due to requirement 'std::is_object_v': variant alternatives must be non-array object types + 1441 | static_assert(((std::is_object_v<_Types> && !is_array_v<_Types>) && ...), + | ^~~~~~~~~~~~~~~~~~~~~~~~ +../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here + 15 | NodeVariant data; + | ^ +../src/grammar/lexer.re:25:36: error: excess elements in struct initializer + 25 | *yylval = ast::IntNode{std::stoi(toStr(start, cursor))}; + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +../src/grammar/lexer.re:25:21: error: no viable overloaded '=' + 25 | *yylval = ast::IntNode{std::stoi(toStr(start, cursor))}; + | ~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +../src/ast/logic.hpp:14:12: note: candidate function (the implicit copy assignment operator) not viable: no know +n conversion from 'ast::IntNode' to 'const Node' for 1st argument + 14 | struct Node { + | ^~~~ +../src/ast/logic.hpp:14:12: note: candidate function (the implicit move assignment operator) not viable: no know +n conversion from 'ast::IntNode' to 'Node' for 1st argument + 14 | struct Node { + | ^~~~ +../src/grammar/lexer.re:18:45: warning: unused parameter 'marker' [-Wunused-parameter] + 18 | const char*& cursor, const char*& marker, const char* limit) { + | ^ +2 warnings and 6 errors generated. +ninja: build stopped: subcommand failed. +bash: ./build/zane: No such file or directory + manuel on  ~/projects/zane/compiler essential/parser +# diff --git a/src/ast/fwd.hpp b/src/ast/fwd.hpp new file mode 100644 index 00000000..de9bfb80 --- /dev/null +++ b/src/ast/fwd.hpp @@ -0,0 +1,6 @@ +#pragma once +#include +namespace ast { + struct Node; + using NodePtr = std::unique_ptr; +} diff --git a/src/ast/logic.hpp b/src/ast/logic.hpp new file mode 100644 index 00000000..76709746 --- /dev/null +++ b/src/ast/logic.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "nodes.hpp" +#include +namespace ast { + #define X(Name, Body) Name, + using NodeVariant = std::variant< + #include "node_list.def" + std::monostate + >; + #undef X + + struct Node { + NodeVariant data; + template explicit Node(T&& t) : data(std::forward(t)) {} + }; +} diff --git a/src/ast/node_list.def b/src/ast/node_list.def new file mode 100644 index 00000000..2844faca --- /dev/null +++ b/src/ast/node_list.def @@ -0,0 +1,2 @@ +X(IntNode, { int val; }) +X(AddNode, { std::unique_ptr lhs; std::unique_ptr rhs; }) diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index 02fa90c0..dedba9e0 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -1,36 +1,7 @@ -// nodes.hpp #pragma once -#include -#include -#include -#include - +#include "fwd.hpp" namespace ast { - -// 1. Forward declare a concrete struct for recursive pointers -struct Node; -using NodePtr = std::unique_ptr; - -// 2. Concrete AST types -struct IntNode { int val; }; -struct AddNode { NodePtr lhs, rhs; }; -struct CallNode { std::string name; std::vector args; }; - -// 3. Variant alias (different name to avoid clash) -using NodeVariant = std::variant; - -// 4. Wrapper that ties the pointer and variant together -struct Node { - NodeVariant data; - template explicit Node(T&& t) : data(std::forward(t)) {} -}; - -struct Evaluator { - int operator()(const IntNode& n) const { return n.val; } - int operator()(const AddNode& n) const { - return std::visit(*this, n.lhs->data) + std::visit(*this, n.rhs->data); - } - int operator()(const CallNode& n) const { return 0; } -}; - -} // namespace ast + #define X(Name, Members) struct Name Members; + #include "node_list.def" + #undef X +} diff --git a/src/grammar/ast.hpp b/src/grammar/ast.hpp deleted file mode 100644 index 8b137891..00000000 --- a/src/grammar/ast.hpp +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/grammar/lexer.hpp b/src/grammar/lexer.hpp deleted file mode 100644 index b2f96e5b..00000000 --- a/src/grammar/lexer.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include - -namespace zane { -class Lexer { -public: - explicit Lexer(std::string source) - : source_(std::move(source)) {} - - int next(void* semanticValue); - - const char*& cursor() { - return cursor_; - } - - const char*& marker() { - return marker_; - } - - const char* limit() const { - return source_.data() + source_.size(); - } - - void reset() { - cursor_ = source_.data(); - marker_ = source_.data(); - } - -private: - std::string source_; - const char* cursor_ = nullptr; - const char* marker_ = nullptr; -}; - -} // namespace zane diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index a1794988..1eaf891c 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -1,130 +1,34 @@ -#include -#include -#include - -#include "lexer.hpp" -#include "parser.hpp" - -static char* dupRange(const char* begin, const char* end) { - const std::size_t size = static_cast(end - begin); - char* text = static_cast(std::malloc(size + 1)); - if (text == nullptr) { - throw std::bad_alloc(); - } - std::memcpy(text, begin, size); - text[size] = '\0'; - return text; -} - -int zane::Lexer::next(void* semanticValue) { - YYSTYPE* semantic = static_cast(semanticValue); - const char*& YYCURSOR = cursor(); - const char*& YYMARKER = marker(); - const char* YYLIMIT = limit(); - - for (;;) { - if (YYCURSOR >= YYLIMIT) { - return 0; - } - - const char* token = YYCURSOR; - - /**!re2c - re2c:define:YYCTYPE = char; - re2c:define:YYCURSOR = YYCURSOR; - re2c:define:YYLIMIT = YYLIMIT; - re2c:define:YYMARKER = YYMARKER; - re2c:yyfill:enable = 0; - - [ \t\r\n]+ { continue; } - "///" [^\n]* ("\n" "///" [^\n]*)* "\n"? { continue; } - "//" [^\n]* "\n"? { continue; } - - "package" { return PACKAGE; } - "import" { return IMPORT; } - "class" { return CLASS; } - "struct" { return STRUCT; } - "ref" { return REF; } - "implicit" { return IMPLICIT; } - "this" { return THIS; } - "mut" { return MUT; } - "if" { return IF; } - "elif" { return ELIF; } - "else" { return ELSE; } - "guard" { return GUARD; } - "loop" { return LOOP; } - "from" { return FROM; } - "to" { return TO; } - "return" { return RETURN; } - "abort" { return ABORT; } - "resolve" { return RESOLVE; } - "spawn" { return SPAWN; } - "init" { return INIT; } - "and" { return AND; } - "or" { return OR; } - "true" { return TRUE; } - "false" { return FALSE; } - - "=>" { return FAT_ARROW; } - "->" { return ARROW; } - "??" { return QQ; } - "==" { return EQEQ; } - "~=" { return NEQ; } - "<=" { return LE; } - ">=" { return GE; } - - "$" { return NAME_SEP; } - - "(" { return '('; } - ")" { return ')'; } - "{" { return '{'; } - "}" { return '}'; } - "[" { return '['; } - "]" { return ']'; } - "," { return ','; } - ":" { return ':'; } - "!" { return '!'; } - "." { return '.'; } - "?" { return '?'; } - "=" { return '='; } - "+" { return '+'; } - "-" { return '-'; } - "*" { return '*'; } - "/" { return '/'; } - "~" { return '~'; } - "<" { return '<'; } - ">" { return '>'; } - "|" { return '|'; } - "@" { return '@'; } - - "'" [A-Za-z_] [A-Za-z_0-9]* { - semantic->text = dupRange(token, YYCURSOR); - return TYPE_PARAM; - } - "\"" ([^"\\\n] | "\\" .)* "\"" { - semantic->text = dupRange(token + 1, YYCURSOR - 1); - return STRING; - } - [0-9]+ "." [0-9]+ { - semantic->text = dupRange(token, YYCURSOR); - return FLOAT; - } - [0-9]+ { - semantic->text = dupRange(token, YYCURSOR); - return INT; - } - [A-Za-z_] [A-Za-z_0-9]* { - semantic->text = dupRange(token, YYCURSOR); - return NAME; - } - * { - std::cerr << "unexpected character: " << *token << '\n'; - return 0; - } - **/ - } +/*!re2c +re2c:define:YYCTYPE = "unsigned char"; +re2c:define:YYCURSOR = cursor; +re2c:define:YYLIMIT = limit; +re2c:define:YYMARKER = marker; +re2c:yyfill:enable = 0; +*/ + +#include "ast/logic.hpp" +#include "parser.tab.h" +#include + +static std::string toStr(const char* b, const char* e) { + return std::string(b, static_cast(e - b)); } -int yylex(YYSTYPE* yylval, zane::Lexer* lexer) { - return lexer->next(yylval); +int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, + const char*& cursor, const char*& marker, const char* limit) { + for (;;) { + if (cursor >= limit) return yy::Parser::token::END; + const char* start = cursor; + /*!re2c + [ \t\n]+ { continue; } + [0-9]+ { + *yylval = ast::IntNode{std::stoi(toStr(start, cursor))}; + return yy::Parser::token::INT; + } + "+" { return yy::Parser::token::PLUS; } + "(" { return yy::Parser::token::LPAREN; } + ")" { return yy::Parser::token::RPAREN; } + * { return yy::Parser::token::ERROR; } + */ + } } diff --git a/src/grammar/parser.y b/src/grammar/parser.y new file mode 100644 index 00000000..1924a76c --- /dev/null +++ b/src/grammar/parser.y @@ -0,0 +1,40 @@ +%skeleton "lalr1.cc" +%require "3.8" + +%define api.parser.class { Parser } +%define api.namespace { yy } +%define api.value.type { ast::Node } + +%code requires { + #include "ast/logic.hpp" + #include + #include +} + +%locations +%param { const char*& cursor } +%param { const char*& marker } +%param { const char* limit } + +%token INT +%token PLUS LPAREN RPAREN END ERROR +%type expr +%left PLUS + +%% +start: expr END ; + +expr: INT { $$ = ast::IntNode{$1}; } + | expr PLUS expr { + $$ = ast::AddNode{ + std::make_unique(std::move($1)), + std::make_unique(std::move($3)) + }; + } + | LPAREN expr RPAREN { $$ = std::move($2); } + ; +%% + +void yy::Parser::error(const location& l, const std::string& m) { + std::cerr << "Error at " << l.begin.line << ":" << l.begin.column << ": " << m << "\n"; +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 00000000..9206a591 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,22 @@ +#include "ast/logic.hpp" +#include "parser.tab.h" +#include +#include + +int main(int argc, char** argv) { + if (argc < 2) { + std::cerr << "Usage: " << argv[0] << " \"\"\n"; + return 1; + } + + std::string src = argv[1]; + const char* cursor = src.data(); + const char* marker = cursor; + const char* limit = cursor + src.size(); + + yy::Parser parser; + int res = parser.parse(cursor, marker, limit); + + if (res == 0) std::cout << "✓ Parsed\n"; + return res; +} From e2c4707f938064f7d4242c0b3d4fb17aa21e9b61 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 21 May 2026 10:51:30 +0200 Subject: [PATCH 004/154] update --- prompt.txt | 426 ------------------------------------------- src/ast/logic.hpp | 64 +++++-- src/grammar/lexer.re | 4 +- src/grammar/parser.y | 21 ++- src/main.cpp | 28 ++- 5 files changed, 85 insertions(+), 458 deletions(-) delete mode 100644 prompt.txt diff --git a/prompt.txt b/prompt.txt deleted file mode 100644 index 146a88e8..00000000 --- a/prompt.txt +++ /dev/null @@ -1,426 +0,0 @@ -can you please fix this issue? but first explore the codebase. - manuel on  ~/projects/zane/compiler essential/parser -# devbox shell -Starting a devbox shell... -Welcome to devbox! - manuel on  ~/projects/zane/compiler essential/parser -# rm -rf build -CXX=clang++ CC=clang meson setup build --reconfigure -meson compile -C build -./build/zane "1 + 2" -The Meson build system -Version: 1.10.2 -Source dir: /home/manuel/projects/zane/compiler -Build dir: /home/manuel/projects/zane/compiler/build -Build type: native build -Project name: zane -Project version: 0.1.0 -C++ compiler for the host machine: clang++ (clang 21.1.8 "clang version 21.1.8") -C++ linker for the host machine: clang++ ld.bfd 2.46 -Host machine cpu family: x86_64 -Host machine cpu: x86_64 -Program re2c found: YES (/home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/re2c) -Program bison found: YES (/home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/bison) -Build targets in project: 3 - -Found ninja-1.13.1 at /home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/ninja -INFO: autodetecting backend as ninja -INFO: calculating backend command to run: /home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/ni -nja -C /home/manuel/projects/zane/compiler/build -ninja: Entering directory `/home/manuel/projects/zane/compiler/build' -[3/6] Compiling C++ object zane.p/src_main.cpp.o -FAILED: [code=1] zane.p/src_main.cpp.o -clang++ -Izane.p -I. -I.. -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra - -Wpedantic -std=c++20 -O0 -g -Wall -Wextra -MD -MQ zane.p/src_main.cpp.o -MF zane.p/src_main.cpp.o.d -o zane.p/ -src_main.cpp.o -c ../src/main.cpp -In file included from ../src/main.cpp:1: -In file included from ../src/ast/logic.hpp:2: -In file included from ../src/ast/nodes.hpp:2: -In file included from ../src/ast/fwd.hpp:2: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/memory:65: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/bits/memoryfwd.h -:50: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l -inux-gnu/bits/c++config.h:727: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l -inux-gnu/bits/os_defines.h:39: -/nix/store/fbbw928argckfii0j322346ihmllg7a7-glibc-2.42-61-dev/include/features.h:435:4: warning: _FORTIFY_SOURCE - requires compiling with optimization (-O) [-W#warnings] - 435 | # warning _FORTIFY_SOURCE requires compiling with optimization (-O) - | ^ -In file included from ../src/main.cpp:1: -In file included from ../src/ast/logic.hpp:2: -In file included from ../src/ast/nodes.hpp:6: -../src/ast/node_list.def:1:13: error: expected member name or ';' after declaration specifiers - 1 | X(IntNode, { int val; }) - | ^ -../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' - 5 | #define X(Name, Body) struct Name { Body }; - | ^ -In file included from ../src/main.cpp:1: -In file included from ../src/ast/logic.hpp:2: -In file included from ../src/ast/nodes.hpp:6: -../src/ast/node_list.def:2:13: error: expected member name or ';' after declaration specifiers - 2 | X(AddNode, { NodePtr lhs; NodePtr rhs; }) - | ^ -../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' - 5 | #define X(Name, Body) struct Name { Body }; - | ^ -In file included from ../src/main.cpp:1: -In file included from ../src/ast/logic.hpp:3: -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:246:13: error: field has incom -plete type 'void' - 246 | _Type _M_storage; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:429:30: note: in instantiation - of template class 'std::__detail::__variant::_Uninitialized' requested here - 429 | _Uninitialized<_First> _M_first; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requested here - 430 | _Variadic_union<__trivially_destructible, _Rest...> _M_rest; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requested here -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requeste -d here -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:511:41: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requested here - 511 | _Variadic_union _M_u; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:576:30: note: (skipping 2 cont -exts in backtrace; use -ftemplate-backtrace-limit=0 to see all) - 576 | struct _Copy_ctor_base : _Variant_storage_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:651:32: note: in instantiation - of template class 'std::__detail::__variant::_Move_ctor_base' requested here - 651 | struct _Copy_assign_base : _Move_ctor_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:703:32: note: in instantiation - of template class 'std::__detail::__variant::_Copy_assign_base' requested here - 703 | struct _Move_assign_base : _Copy_assign_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:757:28: note: in instantiation - of template class 'std::__detail::__variant::_Move_assign_base' requested here - 757 | struct _Variant_base : _Move_assign_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1426:15: note: in instantiatio -n of template class 'std::__detail::__variant::_Variant_base' -requested here - 1426 | : private __detail::__variant::_Variant_base<_Types...>, - | ^ -../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here - 15 | NodeVariant data; - | ^ -In file included from ../src/main.cpp:1: -In file included from ../src/ast/logic.hpp:3: -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1441:23: error: static asserti -on failed due to requirement 'std::is_object_v': variant alternatives must be non-array object types - 1441 | static_assert(((std::is_object_v<_Types> && !is_array_v<_Types>) && ...), - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here - 15 | NodeVariant data; - | ^ -../src/main.cpp:17:16: error: no matching constructor for initialization of 'yy::Parser' - 17 | yy::Parser parser; - | ^ -parser.tab.h:422:6: note: candidate constructor not viable: requires 1 argument, but 0 were provided - 422 | Parser (const Parser &) = delete; - | ^ ~~~~~~~~~~~~~~~ -parser.tab.h:417:6: note: candidate constructor not viable: requires 3 arguments, but 0 were provided - 417 | Parser (const char*& cursor_yyarg, const char*& marker_yyarg, const char* limit_yyarg); - | ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -../src/main.cpp:18:28: error: too many arguments to function call, expected 0, have 3 - 18 | int res = parser.parse(cursor, marker, limit); - | ~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~ -parser.tab.h:433:17: note: 'parse' declared here - 433 | virtual int parse (); - | ^ -1 warning and 6 errors generated. -[4/6] Compiling C++ object zane.p/meson-generated_.._parser.cc.o -FAILED: [code=1] zane.p/meson-generated_.._parser.cc.o -clang++ -Izane.p -I. -I.. -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra - -Wpedantic -std=c++20 -O0 -g -Wall -Wextra -MD -MQ zane.p/meson-generated_.._parser.cc.o -MF zane.p/meson-gener -ated_.._parser.cc.o.d -o zane.p/meson-generated_.._parser.cc.o -c parser.cc -In file included from parser.cc:41: -In file included from ../src/grammar/parser.y:9: -In file included from ../src/ast/logic.hpp:2: -In file included from ../src/ast/nodes.hpp:2: -In file included from ../src/ast/fwd.hpp:2: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/memory:65: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/bits/memoryfwd.h -:50: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l -inux-gnu/bits/c++config.h:727: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l -inux-gnu/bits/os_defines.h:39: -/nix/store/fbbw928argckfii0j322346ihmllg7a7-glibc-2.42-61-dev/include/features.h:435:4: warning: _FORTIFY_SOURCE - requires compiling with optimization (-O) [-W#warnings] - 435 | # warning _FORTIFY_SOURCE requires compiling with optimization (-O) - | ^ -In file included from parser.cc:41: -In file included from ../src/grammar/parser.y:9: -In file included from ../src/ast/logic.hpp:2: -In file included from ../src/ast/nodes.hpp:6: -../src/ast/node_list.def:1:13: error: expected member name or ';' after declaration specifiers - 1 | X(IntNode, { int val; }) - | ^ -../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' - 5 | #define X(Name, Body) struct Name { Body }; - | ^ -In file included from parser.cc:41: -In file included from ../src/grammar/parser.y:9: -In file included from ../src/ast/logic.hpp:2: -In file included from ../src/ast/nodes.hpp:6: -../src/ast/node_list.def:2:13: error: expected member name or ';' after declaration specifiers - 2 | X(AddNode, { NodePtr lhs; NodePtr rhs; }) - | ^ -../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' - 5 | #define X(Name, Body) struct Name { Body }; - | ^ -In file included from parser.cc:41: -In file included from ../src/grammar/parser.y:9: -In file included from ../src/ast/logic.hpp:3: -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:246:13: error: field has incom -plete type 'void' - 246 | _Type _M_storage; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:429:30: note: in instantiation - of template class 'std::__detail::__variant::_Uninitialized' requested here - 429 | _Uninitialized<_First> _M_first; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requested here - 430 | _Variadic_union<__trivially_destructible, _Rest...> _M_rest; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requested here -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requeste -d here -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:511:41: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requested here - 511 | _Variadic_union _M_u; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:576:30: note: (skipping 2 cont -exts in backtrace; use -ftemplate-backtrace-limit=0 to see all) - 576 | struct _Copy_ctor_base : _Variant_storage_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:651:32: note: in instantiation - of template class 'std::__detail::__variant::_Move_ctor_base' requested here - 651 | struct _Copy_assign_base : _Move_ctor_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:703:32: note: in instantiation - of template class 'std::__detail::__variant::_Copy_assign_base' requested here - 703 | struct _Move_assign_base : _Copy_assign_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:757:28: note: in instantiation - of template class 'std::__detail::__variant::_Move_assign_base' requested here - 757 | struct _Variant_base : _Move_assign_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1426:15: note: in instantiatio -n of template class 'std::__detail::__variant::_Variant_base' -requested here - 1426 | : private __detail::__variant::_Variant_base<_Types...>, - | ^ -../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here - 15 | NodeVariant data; - | ^ -In file included from parser.cc:41: -In file included from ../src/grammar/parser.y:9: -In file included from ../src/ast/logic.hpp:3: -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1441:23: error: static asserti -on failed due to requirement 'std::is_object_v': variant alternatives must be non-array object types - 1441 | static_assert(((std::is_object_v<_Types> && !is_array_v<_Types>) && ...), - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here - 15 | NodeVariant data; - | ^ -parser.cc:300:33: error: no member named 'state' in 'yy::Parser::stack_symbol_type' - 300 | : super_type (YY_MOVE (that.state), YY_MOVE (that.value), YY_MOVE (that.location)) - | ~~~~ ^ -parser.cc:300:55: error: no member named 'value' in 'yy::Parser::stack_symbol_type' - 300 | : super_type (YY_MOVE (that.state), YY_MOVE (that.value), YY_MOVE (that.location)) - | ~~~~ ^ -parser.cc:300:77: error: no member named 'location' in 'yy::Parser::stack_symbol_type' - 300 | : super_type (YY_MOVE (that.state), YY_MOVE (that.value), YY_MOVE (that.location)) - | ~~~~ ^ -parser.cc:300:7: error: type 'super_type' (aka 'basic_symbol') is not a direct or virtual base of 'yy: -:Parser::stack_symbol_type' - 300 | : super_type (YY_MOVE (that.state), YY_MOVE (that.value), YY_MOVE (that.location)) - | ^~~~~~~~~~ -parser.cc:304:10: error: no member named 'state' in 'yy::Parser::stack_symbol_type' - 304 | that.state = empty_state; - | ~~~~ ^ -parser.cc:304:18: error: use of undeclared identifier 'empty_state'; did you mean 'by_state::empty_state'? - 304 | that.state = empty_state; - | ^~~~~~~~~~~ - | by_state::empty_state -parser.tab.h:594:14: note: 'by_state::empty_state' declared here - 594 | enum { empty_state = 0 }; - | ^ -parser.cc:309:36: error: no member named 'value' in 'yy::Parser::symbol_type' - 309 | : super_type (s, YY_MOVE (that.value), YY_MOVE (that.location)) - | ~~~~ ^ -parser.cc:309:58: error: no member named 'location' in 'yy::Parser::symbol_type' - 309 | : super_type (s, YY_MOVE (that.value), YY_MOVE (that.location)) - | ~~~~ ^ -parser.cc:309:7: error: type 'super_type' (aka 'basic_symbol') is not a direct or virtual base of 'yy: -:Parser::stack_symbol_type' - 309 | : super_type (s, YY_MOVE (that.value), YY_MOVE (that.location)) - | ^~~~~~~~~~ -parser.cc:312:10: error: no member named 'kind_' in 'yy::Parser::symbol_type' - 312 | that.kind_ = symbol_kind::S_YYEMPTY; - | ~~~~ ^ -parser.cc:487:55: error: no member named 'state' in 'yy::Parser::stack_symbol_type' - 487 | YYCDEBUG << "Entering state " << int (yystack_[0].state) << '\n'; - | ~~~~~~~~~~~ ^ -parser.cc:491:21: error: no member named 'state' in 'yy::Parser::stack_symbol_type' - 491 | if (yystack_[0].state == yyfinal_) - | ~~~~~~~~~~~ ^ -parser.cc:502:32: error: no member named 'state' in 'yy::Parser::stack_symbol_type' - 502 | yyn = yypact_[+yystack_[0].state]; - | ~~~~~~~~~~~ ^ -parser.cc:507:14: error: no member named 'empty' in 'yy::Parser::symbol_type' - 507 | if (yyla.empty ()) - | ~~~~ ^ -parser.cc:514:18: error: no member named 'kind_' in 'yy::Parser::symbol_type' - 514 | yyla.kind_ = yytranslate_ (yylex (&yyla.value, &yyla.location, cursor, marker, limit)); - | ~~~~ ^ -fatal error: too many errors emitted, stopping now [-ferror-limit=] -1 warning and 20 errors generated. -[5/6] Compiling C++ object zane.p/meson-generated_.._lexer.cc.o -FAILED: [code=1] zane.p/meson-generated_.._lexer.cc.o -clang++ -Izane.p -I. -I.. -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra - -Wpedantic -std=c++20 -O0 -g -Wall -Wextra -MD -MQ zane.p/meson-generated_.._lexer.cc.o -MF zane.p/meson-genera -ted_.._lexer.cc.o.d -o zane.p/meson-generated_.._lexer.cc.o -c lexer.cc -In file included from ../src/grammar/lexer.re:9: -In file included from ../src/ast/logic.hpp:2: -In file included from ../src/ast/nodes.hpp:2: -In file included from ../src/ast/fwd.hpp:2: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/memory:65: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/bits/memoryfwd.h -:50: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l -inux-gnu/bits/c++config.h:727: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-l -inux-gnu/bits/os_defines.h:39: -/nix/store/fbbw928argckfii0j322346ihmllg7a7-glibc-2.42-61-dev/include/features.h:435:4: warning: _FORTIFY_SOURCE - requires compiling with optimization (-O) [-W#warnings] - 435 | # warning _FORTIFY_SOURCE requires compiling with optimization (-O) - | ^ -In file included from ../src/grammar/lexer.re:9: -In file included from ../src/ast/logic.hpp:2: -In file included from ../src/ast/nodes.hpp:6: -../src/ast/node_list.def:1:13: error: expected member name or ';' after declaration specifiers - 1 | X(IntNode, { int val; }) - | ^ -../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' - 5 | #define X(Name, Body) struct Name { Body }; - | ^ -In file included from ../src/grammar/lexer.re:9: -In file included from ../src/ast/logic.hpp:2: -In file included from ../src/ast/nodes.hpp:6: -../src/ast/node_list.def:2:13: error: expected member name or ';' after declaration specifiers - 2 | X(AddNode, { NodePtr lhs; NodePtr rhs; }) - | ^ -../src/ast/nodes.hpp:5:41: note: expanded from macro 'X' - 5 | #define X(Name, Body) struct Name { Body }; - | ^ -In file included from ../src/grammar/lexer.re:9: -In file included from ../src/ast/logic.hpp:3: -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:246:13: error: field has incom -plete type 'void' - 246 | _Type _M_storage; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:429:30: note: in instantiation - of template class 'std::__detail::__variant::_Uninitialized' requested here - 429 | _Uninitialized<_First> _M_first; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requested here - 430 | _Variadic_union<__trivially_destructible, _Rest...> _M_rest; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requested here -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:430:59: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requeste -d here -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:511:41: note: in instantiation - of template class 'std::__detail::__variant::_Variadic_union' requested here - 511 | _Variadic_union _M_u; - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:576:30: note: (skipping 2 cont -exts in backtrace; use -ftemplate-backtrace-limit=0 to see all) - 576 | struct _Copy_ctor_base : _Variant_storage_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:651:32: note: in instantiation - of template class 'std::__detail::__variant::_Move_ctor_base' requested here - 651 | struct _Copy_assign_base : _Move_ctor_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:703:32: note: in instantiation - of template class 'std::__detail::__variant::_Copy_assign_base' requested here - 703 | struct _Move_assign_base : _Copy_assign_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:757:28: note: in instantiation - of template class 'std::__detail::__variant::_Move_assign_base' requested here - 757 | struct _Variant_base : _Move_assign_alias<_Types...> - | ^ -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1426:15: note: in instantiatio -n of template class 'std::__detail::__variant::_Variant_base' -requested here - 1426 | : private __detail::__variant::_Variant_base<_Types...>, - | ^ -../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here - 15 | NodeVariant data; - | ^ -In file included from ../src/grammar/lexer.re:9: -In file included from ../src/ast/logic.hpp:3: -/nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/variant:1441:23: error: static asserti -on failed due to requirement 'std::is_object_v': variant alternatives must be non-array object types - 1441 | static_assert(((std::is_object_v<_Types> && !is_array_v<_Types>) && ...), - | ^~~~~~~~~~~~~~~~~~~~~~~~ -../src/ast/logic.hpp:15:21: note: in instantiation of template class 'std::variant' requested here - 15 | NodeVariant data; - | ^ -../src/grammar/lexer.re:25:36: error: excess elements in struct initializer - 25 | *yylval = ast::IntNode{std::stoi(toStr(start, cursor))}; - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -../src/grammar/lexer.re:25:21: error: no viable overloaded '=' - 25 | *yylval = ast::IntNode{std::stoi(toStr(start, cursor))}; - | ~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -../src/ast/logic.hpp:14:12: note: candidate function (the implicit copy assignment operator) not viable: no know -n conversion from 'ast::IntNode' to 'const Node' for 1st argument - 14 | struct Node { - | ^~~~ -../src/ast/logic.hpp:14:12: note: candidate function (the implicit move assignment operator) not viable: no know -n conversion from 'ast::IntNode' to 'Node' for 1st argument - 14 | struct Node { - | ^~~~ -../src/grammar/lexer.re:18:45: warning: unused parameter 'marker' [-Wunused-parameter] - 18 | const char*& cursor, const char*& marker, const char* limit) { - | ^ -2 warnings and 6 errors generated. -ninja: build stopped: subcommand failed. -bash: ./build/zane: No such file or directory - manuel on  ~/projects/zane/compiler essential/parser -# diff --git a/src/ast/logic.hpp b/src/ast/logic.hpp index 76709746..4d546d9c 100644 --- a/src/ast/logic.hpp +++ b/src/ast/logic.hpp @@ -1,16 +1,56 @@ #pragma once -#include "nodes.hpp" +#include #include + namespace ast { - #define X(Name, Body) Name, - using NodeVariant = std::variant< - #include "node_list.def" - std::monostate - >; - #undef X - struct Node { - NodeVariant data; - template explicit Node(T&& t) : data(std::forward(t)) {} - }; -} +// Integer literal node +struct IntNode { + int value; + IntNode(int v) : value(v) {} + IntNode(const IntNode&) = default; + IntNode& operator=(const IntNode&) = default; +}; + +// Addition node (left + right) +struct AddNode { + std::unique_ptr left; + std::unique_ptr right; + AddNode(std::unique_ptr l, std::unique_ptr r) + : left(std::move(l)), right(std::move(r)) {} + AddNode(const AddNode& other) + : left(other.left ? std::make_unique(*other.left) : nullptr), + right(other.right ? std::make_unique(*other.right) : nullptr) {} + AddNode& operator=(const AddNode& other) { + left = other.left ? std::make_unique(*other.left) : nullptr; + right = other.right ? std::make_unique(*other.right) : nullptr; + return *this; + } +}; + +// Node is a variant of all possible AST nodes +struct Node { + std::variant data; + + // Default constructor (required by Bison) + Node() : data(IntNode{0}) {} + + // Constructor for IntNode + explicit Node(IntNode t) : data(t) {} + + // Constructor for AddNode + explicit Node(AddNode t) : data(t) {} + + // Enable copy semantics (required by Bison) + Node(const Node& other) : data(other.data) {} + Node& operator=(const Node& other) { + data = other.data; + return *this; + } + + // Enable move semantics + Node(Node&&) = default; + Node& operator=(Node&&) = default; +}; + +} // namespace ast \ No newline at end of file diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 1eaf891c..df0409ee 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -17,12 +17,12 @@ static std::string toStr(const char* b, const char* e) { int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, const char*& cursor, const char*& marker, const char* limit) { for (;;) { - if (cursor >= limit) return yy::Parser::token::END; + if (cursor >= limit) return 0; // YYEOF const char* start = cursor; /*!re2c [ \t\n]+ { continue; } [0-9]+ { - *yylval = ast::IntNode{std::stoi(toStr(start, cursor))}; + *yylval = ast::Node(ast::IntNode{std::stoi(toStr(start, cursor))}); return yy::Parser::token::INT; } "+" { return yy::Parser::token::PLUS; } diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 1924a76c..9dcff6a9 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -5,10 +5,15 @@ %define api.namespace { yy } %define api.value.type { ast::Node } -%code requires { +%{ #include "ast/logic.hpp" #include #include +%} + +%code { + int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, + const char*& cursor, const char*& marker, const char* limit); } %locations @@ -16,20 +21,20 @@ %param { const char*& marker } %param { const char* limit } -%token INT -%token PLUS LPAREN RPAREN END ERROR -%type expr +%token INT +%token PLUS LPAREN RPAREN ERROR +%type expr %left PLUS %% -start: expr END ; +start: expr ; -expr: INT { $$ = ast::IntNode{$1}; } +expr: INT { $$ = std::move($1); } | expr PLUS expr { - $$ = ast::AddNode{ + $$ = ast::Node(ast::AddNode( std::make_unique(std::move($1)), std::make_unique(std::move($3)) - }; + )); } | LPAREN expr RPAREN { $$ = std::move($2); } ; diff --git a/src/main.cpp b/src/main.cpp index 9206a591..e601099f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,20 +3,28 @@ #include #include +int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, + const char*& cursor, const char*& marker, const char* limit); + int main(int argc, char** argv) { if (argc < 2) { - std::cerr << "Usage: " << argv[0] << " \"\"\n"; + std::cerr << "Usage: " << argv[0] << " \n"; return 1; } - - std::string src = argv[1]; - const char* cursor = src.data(); + + std::string input = argv[1]; + const char* cursor = input.c_str(); const char* marker = cursor; - const char* limit = cursor + src.size(); - - yy::Parser parser; - int res = parser.parse(cursor, marker, limit); - - if (res == 0) std::cout << "✓ Parsed\n"; + const char* limit = cursor + input.size(); + + yy::Parser parser(cursor, marker, limit); + int res = parser.parse(); + + if (res == 0) { + std::cout << "Parsed successfully\n"; + } else { + std::cerr << "Parsing failed\n"; + } + return res; } From c5f9cf0070915938579757a4990f39587c41214e Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 21 May 2026 19:00:03 +0200 Subject: [PATCH 005/154] update --- src/ast/logic.hpp | 74 ++++++++++++++++++++++---------------------- src/grammar/lexer.re | 34 ++++++++++---------- src/grammar/parser.y | 28 ++++++++--------- src/main.cpp | 42 ++++++++++++------------- src/types/stack.hpp | 2 +- 5 files changed, 90 insertions(+), 90 deletions(-) diff --git a/src/ast/logic.hpp b/src/ast/logic.hpp index 4d546d9c..e031870b 100644 --- a/src/ast/logic.hpp +++ b/src/ast/logic.hpp @@ -6,51 +6,51 @@ namespace ast { // Integer literal node struct IntNode { - int value; - IntNode(int v) : value(v) {} - IntNode(const IntNode&) = default; - IntNode& operator=(const IntNode&) = default; + int value; + IntNode(int v) : value(v) {} + IntNode(const IntNode&) = default; + IntNode& operator=(const IntNode&) = default; }; // Addition node (left + right) struct AddNode { - std::unique_ptr left; - std::unique_ptr right; - AddNode(std::unique_ptr l, std::unique_ptr r) - : left(std::move(l)), right(std::move(r)) {} - AddNode(const AddNode& other) - : left(other.left ? std::make_unique(*other.left) : nullptr), - right(other.right ? std::make_unique(*other.right) : nullptr) {} - AddNode& operator=(const AddNode& other) { - left = other.left ? std::make_unique(*other.left) : nullptr; - right = other.right ? std::make_unique(*other.right) : nullptr; - return *this; - } + std::unique_ptr left; + std::unique_ptr right; + AddNode(std::unique_ptr l, std::unique_ptr r) + : left(std::move(l)), right(std::move(r)) {} + AddNode(const AddNode& other) + : left(other.left ? std::make_unique(*other.left) : nullptr), + right(other.right ? std::make_unique(*other.right) : nullptr) {} + AddNode& operator=(const AddNode& other) { + left = other.left ? std::make_unique(*other.left) : nullptr; + right = other.right ? std::make_unique(*other.right) : nullptr; + return *this; + } }; // Node is a variant of all possible AST nodes struct Node { - std::variant data; - - // Default constructor (required by Bison) - Node() : data(IntNode{0}) {} - - // Constructor for IntNode - explicit Node(IntNode t) : data(t) {} - - // Constructor for AddNode - explicit Node(AddNode t) : data(t) {} - - // Enable copy semantics (required by Bison) - Node(const Node& other) : data(other.data) {} - Node& operator=(const Node& other) { - data = other.data; - return *this; - } - - // Enable move semantics - Node(Node&&) = default; - Node& operator=(Node&&) = default; + std::variant data; + + // Default constructor (required by Bison) + Node() : data(IntNode{0}) {} + + // Constructor for IntNode + explicit Node(IntNode t) : data(t) {} + + // Constructor for AddNode + explicit Node(AddNode t) : data(t) {} + + // Enable copy semantics (required by Bison) + Node(const Node& other) : data(other.data) {} + Node& operator=(const Node& other) { + data = other.data; + return *this; + } + + // Enable move semantics + Node(Node&&) = default; + Node& operator=(Node&&) = default; }; } // namespace ast \ No newline at end of file diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index df0409ee..b509dffc 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -11,24 +11,24 @@ re2c:yyfill:enable = 0; #include static std::string toStr(const char* b, const char* e) { - return std::string(b, static_cast(e - b)); + return std::string(b, static_cast(e - b)); } int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, - const char*& cursor, const char*& marker, const char* limit) { - for (;;) { - if (cursor >= limit) return 0; // YYEOF - const char* start = cursor; - /*!re2c - [ \t\n]+ { continue; } - [0-9]+ { - *yylval = ast::Node(ast::IntNode{std::stoi(toStr(start, cursor))}); - return yy::Parser::token::INT; - } - "+" { return yy::Parser::token::PLUS; } - "(" { return yy::Parser::token::LPAREN; } - ")" { return yy::Parser::token::RPAREN; } - * { return yy::Parser::token::ERROR; } - */ - } + const char*& cursor, const char*& marker, const char* limit) { + for (;;) { + if (cursor >= limit) return 0; // YYEOF + const char* start = cursor; + /*!re2c + [ \t\n]+ { continue; } + [0-9]+ { + *yylval = ast::Node(ast::IntNode{std::stoi(toStr(start, cursor))}); + return yy::Parser::token::INT; + } + "+" { return yy::Parser::token::PLUS; } + "(" { return yy::Parser::token::LPAREN; } + ")" { return yy::Parser::token::RPAREN; } + * { return yy::Parser::token::ERROR; } + */ + } } diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 9dcff6a9..625c3ceb 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -6,14 +6,14 @@ %define api.value.type { ast::Node } %{ - #include "ast/logic.hpp" - #include - #include + #include "ast/logic.hpp" + #include + #include %} %code { - int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, - const char*& cursor, const char*& marker, const char* limit); + int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, + const char*& cursor, const char*& marker, const char* limit); } %locations @@ -30,16 +30,16 @@ start: expr ; expr: INT { $$ = std::move($1); } - | expr PLUS expr { - $$ = ast::Node(ast::AddNode( - std::make_unique(std::move($1)), - std::make_unique(std::move($3)) - )); - } - | LPAREN expr RPAREN { $$ = std::move($2); } - ; + | expr PLUS expr { + $$ = ast::Node(ast::AddNode( + std::make_unique(std::move($1)), + std::make_unique(std::move($3)) + )); + } + | LPAREN expr RPAREN { $$ = std::move($2); } + ; %% void yy::Parser::error(const location& l, const std::string& m) { - std::cerr << "Error at " << l.begin.line << ":" << l.begin.column << ": " << m << "\n"; + std::cerr << "Error at " << l.begin.line << ":" << l.begin.column << ": " << m << "\n"; } diff --git a/src/main.cpp b/src/main.cpp index e601099f..1f826eee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,27 +4,27 @@ #include int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, - const char*& cursor, const char*& marker, const char* limit); + const char*& cursor, const char*& marker, const char* limit); int main(int argc, char** argv) { - if (argc < 2) { - std::cerr << "Usage: " << argv[0] << " \n"; - return 1; - } - - std::string input = argv[1]; - const char* cursor = input.c_str(); - const char* marker = cursor; - const char* limit = cursor + input.size(); - - yy::Parser parser(cursor, marker, limit); - int res = parser.parse(); - - if (res == 0) { - std::cout << "Parsed successfully\n"; - } else { - std::cerr << "Parsing failed\n"; - } - - return res; + if (argc < 2) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + std::string input = argv[1]; + const char* cursor = input.c_str(); + const char* marker = cursor; + const char* limit = cursor + input.size(); + + yy::Parser parser(cursor, marker, limit); + int res = parser.parse(); + + if (res == 0) { + std::cout << "Parsed successfully\n"; + } else { + std::cerr << "Parsing failed\n"; + } + + return res; } diff --git a/src/types/stack.hpp b/src/types/stack.hpp index 62e2eb90..e7f5a8b6 100644 --- a/src/types/stack.hpp +++ b/src/types/stack.hpp @@ -19,5 +19,5 @@ class Stack { auto rbegin() { return stack.rbegin(); } auto rend() { return stack.rend(); } auto begin() { return stack.begin(); } - auto end() { return stack.end(); } + auto end() { return stack.end(); } }; From 4c59fcb1e73280865231d3d6ed781507512c206e Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 21 May 2026 19:13:37 +0200 Subject: [PATCH 006/154] first setup --- justfile | 21 ++++----------------- src/main.cpp | 19 ++++++++++++------- test-parser/main.zn | 1 + 3 files changed, 17 insertions(+), 24 deletions(-) create mode 100644 test-parser/main.zn diff --git a/justfile b/justfile index 8b218f0c..8edbc98e 100644 --- a/justfile +++ b/justfile @@ -1,26 +1,13 @@ -build: - meson compile -C build - -init: +debug: rm -rf build - test -d .git/modules || git submodule update --init --recursive vcpkg install CXX=clang++ meson setup build --buildtype=debug --cmake-prefix-path "$(realpath vcpkg_installed/x64-linux)" release: rm -rf build - test -d .git/modules || git submodule update --init --recursive vcpkg install CXX=clang++ meson setup build --buildtype=release --cmake-prefix-path "$(realpath vcpkg_installed/x64-linux)" -check: - clang-check -p build src/*.* - -generate-parser: - scripts/generate_parser.sh - -check-parser: - scripts/check_parser.sh - -link: - ln -sf build/zane bin/zane +test-parser: + meson compile -C build + ./build/zane "1 + 2" diff --git a/src/main.cpp b/src/main.cpp index 1f826eee..4ed0d6be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,17 +2,22 @@ #include "parser.tab.h" #include #include +#include int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, - const char*& cursor, const char*& marker, const char* limit); + const char*& cursor, const char*& marker, const char* limit); + +std::string readFile(const std::string& path) { + std::ifstream file(path); + if (!file.is_open()) + throw std::runtime_error("Could not open file: " + path); + + return std::string((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); +} int main(int argc, char** argv) { - if (argc < 2) { - std::cerr << "Usage: " << argv[0] << " \n"; - return 1; - } - - std::string input = argv[1]; + std::string input = readFile("test-parser/main.zn"); const char* cursor = input.c_str(); const char* marker = cursor; const char* limit = cursor + input.size(); diff --git a/test-parser/main.zn b/test-parser/main.zn new file mode 100644 index 00000000..8d2f0971 --- /dev/null +++ b/test-parser/main.zn @@ -0,0 +1 @@ +1 + 1 From 74af338d9788e75aa972adfd9f653d1bb1044c43 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 22 May 2026 18:54:20 +0200 Subject: [PATCH 007/154] use node_list.def --- src/ast/logic.hpp | 58 +++++++++++++++++++------------------------ src/ast/node_list.def | 16 ++++++++++-- src/ast/nodes.hpp | 3 +++ 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/ast/logic.hpp b/src/ast/logic.hpp index e031870b..2ac172a6 100644 --- a/src/ast/logic.hpp +++ b/src/ast/logic.hpp @@ -1,45 +1,24 @@ #pragma once -#include #include -namespace ast { - -// Integer literal node -struct IntNode { - int value; - IntNode(int v) : value(v) {} - IntNode(const IntNode&) = default; - IntNode& operator=(const IntNode&) = default; -}; +#include "nodes.hpp" -// Addition node (left + right) -struct AddNode { - std::unique_ptr left; - std::unique_ptr right; - AddNode(std::unique_ptr l, std::unique_ptr r) - : left(std::move(l)), right(std::move(r)) {} - AddNode(const AddNode& other) - : left(other.left ? std::make_unique(*other.left) : nullptr), - right(other.right ? std::make_unique(*other.right) : nullptr) {} - AddNode& operator=(const AddNode& other) { - left = other.left ? std::make_unique(*other.left) : nullptr; - right = other.right ? std::make_unique(*other.right) : nullptr; - return *this; - } -}; +namespace ast { -// Node is a variant of all possible AST nodes struct Node { - std::variant data; + std::variant< + std::monostate + #define X(Name, Members) , Name + #include "node_list.def" + #undef X + > data; // Default constructor (required by Bison) Node() : data(IntNode{0}) {} - // Constructor for IntNode - explicit Node(IntNode t) : data(t) {} - - // Constructor for AddNode - explicit Node(AddNode t) : data(t) {} + #define X(Name, Members) explicit Node(Name t) : data(std::move(t)) {} + #include "node_list.def" + #undef X // Enable copy semantics (required by Bison) Node(const Node& other) : data(other.data) {} @@ -53,4 +32,17 @@ struct Node { Node& operator=(Node&&) = default; }; -} // namespace ast \ No newline at end of file +inline AddNode::AddNode(std::unique_ptr l, std::unique_ptr r) + : left(std::move(l)), right(std::move(r)) {} + +inline AddNode::AddNode(const AddNode& other) + : left(other.left ? std::make_unique(*other.left) : nullptr), + right(other.right ? std::make_unique(*other.right) : nullptr) {} + +inline AddNode& AddNode::operator=(const AddNode& other) { + left = other.left ? std::make_unique(*other.left) : nullptr; + right = other.right ? std::make_unique(*other.right) : nullptr; + return *this; +} + +} // namespace ast diff --git a/src/ast/node_list.def b/src/ast/node_list.def index 2844faca..2ef28bcd 100644 --- a/src/ast/node_list.def +++ b/src/ast/node_list.def @@ -1,2 +1,14 @@ -X(IntNode, { int val; }) -X(AddNode, { std::unique_ptr lhs; std::unique_ptr rhs; }) +X(IntNode, { + int value; + IntNode(int v) : value(v) {} + IntNode(const IntNode&) = default; + IntNode& operator=(const IntNode&) = default; +}) + +X(AddNode, { + std::unique_ptr left; + std::unique_ptr right; + AddNode(std::unique_ptr l, std::unique_ptr r); + AddNode(const AddNode& other); + AddNode& operator=(const AddNode& other); +}) diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index dedba9e0..88ae8b16 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -1,5 +1,8 @@ #pragma once +#include +#include #include "fwd.hpp" + namespace ast { #define X(Name, Members) struct Name Members; #include "node_list.def" From 96cf72c8d36ae2415720f94a9f457c2baaa77546 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 23 May 2026 11:58:09 +0200 Subject: [PATCH 008/154] update --- error.txt | 95 +++++++++++++++++++++++++++++++++++++++++++ justfile | 2 +- src/ast/fwd.hpp | 6 --- src/ast/logic.hpp | 48 ---------------------- src/ast/node_list.def | 14 ------- src/ast/nodes.hpp | 38 ++++++++++++++--- src/grammar/lexer.re | 5 ++- src/grammar/parser.y | 39 +++++++++++------- src/main.cpp | 2 +- 9 files changed, 158 insertions(+), 91 deletions(-) create mode 100644 error.txt delete mode 100644 src/ast/fwd.hpp delete mode 100644 src/ast/logic.hpp delete mode 100644 src/ast/node_list.def diff --git a/error.txt b/error.txt new file mode 100644 index 00000000..335848ea --- /dev/null +++ b/error.txt @@ -0,0 +1,95 @@ + manuel on  ~/projects/zane/compiler essential/parser +# devbox shell +Starting a devbox shell... +Welcome to devbox! + manuel on  ~/projects/zane/compiler essential/parser +# just debug test-parser +rm -rf build +vcpkg install +Detecting compiler hash for triplet x64-linux... +Compiler found: /nix/store/qd70v8g0561vm8m33kmnp79z00cgyi5n-gcc-wrapper-15.2.0/bin/g++ +The following packages are already installed: + cereal:x64-linux@1.3.2#1 -- git+https://github.com/microsoft/vcpkg@075869fcf5302c6dd11d564286d0dfa1d2d4d7a1 + nlohmann-json:x64-linux@3.12.0#2 -- git+https://github.com/microsoft/vcpkg@ac3b8821cf486e45dd543bef2a4ba1d1ba230258 + * vcpkg-cmake:x64-linux@2024-04-23 -- git+https://github.com/microsoft/vcpkg@e74aa1e8f93278a8e71372f1fa08c3df420eb840 + * vcpkg-cmake-config:x64-linux@2024-05-23 -- git+https://github.com/microsoft/vcpkg@97a63e4bc1a17422ffe4eff71da53b4b561a7841 +cereal provides CMake targets: + + # this is heuristically generated, and may not be correct + find_package(cereal CONFIG REQUIRED) + target_link_libraries(main PRIVATE cereal::cereal) + +The package nlohmann-json provides CMake targets: + + find_package(nlohmann_json CONFIG REQUIRED) + target_link_libraries(main PRIVATE nlohmann_json::nlohmann_json) + +The package nlohmann-json can be configured to not provide implicit conversions via a custom triplet file: + + set(nlohmann-json_IMPLICIT_CONVERSIONS OFF) + +For more information, see the docs here: + + https://json.nlohmann.me/api/macros/json_use_implicit_conversions/ + +All requested installations completed successfully in: 198 us +CXX=clang++ meson setup build --buildtype=debug --cmake-prefix-path "$(realpath vcpkg_installed/x64-linux)" +The Meson build system +Version: 1.10.2 +Source dir: /home/manuel/projects/zane/compiler +Build dir: /home/manuel/projects/zane/compiler/build +Build type: native build +Project name: zane +Project version: 0.1.0 +C++ compiler for the host machine: clang++ (clang 21.1.8 "clang version 21.1.8") +C++ linker for the host machine: clang++ ld.bfd 2.46 +Host machine cpu family: x86_64 +Host machine cpu: x86_64 +Program re2c found: YES (/home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/re2c) +Program bison found: YES (/home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/bison) +Build targets in project: 3 + +zane 0.1.0 + + User defined options + buildtype : debug + cmake_prefix_path: /home/manuel/projects/zane/compiler/vcpkg_installed/x64-linux + +Found ninja-1.13.1 at /home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/ninja +meson compile -C build +INFO: autodetecting backend as ninja +INFO: calculating backend command to run: /home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/ninja -C /home/man +uel/projects/zane/compiler/build +ninja: Entering directory `/home/manuel/projects/zane/compiler/build' +[1/6] Generating parser with a custom command +FAILED: [code=1] parser.cc parser.tab.h +/home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/bison -d -o parser.cc --defines=parser.tab.h ../src/grammar/ +parser.y +../src/grammar/parser.y:33.24-25: error: $1 of ‘expr’ has no declared type + 33 | $$ = std::move($1); // $1 is already unique_ptr + | ^~ +[2/6] Compiling C++ object zane.p/src_main.cpp.o +FAILED: [code=1] zane.p/src_main.cpp.o +clang++ -Izane.p -I. -I.. -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Wpedantic -std +=c++20 -O0 -g -Wall -Wextra -MD -MQ zane.p/src_main.cpp.o -MF zane.p/src_main.cpp.o.d -o zane.p/src_main.cpp.o -c ../src/main.cp +p +In file included from ../src/main.cpp:1: +In file included from ../src/ast/nodes.hpp:2: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/memory:65: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/bits/memoryfwd.h:50: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-linux-gnu/bits/c+ ++config.h:727: +In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-linux-gnu/bits/os +_defines.h:39: +/nix/store/fbbw928argckfii0j322346ihmllg7a7-glibc-2.42-61-dev/include/features.h:435:4: warning: _FORTIFY_SOURCE requires compil +ing with optimization (-O) [-W#warnings] + 435 | # warning _FORTIFY_SOURCE requires compiling with optimization (-O) + | ^ +../src/main.cpp:2:10: fatal error: 'parser.tab.h' file not found + 2 | #include "parser.tab.h" + | ^~~~~~~~~~~~~~ +1 warning and 1 error generated. +ninja: build stopped: subcommand failed. +error: Recipe `test-parser` failed on line 12 with exit code 1 + manuel on  ~/projects/zane/compiler essential/parser +# diff --git a/justfile b/justfile index 8edbc98e..251ef8d2 100644 --- a/justfile +++ b/justfile @@ -10,4 +10,4 @@ release: test-parser: meson compile -C build - ./build/zane "1 + 2" + ./build/zane diff --git a/src/ast/fwd.hpp b/src/ast/fwd.hpp deleted file mode 100644 index de9bfb80..00000000 --- a/src/ast/fwd.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include -namespace ast { - struct Node; - using NodePtr = std::unique_ptr; -} diff --git a/src/ast/logic.hpp b/src/ast/logic.hpp deleted file mode 100644 index 2ac172a6..00000000 --- a/src/ast/logic.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -#include - -#include "nodes.hpp" - -namespace ast { - -struct Node { - std::variant< - std::monostate - #define X(Name, Members) , Name - #include "node_list.def" - #undef X - > data; - - // Default constructor (required by Bison) - Node() : data(IntNode{0}) {} - - #define X(Name, Members) explicit Node(Name t) : data(std::move(t)) {} - #include "node_list.def" - #undef X - - // Enable copy semantics (required by Bison) - Node(const Node& other) : data(other.data) {} - Node& operator=(const Node& other) { - data = other.data; - return *this; - } - - // Enable move semantics - Node(Node&&) = default; - Node& operator=(Node&&) = default; -}; - -inline AddNode::AddNode(std::unique_ptr l, std::unique_ptr r) - : left(std::move(l)), right(std::move(r)) {} - -inline AddNode::AddNode(const AddNode& other) - : left(other.left ? std::make_unique(*other.left) : nullptr), - right(other.right ? std::make_unique(*other.right) : nullptr) {} - -inline AddNode& AddNode::operator=(const AddNode& other) { - left = other.left ? std::make_unique(*other.left) : nullptr; - right = other.right ? std::make_unique(*other.right) : nullptr; - return *this; -} - -} // namespace ast diff --git a/src/ast/node_list.def b/src/ast/node_list.def deleted file mode 100644 index 2ef28bcd..00000000 --- a/src/ast/node_list.def +++ /dev/null @@ -1,14 +0,0 @@ -X(IntNode, { - int value; - IntNode(int v) : value(v) {} - IntNode(const IntNode&) = default; - IntNode& operator=(const IntNode&) = default; -}) - -X(AddNode, { - std::unique_ptr left; - std::unique_ptr right; - AddNode(std::unique_ptr l, std::unique_ptr r); - AddNode(const AddNode& other); - AddNode& operator=(const AddNode& other); -}) diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index 88ae8b16..d5dae72e 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -1,10 +1,38 @@ #pragma once #include #include -#include "fwd.hpp" +#include namespace ast { - #define X(Name, Members) struct Name Members; - #include "node_list.def" - #undef X -} + +struct Node; +using NodePtr = std::unique_ptr; + +struct IntNode { + int value; + IntNode(int v) : value(v) {} +}; + +struct ValueNode; + +struct AddNode { + std::unique_ptr left; + std::unique_ptr right; + explicit AddNode(std::unique_ptr l, std::unique_ptr r) + : left(std::move(l)), right(std::move(r)) {} +}; + +struct ValueNode { + std::variant data; + + explicit ValueNode(IntNode t) : data(std::move(t)) {} + explicit ValueNode(AddNode t) : data(std::move(t)) {} +}; + +struct Program { + std::unique_ptr valueNode; + + explicit Program(std::unique_ptr t) : valueNode(std::move(t)) {}; +}; + +} // namespace ast diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index b509dffc..851d23fa 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -6,7 +6,7 @@ re2c:define:YYMARKER = marker; re2c:yyfill:enable = 0; */ -#include "ast/logic.hpp" +#include "ast/nodes.hpp" #include "parser.tab.h" #include @@ -22,7 +22,8 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, /*!re2c [ \t\n]+ { continue; } [0-9]+ { - *yylval = ast::Node(ast::IntNode{std::stoi(toStr(start, cursor))}); + int val = std::stoi(toStr(start, cursor)); + *yylval = new ast::ValueNode(ast::IntNode{val}); return yy::Parser::token::INT; } "+" { return yy::Parser::token::PLUS; } diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 625c3ceb..97251f21 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -3,12 +3,12 @@ %define api.parser.class { Parser } %define api.namespace { yy } -%define api.value.type { ast::Node } +%define api.value.type { ast::ValueNode* } %{ - #include "ast/logic.hpp" + #include "ast/nodes.hpp" + #include #include - #include %} %code { @@ -24,20 +24,31 @@ %token INT %token PLUS LPAREN RPAREN ERROR %type expr +%destructor { delete $$; } INT expr %left PLUS %% -start: expr ; - -expr: INT { $$ = std::move($1); } - | expr PLUS expr { - $$ = ast::Node(ast::AddNode( - std::make_unique(std::move($1)), - std::make_unique(std::move($3)) - )); - } - | LPAREN expr RPAREN { $$ = std::move($2); } - ; +start: expr { + delete $1; +} ; + +expr: INT { + $$ = $1; + $1 = nullptr; + +} +| expr PLUS expr { + $$ = new ast::ValueNode(ast::AddNode{ + std::unique_ptr($1), + std::unique_ptr($3), + }); + $1 = nullptr; + $3 = nullptr; +} +| LPAREN expr RPAREN { + $$ = $2; + $2 = nullptr; +} %% void yy::Parser::error(const location& l, const std::string& m) { diff --git a/src/main.cpp b/src/main.cpp index 4ed0d6be..0a2ba8f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -#include "ast/logic.hpp" +#include "ast/nodes.hpp" #include "parser.tab.h" #include #include From a7f2da7c3760afc0d9e4b4ad44e3732f9b24e2f0 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 23 May 2026 12:50:46 +0200 Subject: [PATCH 009/154] update --- src/ast/.hpp | 4 ++++ src/ast/evaluators/.hpp | 3 +++ src/ast/evaluators/to_string.hpp | 32 ++++++++++++++++++++++++++++++++ src/ast/nodes.hpp | 8 +++----- src/grammar/lexer.re | 7 ++++--- src/grammar/parser.y | 17 ++++++++++------- src/main.cpp | 17 ++++++++++------- 7 files changed, 66 insertions(+), 22 deletions(-) create mode 100644 src/ast/.hpp create mode 100644 src/ast/evaluators/.hpp create mode 100644 src/ast/evaluators/to_string.hpp diff --git a/src/ast/.hpp b/src/ast/.hpp new file mode 100644 index 00000000..13c93e2e --- /dev/null +++ b/src/ast/.hpp @@ -0,0 +1,4 @@ +#pragma once + +#include "ast/nodes.hpp" +#include "ast/evaluators/.hpp" diff --git a/src/ast/evaluators/.hpp b/src/ast/evaluators/.hpp new file mode 100644 index 00000000..66fdbeb5 --- /dev/null +++ b/src/ast/evaluators/.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "ast/evaluators/to_string.hpp" diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp new file mode 100644 index 00000000..c8406674 --- /dev/null +++ b/src/ast/evaluators/to_string.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "ast/nodes.hpp" +#include +#include +#include + +namespace ast::evaluators { + +struct ToString { + std::string operator()(const nodes::Program& program) const { + // NOTE: can only visit variant types + return std::visit(*this, program.valueNode->data); + } + + std::string operator()(const nodes::ValueNode& node) const { + return std::visit(*this, node.data); + } + + std::string operator()(const nodes::IntNode& n) const { + return std::to_string(n.value); + } + + std::string operator()(const nodes::AddNode& n) const { + // NOTE: can only visit variant types,which is why we get data directly + std::string l = std::visit(*this, n.left->data); + std::string r = std::visit(*this, n.right->data); + return "(" + l + " + " + r + ")"; + } +}; + +} // namespace evaluators diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index d5dae72e..5cabbb84 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -3,10 +3,7 @@ #include #include -namespace ast { - -struct Node; -using NodePtr = std::unique_ptr; +namespace ast::nodes { struct IntNode { int value; @@ -18,6 +15,7 @@ struct ValueNode; struct AddNode { std::unique_ptr left; std::unique_ptr right; + explicit AddNode(std::unique_ptr l, std::unique_ptr r) : left(std::move(l)), right(std::move(r)) {} }; @@ -35,4 +33,4 @@ struct Program { explicit Program(std::unique_ptr t) : valueNode(std::move(t)) {}; }; -} // namespace ast +} // namespace nodes diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 851d23fa..e643d55c 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -6,7 +6,7 @@ re2c:define:YYMARKER = marker; re2c:yyfill:enable = 0; */ -#include "ast/nodes.hpp" +#include "ast/.hpp" #include "parser.tab.h" #include @@ -15,7 +15,8 @@ static std::string toStr(const char* b, const char* e) { } int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, - const char*& cursor, const char*& marker, const char* limit) { + const char*& cursor, const char*& marker, const char* limit, + ast::nodes::ValueNode*&) { for (;;) { if (cursor >= limit) return 0; // YYEOF const char* start = cursor; @@ -23,7 +24,7 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, [ \t\n]+ { continue; } [0-9]+ { int val = std::stoi(toStr(start, cursor)); - *yylval = new ast::ValueNode(ast::IntNode{val}); + *yylval = new ast::nodes::ValueNode(ast::nodes::IntNode{val}); return yy::Parser::token::INT; } "+" { return yy::Parser::token::PLUS; } diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 97251f21..77b85ea6 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -3,23 +3,25 @@ %define api.parser.class { Parser } %define api.namespace { yy } -%define api.value.type { ast::ValueNode* } +%define api.value.type { ast::nodes::ValueNode* } %{ - #include "ast/nodes.hpp" + #include "ast/.hpp" #include #include %} %code { int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, - const char*& cursor, const char*& marker, const char* limit); + const char*& cursor, const char*& marker, const char* limit, + ast::nodes::ValueNode*& result); } %locations %param { const char*& cursor } %param { const char*& marker } %param { const char* limit } +%param { ast::nodes::ValueNode*& result } %token INT %token PLUS LPAREN RPAREN ERROR @@ -29,7 +31,8 @@ %% start: expr { - delete $1; + result = $1; + $1 = nullptr; } ; expr: INT { @@ -38,9 +41,9 @@ expr: INT { } | expr PLUS expr { - $$ = new ast::ValueNode(ast::AddNode{ - std::unique_ptr($1), - std::unique_ptr($3), + $$ = new ast::nodes::ValueNode(ast::nodes::AddNode{ + std::unique_ptr($1), + std::unique_ptr($3), }); $1 = nullptr; $3 = nullptr; diff --git a/src/main.cpp b/src/main.cpp index 0a2ba8f8..c0cf3096 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,14 @@ -#include "ast/nodes.hpp" +#include "src/ast/.hpp" +#include "ast/evaluators/to_string.hpp" #include "parser.tab.h" #include #include #include +#include int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, - const char*& cursor, const char*& marker, const char* limit); + const char*& cursor, const char*& marker, const char* limit, + ast::nodes::ValueNode*& result); std::string readFile(const std::string& path) { std::ifstream file(path); @@ -21,14 +24,14 @@ int main(int argc, char** argv) { const char* cursor = input.c_str(); const char* marker = cursor; const char* limit = cursor + input.size(); + ast::nodes::ValueNode* result = nullptr; - yy::Parser parser(cursor, marker, limit); + yy::Parser parser(cursor, marker, limit, result); int res = parser.parse(); - if (res == 0) { - std::cout << "Parsed successfully\n"; - } else { - std::cerr << "Parsing failed\n"; + if (result != nullptr) { + std::cout << std::visit(ast::evaluators::ToString{}, result->data); + delete result; } return res; From b7da9fcaf55cdb9b15c7296e7f62a699d005879e Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 23 May 2026 12:58:25 +0200 Subject: [PATCH 010/154] update --- src/grammar/lexer.re | 2 +- src/grammar/parser.y | 6 +++--- src/main.cpp | 13 ++++++------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index e643d55c..7d037bca 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -16,7 +16,7 @@ static std::string toStr(const char* b, const char* e) { int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, const char*& cursor, const char*& marker, const char* limit, - ast::nodes::ValueNode*&) { + ast::nodes::Program*&) { for (;;) { if (cursor >= limit) return 0; // YYEOF const char* start = cursor; diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 77b85ea6..b0b68abe 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -14,14 +14,14 @@ %code { int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, const char*& cursor, const char*& marker, const char* limit, - ast::nodes::ValueNode*& result); + ast::nodes::Program*& ast); } %locations %param { const char*& cursor } %param { const char*& marker } %param { const char* limit } -%param { ast::nodes::ValueNode*& result } +%param { ast::nodes::Program*& ast } %token INT %token PLUS LPAREN RPAREN ERROR @@ -31,7 +31,7 @@ %% start: expr { - result = $1; + ast = new ast::nodes::Program(std::unique_ptr($1)); $1 = nullptr; } ; diff --git a/src/main.cpp b/src/main.cpp index c0cf3096..6a9fc3f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,4 @@ #include "src/ast/.hpp" -#include "ast/evaluators/to_string.hpp" #include "parser.tab.h" #include #include @@ -8,7 +7,7 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, const char*& cursor, const char*& marker, const char* limit, - ast::nodes::ValueNode*& result); + ast::nodes::Program*& ast); std::string readFile(const std::string& path) { std::ifstream file(path); @@ -24,14 +23,14 @@ int main(int argc, char** argv) { const char* cursor = input.c_str(); const char* marker = cursor; const char* limit = cursor + input.size(); - ast::nodes::ValueNode* result = nullptr; + ast::nodes::Program* ast = nullptr; - yy::Parser parser(cursor, marker, limit, result); + yy::Parser parser(cursor, marker, limit, ast); int res = parser.parse(); - if (result != nullptr) { - std::cout << std::visit(ast::evaluators::ToString{}, result->data); - delete result; + if (ast != nullptr) { + std::cout << std::visit(ast::evaluators::ToString {}, ast->valueNode->data); + delete ast; } return res; From 0ab8c4f7b1ddb667453a855e07ef13d84e682ef3 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 23 May 2026 13:06:32 +0200 Subject: [PATCH 011/154] fix meson --- meson.build | 7 +++---- src/main.cpp | 2 +- test-parser/main.zn | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/meson.build b/meson.build index 238d6e30..40493fce 100644 --- a/meson.build +++ b/meson.build @@ -22,8 +22,7 @@ lexer_gen = custom_target('lexer', executable('zane', 'src/main.cpp', - parser_gen[0], - lexer_gen, - include_directories: include_directories('src', '.'), - cpp_args: ['-Wall', '-Wextra'], + parser_gen[0], # parser.cc + lexer_gen, # lexer.cc + include_directories: include_directories('src'), ) diff --git a/src/main.cpp b/src/main.cpp index 6a9fc3f6..630e9601 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -#include "src/ast/.hpp" +#include "ast/.hpp" #include "parser.tab.h" #include #include diff --git a/test-parser/main.zn b/test-parser/main.zn index 8d2f0971..943766bb 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1 +1 @@ -1 + 1 +1 + 1 + 10 + 20 From 202a25d43990021b3644d7d9687d398b7825bbbf Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 23 May 2026 13:29:48 +0200 Subject: [PATCH 012/154] getting ready for zane ast --- src/ast/evaluators/to_string.hpp | 1 - src/ast/nodes.hpp | 40 ++++++++++++++++++-------------- test-parser/main.zn | 4 +++- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index c8406674..0a25c3b3 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -3,7 +3,6 @@ #include "ast/nodes.hpp" #include #include -#include namespace ast::evaluators { diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index 5cabbb84..fc73a7f2 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -1,36 +1,42 @@ #pragma once #include +#include #include #include +#include namespace ast::nodes { -struct IntNode { - int value; - IntNode(int v) : value(v) {} +struct TypeExpression; + +struct NameType { + std::string name; + std::vector generics; }; -struct ValueNode; +struct FunctionType { + std::vector paramTypes; + std::unique_ptr returnType; +}; -struct AddNode { - std::unique_ptr left; - std::unique_ptr right; +struct TypeExpression { + std::variant data; - explicit AddNode(std::unique_ptr l, std::unique_ptr r) - : left(std::move(l)), right(std::move(r)) {} + explicit TypeExpression(NameType nameType) : data(std::move(nameType)) {} + explicit TypeExpression(FunctionType functionType) : data(std::move(functionType)) {} }; -struct ValueNode { - std::variant data; - - explicit ValueNode(IntNode t) : data(std::move(t)) {} - explicit ValueNode(AddNode t) : data(std::move(t)) {} +struct FunctionDecl { + std::string name; + FunctionType type; }; -struct Program { - std::unique_ptr valueNode; +using Declaration = FunctionDecl; + +struct Package { + std::vector declarations; - explicit Program(std::unique_ptr t) : valueNode(std::move(t)) {}; + explicit Package() : declarations() {}; }; } // namespace nodes diff --git a/test-parser/main.zn b/test-parser/main.zn index 943766bb..13a02c2a 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1 +1,3 @@ -1 + 1 + 10 + 20 +Void main() { + print("hello") +} From fa601ac72c8b78ae994960c30d8312828ca1d977 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 23 May 2026 13:57:58 +0200 Subject: [PATCH 013/154] update nodes to sufficient for test example --- src/ast/nodes.hpp | 51 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index fc73a7f2..f14d2933 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -7,6 +7,8 @@ namespace ast::nodes { +struct Statement; + struct TypeExpression; struct NameType { @@ -21,22 +23,59 @@ struct FunctionType { struct TypeExpression { std::variant data; +}; - explicit TypeExpression(NameType nameType) : data(std::move(nameType)) {} - explicit TypeExpression(FunctionType functionType) : data(std::move(functionType)) {} +struct Scope { + std::vector> statements; +}; + +struct Parameter { + std::unique_ptr type; + std::string name; }; struct FunctionDecl { - std::string name; - FunctionType type; + std::string name; + std::vector parameters; + TypeExpression returnType; + Scope functionBody; + bool mutating; }; -using Declaration = FunctionDecl; + +// values +struct ValueExpr; + +struct FunctionCall { + std::unique_ptr callee; + std::vector arguments; +}; + +/// does not include quotes +struct StringLiteral { + std::string data; +}; + +struct ValueSymbol { + std::string name; +}; + +struct ValueExpr { + /// decided not to distinguish between callable and objects, since not verifyable at parse time + std::variant data; +}; +// end values + +struct Statement { + std::variant data; +}; + +using Declaration = std::variant; struct Package { std::vector declarations; - explicit Package() : declarations() {}; + explicit Package() : declarations() {} }; } // namespace nodes From 8b0c830c6b428c3572b05ef98f6c860783d20098 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 23 May 2026 18:12:49 +0200 Subject: [PATCH 014/154] add stages.md --- docs/stages.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/stages.md diff --git a/docs/stages.md b/docs/stages.md new file mode 100644 index 00000000..a4635b7a --- /dev/null +++ b/docs/stages.md @@ -0,0 +1,8 @@ +We use 4 stages: +1. parsing: astA +2. semantics: astB +3. optimizations: mutate astB +4. codegen: binary + +we use two different ast's. astA only captures the content and doesnt do name resolution or desugaring. +those things are handled in stage 2 semantics. From abbe2509701872ad7cc333b877737393d64b9a53 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 23 May 2026 19:17:41 +0200 Subject: [PATCH 015/154] update --- src/grammar/lexer.re | 66 +++++++++----- src/grammar/parser.y | 203 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 211 insertions(+), 58 deletions(-) diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 7d037bca..3ed3e5af 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -1,11 +1,3 @@ -/*!re2c -re2c:define:YYCTYPE = "unsigned char"; -re2c:define:YYCURSOR = cursor; -re2c:define:YYLIMIT = limit; -re2c:define:YYMARKER = marker; -re2c:yyfill:enable = 0; -*/ - #include "ast/.hpp" #include "parser.tab.h" #include @@ -14,23 +6,55 @@ static std::string toStr(const char* b, const char* e) { return std::string(b, static_cast(e - b)); } +static std::string unescape(const char* b, const char* e) { + std::string out; + out.reserve(static_cast(e - b)); + while (b < e) { + if (*b == '\\' && b + 1 < e) { + ++b; + switch (*b) { + case '"': out += '"'; break; + case '\\': out += '\\'; break; + case 'n': out += '\n'; break; + case 't': out += '\t'; break; + default: out += '\\'; out += *b; break; + } + } else { + out += *b; + } + ++b; + } + return out; +} + int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, - const char*& cursor, const char*& marker, const char* limit, - ast::nodes::Program*&) { + const char*& cursor, const char*& marker, const char* limit, + ast::nodes::Package*&) { for (;;) { - if (cursor >= limit) return 0; // YYEOF + if (cursor >= limit) return 0; const char* start = cursor; /*!re2c - [ \t\n]+ { continue; } - [0-9]+ { - int val = std::stoi(toStr(start, cursor)); - *yylval = new ast::nodes::ValueNode(ast::nodes::IntNode{val}); - return yy::Parser::token::INT; - } - "+" { return yy::Parser::token::PLUS; } - "(" { return yy::Parser::token::LPAREN; } - ")" { return yy::Parser::token::RPAREN; } - * { return yy::Parser::token::ERROR; } + re2c:flags:utf-8 = 1; + re2c:define:YYCTYPE = "char"; + re2c:define:YYCURSOR = cursor; + re2c:define:YYLIMIT = limit; + re2c:define:YYMARKER = marker; + re2c:yyfill:enable = 0; + + nonascii = [\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]; + ident = [a-zA-Z_] | nonascii; + str_char = [^"\\] | "\\" [^]; + + [ \t\n]+ { continue; } + "(" { return yy::Parser::token::LPAREN; } + ")" { return yy::Parser::token::RPAREN; } + "{" { return yy::Parser::token::LCURLY; } + "}" { return yy::Parser::token::RCURLY; } + ["] str_char* ["] { yylval->emplace(unescape(start+1, cursor-1)); + return yy::Parser::token::STRING; } + ident+ { yylval->emplace(toStr(start, cursor)); + return yy::Parser::token::IDENT; } + * { return yy::Parser::token::ERROR; } */ } } diff --git a/src/grammar/parser.y b/src/grammar/parser.y index b0b68abe..5301560a 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -1,59 +1,188 @@ %skeleton "lalr1.cc" %require "3.8" +%define api.parser.class {Parser} +%define api.value.type variant +%define parse.error detailed +%locations -%define api.parser.class { Parser } -%define api.namespace { yy } -%define api.value.type { ast::nodes::ValueNode* } - -%{ +%code requires { #include "ast/.hpp" #include + #include #include -%} + #include +} %code { int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, - const char*& cursor, const char*& marker, const char* limit, - ast::nodes::Program*& ast); + const char*& cursor, const char*& marker, const char* limit, + ast::nodes::Package*& ast); } -%locations %param { const char*& cursor } %param { const char*& marker } %param { const char* limit } -%param { ast::nodes::Program*& ast } +%param { ast::nodes::Package*& ast } + +// --- tokens --- +%token LPAREN RPAREN LCURLY RCURLY +%token COMMA COLON SEMICOLON +%token STRING IDENT +%token ERROR -%token INT -%token PLUS LPAREN RPAREN ERROR -%type expr -%destructor { delete $$; } INT expr -%left PLUS +// --- non-terminal types --- +%type package +%type declaration +%type function_decl +%type > parameters param_list +%type parameter +%type type_expr +%type name_type +%type function_type +%type > type_expr_list type_expr_list_ne +%type scope +%type >> statements +%type statement +%type function_call +%type value_expr +%type > arguments arg_list %% -start: expr { - ast = new ast::nodes::Program(std::unique_ptr($1)); - $1 = nullptr; -} ; -expr: INT { - $$ = $1; - $1 = nullptr; +package + : %empty + { $$ = ast::nodes::Package(); } + | package[pkg] declaration[decl] + { $pkg.declarations.push_back(std::move($decl)); $$ = std::move($pkg); } + ; + +declaration + : function_decl[fd] + { $$ = ast::nodes::Declaration(std::move($fd)); } + ; + +function_decl + : type_expr[return_type] IDENT[name] LPAREN parameters[params] RPAREN scope[body] + { + $$ = ast::nodes::FunctionDecl{ + std::move($name), + std::move($params), + std::move($return_type), + std::move($body), + false + }; + } + ; + +parameters + : %empty + { $$ = {}; } + | param_list[list] + { $$ = std::move($list); } + ; + +param_list + : parameter[p] + { $$ = {std::move($p)}; } + | param_list[list] COMMA parameter[p] + { $list.push_back(std::move($p)); $$ = std::move($list); } + ; + +parameter + : IDENT[name] type_expr[type] + { + $$ = ast::nodes::Parameter{ + std::make_unique(std::move($type)), + std::move($name) + }; + } + ; + +type_expr + : name_type[nt] + { $$ = ast::nodes::TypeExpression{ std::move($nt) }; } + ; + +// assumed syntax: Name or Name(T, U, ...) for generics +name_type + : IDENT[id] + { $$ = ast::nodes::NameType{ std::move($id), {} }; } + ; + +type_expr_list + : %empty + { $$ = {}; } + | type_expr_list_ne[list] + { $$ = std::move($list); } + ; + +type_expr_list_ne + : type_expr[t] + { $$ = {std::move($t)}; } + | type_expr_list_ne[list] COMMA type_expr[t] + { $list.push_back(std::move($t)); $$ = std::move($list); } + ; + +scope + : LCURLY statements[stmts] RCURLY + { + ast::nodes::Scope s; + s.statements = std::move($stmts); + $$ = std::move(s); + } + ; + +statements + : %empty + { $$ = {}; } + | statements[list] statement[stmt] SEMICOLON + { + $list.push_back(std::make_unique(std::move($stmt))); + $$ = std::move($list); + } + ; + +statement + : function_call[fc] + { $$ = ast::nodes::Statement{ std::move($fc) }; } + ; + +// value_expr left-recursion handles chained calls: foo(a)(b) +value_expr + : IDENT[id] + { $$ = ast::nodes::ValueExpr{ ast::nodes::ValueSymbol{ std::move($id) } }; } + | STRING[s] + { $$ = ast::nodes::ValueExpr{ ast::nodes::StringLiteral{ std::move($s) } }; } + | function_call[fc] + { $$ = ast::nodes::ValueExpr{ std::move($fc) }; } + ; + +function_call + : value_expr[callee] LPAREN arguments[args] RPAREN + { + $$ = ast::nodes::FunctionCall{ + std::make_unique(std::move($callee)), + std::move($args) + }; + } + ; + +arguments + : %empty + { $$ = {}; } + | arg_list[list] + { $$ = std::move($list); } + ; + +arg_list + : value_expr[v] + { $$ = {std::move($v)}; } + | arg_list[list] COMMA value_expr[v] + { $list.push_back(std::move($v)); $$ = std::move($list); } + ; -} -| expr PLUS expr { - $$ = new ast::nodes::ValueNode(ast::nodes::AddNode{ - std::unique_ptr($1), - std::unique_ptr($3), - }); - $1 = nullptr; - $3 = nullptr; -} -| LPAREN expr RPAREN { - $$ = $2; - $2 = nullptr; -} %% -void yy::Parser::error(const location& l, const std::string& m) { - std::cerr << "Error at " << l.begin.line << ":" << l.begin.column << ": " << m << "\n"; +void yy::Parser::error(const location_type& loc, const std::string& msg) { + std::cerr << loc.begin.line << ":" << loc.begin.column << ": " << msg << "\n"; } From 45ee436855069db67015b13b137e7dcc4d78b307 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 23 May 2026 19:18:12 +0200 Subject: [PATCH 016/154] format --- src/grammar/parser.y | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 5301560a..c3e4d056 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -14,9 +14,10 @@ } %code { - int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, - const char*& cursor, const char*& marker, const char* limit, - ast::nodes::Package*& ast); + int yylex( + yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, + const char*& cursor, const char*& marker, const char* limit, + ast::nodes::Package*& ast); } %param { const char*& cursor } From e0435b3c8438108fc285eb8b21b1808e576bbf1a Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 23 May 2026 19:42:16 +0200 Subject: [PATCH 017/154] print tree --- src/ast/evaluators/to_string.hpp | 207 ++++++++++++++++++++++++++++--- src/ast/nodes.hpp | 141 ++++++++++++++++++++- src/grammar/lexer.re | 3 + src/grammar/parser.y | 40 ++++-- src/main.cpp | 8 +- 5 files changed, 366 insertions(+), 33 deletions(-) diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index 0a25c3b3..854c5bb6 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -1,31 +1,200 @@ #pragma once #include "ast/nodes.hpp" +#include #include #include +#include namespace ast::evaluators { struct ToString { - std::string operator()(const nodes::Program& program) const { - // NOTE: can only visit variant types - return std::visit(*this, program.valueNode->data); - } - - std::string operator()(const nodes::ValueNode& node) const { - return std::visit(*this, node.data); - } - - std::string operator()(const nodes::IntNode& n) const { - return std::to_string(n.value); - } - - std::string operator()(const nodes::AddNode& n) const { - // NOTE: can only visit variant types,which is why we get data directly - std::string l = std::visit(*this, n.left->data); - std::string r = std::visit(*this, n.right->data); - return "(" + l + " + " + r + ")"; - } +std::string operator()(const nodes::StringLiteral& literal) const { + return formatNode("StringLiteral \"" + literal.data + "\"", {}); +} + +std::string operator()(const nodes::ValueSymbol& symbol) const { + return formatNode("ValueSymbol " + symbol.name, {}); +} + +std::string operator()(const nodes::FunctionCall& call) const { + std::vector children; + if (call.callee != nullptr) { + children.push_back(formatBranch("callee", render(*call.callee))); + } + + for (std::size_t i = 0; i < call.arguments.size(); ++i) { + children.push_back(formatBranch("argument[" + std::to_string(i) + "]", render(call.arguments[i]))); + } + + return formatNode("FunctionCall", children); +} + +std::string operator()(const nodes::NameType& type) const { + std::vector children; + for (std::size_t i = 0; i < type.generics.size(); ++i) { + children.push_back(formatBranch("generic[" + std::to_string(i) + "]", render(type.generics[i]))); + } + + return formatNode("NameType " + type.name, children); +} + +std::string operator()(const nodes::FunctionType& type) const { + std::vector children; + for (std::size_t i = 0; i < type.paramTypes.size(); ++i) { + children.push_back(formatBranch("paramType[" + std::to_string(i) + "]", render(type.paramTypes[i]))); + } + + if (type.returnType != nullptr) { + children.push_back(formatBranch("returnType", render(*type.returnType))); + } + + return formatNode("FunctionType", children); +} + +std::string operator()(const nodes::TypeExpression& expression) const { + return std::visit(*this, expression.data); +} + +std::string operator()(const nodes::Parameter& parameter) const { + std::vector children; + if (parameter.type != nullptr) { + children.push_back(formatBranch("type", render(*parameter.type))); + } + + return formatNode("Parameter " + parameter.name, children); +} + +std::string operator()(const nodes::Statement& statement) const { + return formatNode("Statement", {formatBranch("data", std::visit(*this, statement.data))}); +} + +std::string operator()(const nodes::Scope& scope) const { + std::vector children; + for (std::size_t i = 0; i < scope.statements.size(); ++i) { + if (scope.statements[i] != nullptr) { + children.push_back(formatBranch("statement[" + std::to_string(i) + "]", render(*scope.statements[i]))); + } + } + + return formatNode("Scope", children); +} + +std::string operator()(const nodes::FunctionDecl& declaration) const { + std::vector children; + children.push_back(formatLeaf("mutating", declaration.mutating ? "true" : "false")); + + for (std::size_t i = 0; i < declaration.parameters.size(); ++i) { + children.push_back(formatBranch("parameter[" + std::to_string(i) + "]", render(declaration.parameters[i]))); + } + + children.push_back(formatBranch("returnType", render(declaration.returnType))); + children.push_back(formatBranch("functionBody", render(declaration.functionBody))); + + return formatNode("FunctionDecl " + declaration.name, children); +} + +std::string operator()(const nodes::Declaration& declaration) const { + return std::visit(*this, declaration); +} + +std::string operator()(const nodes::Package& package) const { + std::vector children; + for (std::size_t i = 0; i < package.declarations.size(); ++i) { + children.push_back(formatBranch("declaration[" + std::to_string(i) + "]", render(package.declarations[i]))); + } + + return formatNode("Package", children); +} + +std::string operator()(const nodes::ValueExpr& expression) const { + return std::visit(*this, expression.data); +} + +private: +std::string render(const nodes::ValueExpr& expression) const { + return (*this)(expression); +} + +std::string render(const nodes::TypeExpression& expression) const { + return (*this)(expression); +} + +std::string render(const nodes::Parameter& parameter) const { + return (*this)(parameter); +} + +std::string render(const nodes::Statement& statement) const { + return (*this)(statement); +} + +std::string render(const nodes::Scope& scope) const { + return (*this)(scope); +} + +std::string render(const nodes::Declaration& declaration) const { + return (*this)(declaration); +} + +static std::string formatLeaf(const std::string& label, const std::string& value) { + return label + ": " + value; +} + +static std::string formatBranch(const std::string& label, const std::string& subtree) { + const std::vector lines = splitLines(subtree); + if (lines.empty()) { + return label; + } + + std::string result = label + ": " + lines.front(); + for (std::size_t i = 1; i < lines.size(); ++i) { + result += "\n " + lines[i]; + } + + return result; +} + +static std::string formatNode(const std::string& label, const std::vector& children) { + if (children.empty()) { + return label; + } + + std::string result = label; + for (std::size_t i = 0; i < children.size(); ++i) { + result += "\n"; + result += i + 1 == children.size() ? "`-- " : "|-- "; + result += indent(children[i], i + 1 == children.size() ? " " : "| "); + } + + return result; +} + +static std::string indent(const std::string& text, const std::string& prefix) { + const std::vector lines = splitLines(text); + if (lines.empty()) { + return {}; + } + + std::string result = lines.front(); + for (std::size_t i = 1; i < lines.size(); ++i) { + result += "\n" + prefix + lines[i]; + } + + return result; +} + +static std::vector splitLines(const std::string& text) { + std::istringstream input(text); + std::vector lines; + std::string line; + + while (std::getline(input, line)) { + lines.push_back(line); + } + + return lines; +} + }; } // namespace evaluators diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index f14d2933..23ffff7c 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -8,9 +8,17 @@ namespace ast::nodes { struct Statement; - struct TypeExpression; +template +std::unique_ptr clonePtr(const std::unique_ptr& ptr) { + if (ptr == nullptr) { + return nullptr; + } + + return std::make_unique(*ptr); +} + struct NameType { std::string name; std::vector generics; @@ -19,19 +27,47 @@ struct NameType { struct FunctionType { std::vector paramTypes; std::unique_ptr returnType; + + FunctionType() = default; + FunctionType(std::vector paramTypes, std::unique_ptr returnType); + FunctionType(const FunctionType& other); + FunctionType& operator=(const FunctionType& other); + FunctionType(FunctionType&&) noexcept = default; + FunctionType& operator=(FunctionType&&) noexcept = default; }; struct TypeExpression { std::variant data; + + TypeExpression() = default; + TypeExpression(std::variant data) : data(std::move(data)) {} + TypeExpression(const TypeExpression&) = default; + TypeExpression& operator=(const TypeExpression&) = default; + TypeExpression(TypeExpression&&) noexcept = default; + TypeExpression& operator=(TypeExpression&&) noexcept = default; }; struct Scope { std::vector> statements; + + Scope() = default; + Scope(const Scope& other); + Scope& operator=(const Scope& other); + Scope(Scope&&) noexcept = default; + Scope& operator=(Scope&&) noexcept = default; }; struct Parameter { std::unique_ptr type; std::string name; + + Parameter() = default; + Parameter(std::unique_ptr type, std::string name) + : type(std::move(type)), name(std::move(name)) {} + Parameter(const Parameter& other); + Parameter& operator=(const Parameter& other); + Parameter(Parameter&&) noexcept = default; + Parameter& operator=(Parameter&&) noexcept = default; }; struct FunctionDecl { @@ -40,6 +76,18 @@ struct FunctionDecl { TypeExpression returnType; Scope functionBody; bool mutating; + + FunctionDecl() = default; + FunctionDecl(std::string name, std::vector parameters, TypeExpression returnType, Scope functionBody, bool mutating) + : name(std::move(name)), + parameters(std::move(parameters)), + returnType(std::move(returnType)), + functionBody(std::move(functionBody)), + mutating(mutating) {} + FunctionDecl(const FunctionDecl&) = default; + FunctionDecl& operator=(const FunctionDecl&) = default; + FunctionDecl(FunctionDecl&&) noexcept = default; + FunctionDecl& operator=(FunctionDecl&&) noexcept = default; }; @@ -50,6 +98,13 @@ struct ValueExpr; struct FunctionCall { std::unique_ptr callee; std::vector arguments; + + FunctionCall() = default; + FunctionCall(std::unique_ptr callee, std::vector arguments); + FunctionCall(const FunctionCall& other); + FunctionCall& operator=(const FunctionCall& other); + FunctionCall(FunctionCall&&) noexcept = default; + FunctionCall& operator=(FunctionCall&&) noexcept = default; }; /// does not include quotes @@ -64,11 +119,25 @@ struct ValueSymbol { struct ValueExpr { /// decided not to distinguish between callable and objects, since not verifyable at parse time std::variant data; + + ValueExpr() = default; + ValueExpr(std::variant data) : data(std::move(data)) {} + ValueExpr(const ValueExpr&) = default; + ValueExpr& operator=(const ValueExpr&) = default; + ValueExpr(ValueExpr&&) noexcept = default; + ValueExpr& operator=(ValueExpr&&) noexcept = default; }; // end values struct Statement { std::variant data; + + Statement() = default; + Statement(std::variant data) : data(std::move(data)) {} + Statement(const Statement&) = default; + Statement& operator=(const Statement&) = default; + Statement(Statement&&) noexcept = default; + Statement& operator=(Statement&&) noexcept = default; }; using Declaration = std::variant; @@ -76,6 +145,76 @@ struct Package { std::vector declarations; explicit Package() : declarations() {} + Package(std::vector declarations) : declarations(std::move(declarations)) {} + Package(const Package&) = default; + Package& operator=(const Package&) = default; + Package(Package&&) noexcept = default; + Package& operator=(Package&&) noexcept = default; }; +inline FunctionType::FunctionType(const FunctionType& other) + : paramTypes(other.paramTypes), returnType(clonePtr(other.returnType)) {} + +inline FunctionType::FunctionType(std::vector paramTypes, std::unique_ptr returnType) + : paramTypes(std::move(paramTypes)), returnType(std::move(returnType)) {} + +inline FunctionType& FunctionType::operator=(const FunctionType& other) { + if (this == &other) { + return *this; + } + + paramTypes = other.paramTypes; + returnType = clonePtr(other.returnType); + return *this; +} + +inline Parameter::Parameter(const Parameter& other) + : type(clonePtr(other.type)), name(other.name) {} + +inline Parameter& Parameter::operator=(const Parameter& other) { + if (this == &other) { + return *this; + } + + type = clonePtr(other.type); + name = other.name; + return *this; +} + +inline FunctionCall::FunctionCall(const FunctionCall& other) + : callee(clonePtr(other.callee)), arguments(other.arguments) {} + +inline FunctionCall::FunctionCall(std::unique_ptr callee, std::vector arguments) + : callee(std::move(callee)), arguments(std::move(arguments)) {} + +inline FunctionCall& FunctionCall::operator=(const FunctionCall& other) { + if (this == &other) { + return *this; + } + + callee = clonePtr(other.callee); + arguments = other.arguments; + return *this; +} + +inline Scope::Scope(const Scope& other) { + statements.reserve(other.statements.size()); + for (const auto& statement : other.statements) { + statements.push_back(clonePtr(statement)); + } +} + +inline Scope& Scope::operator=(const Scope& other) { + if (this == &other) { + return *this; + } + + statements.clear(); + statements.reserve(other.statements.size()); + for (const auto& statement : other.statements) { + statements.push_back(clonePtr(statement)); + } + return *this; +} + } // namespace nodes diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 3ed3e5af..950a0cdc 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -50,6 +50,9 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, ")" { return yy::Parser::token::RPAREN; } "{" { return yy::Parser::token::LCURLY; } "}" { return yy::Parser::token::RCURLY; } + "," { return yy::Parser::token::COMMA; } + ":" { return yy::Parser::token::COLON; } + ";" { return yy::Parser::token::SEMICOLON; } ["] str_char* ["] { yylval->emplace(unescape(start+1, cursor-1)); return yy::Parser::token::STRING; } ident+ { yylval->emplace(toStr(start, cursor)); diff --git a/src/grammar/parser.y b/src/grammar/parser.y index c3e4d056..d645cb1c 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -52,9 +52,17 @@ package : %empty - { $$ = ast::nodes::Package(); } + { + $$ = ast::nodes::Package(); + ast = new ast::nodes::Package($$); + } | package[pkg] declaration[decl] - { $pkg.declarations.push_back(std::move($decl)); $$ = std::move($pkg); } + { + $pkg.declarations.push_back(std::move($decl)); + delete ast; + ast = new ast::nodes::Package($pkg); + $$ = std::move($pkg); + } ; declaration @@ -77,14 +85,17 @@ function_decl parameters : %empty - { $$ = {}; } + { $$ = std::vector(); } | param_list[list] { $$ = std::move($list); } ; param_list : parameter[p] - { $$ = {std::move($p)}; } + { + $$ = std::vector(); + $$.push_back(std::move($p)); + } | param_list[list] COMMA parameter[p] { $list.push_back(std::move($p)); $$ = std::move($list); } ; @@ -112,14 +123,17 @@ name_type type_expr_list : %empty - { $$ = {}; } + { $$ = std::vector(); } | type_expr_list_ne[list] { $$ = std::move($list); } ; type_expr_list_ne : type_expr[t] - { $$ = {std::move($t)}; } + { + $$ = std::vector(); + $$.push_back(std::move($t)); + } | type_expr_list_ne[list] COMMA type_expr[t] { $list.push_back(std::move($t)); $$ = std::move($list); } ; @@ -135,7 +149,12 @@ scope statements : %empty - { $$ = {}; } + { $$ = std::vector>(); } + | statements[list] statement[stmt] + { + $list.push_back(std::make_unique(std::move($stmt))); + $$ = std::move($list); + } | statements[list] statement[stmt] SEMICOLON { $list.push_back(std::make_unique(std::move($stmt))); @@ -170,14 +189,17 @@ function_call arguments : %empty - { $$ = {}; } + { $$ = std::vector(); } | arg_list[list] { $$ = std::move($list); } ; arg_list : value_expr[v] - { $$ = {std::move($v)}; } + { + $$ = std::vector(); + $$.push_back(std::move($v)); + } | arg_list[list] COMMA value_expr[v] { $list.push_back(std::move($v)); $$ = std::move($list); } ; diff --git a/src/main.cpp b/src/main.cpp index 630e9601..72a4ec4b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,7 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, const char*& cursor, const char*& marker, const char* limit, - ast::nodes::Program*& ast); + ast::nodes::Package*& ast); std::string readFile(const std::string& path) { std::ifstream file(path); @@ -18,18 +18,18 @@ std::string readFile(const std::string& path) { std::istreambuf_iterator()); } -int main(int argc, char** argv) { +int main() { std::string input = readFile("test-parser/main.zn"); const char* cursor = input.c_str(); const char* marker = cursor; const char* limit = cursor + input.size(); - ast::nodes::Program* ast = nullptr; + ast::nodes::Package* ast = nullptr; yy::Parser parser(cursor, marker, limit, ast); int res = parser.parse(); if (ast != nullptr) { - std::cout << std::visit(ast::evaluators::ToString {}, ast->valueNode->data); + std::cout << ast::evaluators::ToString {}(*ast) << '\n'; delete ast; } From 21c94a4c7c862dc105f3d99def2d5e85a67d45ea Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 23 May 2026 22:38:26 +0200 Subject: [PATCH 018/154] update --- src/ast/evaluators/to_string.hpp | 173 +++++++++++++++-------------- src/ast/nodes.hpp | 182 +++++++++---------------------- src/grammar/parser.y | 95 ++++++++-------- 3 files changed, 189 insertions(+), 261 deletions(-) diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index 854c5bb6..ddf12327 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -8,48 +8,117 @@ namespace ast::evaluators { +namespace detail::tree { + +inline std::vector splitLines(const std::string& text) { + std::istringstream input(text); + std::vector lines; + std::string line; + + while (std::getline(input, line)) { + lines.push_back(line); + } + + return lines; +} + +inline std::string indent(const std::string& text, const std::string& prefix) { + const std::vector lines = splitLines(text); + if (lines.empty()) { + return {}; + } + + std::string result = lines.front(); + for (std::size_t i = 1; i < lines.size(); ++i) { + result += "\n" + prefix + lines[i]; + } + + return result; +} + +inline std::string leaf(const std::string& label, const std::string& value) { + return label + ": " + value; +} + +inline std::string branch(const std::string& label, const std::string& subtree) { + const std::vector lines = splitLines(subtree); + if (lines.empty()) { + return label; + } + + std::string result = label + ": " + lines.front(); + for (std::size_t i = 1; i < lines.size(); ++i) { + result += "\n " + lines[i]; + } + + return result; +} + +inline std::string node(const std::string& label, const std::vector& children) { + if (children.empty()) { + return label; + } + + std::string result = label; + for (std::size_t i = 0; i < children.size(); ++i) { + result += "\n"; + result += i + 1 == children.size() ? "`-- " : "|-- "; + result += indent(children[i], i + 1 == children.size() ? " " : "| "); + } + + return result; +} + +} // namespace detail::tree + struct ToString { std::string operator()(const nodes::StringLiteral& literal) const { - return formatNode("StringLiteral \"" + literal.data + "\"", {}); + return detail::tree::node("StringLiteral \"" + literal.data + "\"", {}); } std::string operator()(const nodes::ValueSymbol& symbol) const { - return formatNode("ValueSymbol " + symbol.name, {}); + return detail::tree::node("ValueSymbol " + symbol.name, {}); } std::string operator()(const nodes::FunctionCall& call) const { std::vector children; if (call.callee != nullptr) { - children.push_back(formatBranch("callee", render(*call.callee))); + children.push_back(detail::tree::branch("callee", render(*call.callee))); } for (std::size_t i = 0; i < call.arguments.size(); ++i) { - children.push_back(formatBranch("argument[" + std::to_string(i) + "]", render(call.arguments[i]))); + if (call.arguments[i] != nullptr) { + children.push_back(detail::tree::branch("argument[" + std::to_string(i) + "]", render(*call.arguments[i]))); + } } - return formatNode("FunctionCall", children); + return detail::tree::node("FunctionCall", children); } std::string operator()(const nodes::NameType& type) const { std::vector children; for (std::size_t i = 0; i < type.generics.size(); ++i) { - children.push_back(formatBranch("generic[" + std::to_string(i) + "]", render(type.generics[i]))); + if (type.generics[i] != nullptr) { + children.push_back(detail::tree::branch("generic[" + std::to_string(i) + "]", render(*type.generics[i]))); + } } - return formatNode("NameType " + type.name, children); + return detail::tree::node("NameType " + type.name, children); } std::string operator()(const nodes::FunctionType& type) const { std::vector children; for (std::size_t i = 0; i < type.paramTypes.size(); ++i) { - children.push_back(formatBranch("paramType[" + std::to_string(i) + "]", render(type.paramTypes[i]))); + if (type.paramTypes[i] != nullptr) { + children.push_back(detail::tree::branch("paramType[" + std::to_string(i) + "]", render(*type.paramTypes[i]))); + } } if (type.returnType != nullptr) { - children.push_back(formatBranch("returnType", render(*type.returnType))); + children.push_back(detail::tree::branch("returnType", render(*type.returnType))); } - return formatNode("FunctionType", children); + return detail::tree::node("FunctionType", children); } std::string operator()(const nodes::TypeExpression& expression) const { @@ -59,39 +128,39 @@ std::string operator()(const nodes::TypeExpression& expression) const { std::string operator()(const nodes::Parameter& parameter) const { std::vector children; if (parameter.type != nullptr) { - children.push_back(formatBranch("type", render(*parameter.type))); + children.push_back(detail::tree::branch("type", render(*parameter.type))); } - return formatNode("Parameter " + parameter.name, children); + return detail::tree::node("Parameter " + parameter.name, children); } std::string operator()(const nodes::Statement& statement) const { - return formatNode("Statement", {formatBranch("data", std::visit(*this, statement.data))}); + return detail::tree::node("Statement", {detail::tree::branch("data", std::visit(*this, statement.data))}); } std::string operator()(const nodes::Scope& scope) const { std::vector children; for (std::size_t i = 0; i < scope.statements.size(); ++i) { if (scope.statements[i] != nullptr) { - children.push_back(formatBranch("statement[" + std::to_string(i) + "]", render(*scope.statements[i]))); + children.push_back(detail::tree::branch("statement[" + std::to_string(i) + "]", render(*scope.statements[i]))); } } - return formatNode("Scope", children); + return detail::tree::node("Scope", children); } std::string operator()(const nodes::FunctionDecl& declaration) const { std::vector children; - children.push_back(formatLeaf("mutating", declaration.mutating ? "true" : "false")); + children.push_back(detail::tree::leaf("mutating", declaration.mutating ? "true" : "false")); for (std::size_t i = 0; i < declaration.parameters.size(); ++i) { - children.push_back(formatBranch("parameter[" + std::to_string(i) + "]", render(declaration.parameters[i]))); + children.push_back(detail::tree::branch("parameter[" + std::to_string(i) + "]", render(declaration.parameters[i]))); } - children.push_back(formatBranch("returnType", render(declaration.returnType))); - children.push_back(formatBranch("functionBody", render(declaration.functionBody))); + children.push_back(detail::tree::branch("returnType", render(declaration.returnType))); + children.push_back(detail::tree::branch("functionBody", render(declaration.functionBody))); - return formatNode("FunctionDecl " + declaration.name, children); + return detail::tree::node("FunctionDecl " + declaration.name, children); } std::string operator()(const nodes::Declaration& declaration) const { @@ -101,10 +170,10 @@ std::string operator()(const nodes::Declaration& declaration) const { std::string operator()(const nodes::Package& package) const { std::vector children; for (std::size_t i = 0; i < package.declarations.size(); ++i) { - children.push_back(formatBranch("declaration[" + std::to_string(i) + "]", render(package.declarations[i]))); + children.push_back(detail::tree::branch("declaration[" + std::to_string(i) + "]", render(package.declarations[i]))); } - return formatNode("Package", children); + return detail::tree::node("Package", children); } std::string operator()(const nodes::ValueExpr& expression) const { @@ -135,66 +204,6 @@ std::string render(const nodes::Scope& scope) const { std::string render(const nodes::Declaration& declaration) const { return (*this)(declaration); } - -static std::string formatLeaf(const std::string& label, const std::string& value) { - return label + ": " + value; -} - -static std::string formatBranch(const std::string& label, const std::string& subtree) { - const std::vector lines = splitLines(subtree); - if (lines.empty()) { - return label; - } - - std::string result = label + ": " + lines.front(); - for (std::size_t i = 1; i < lines.size(); ++i) { - result += "\n " + lines[i]; - } - - return result; -} - -static std::string formatNode(const std::string& label, const std::vector& children) { - if (children.empty()) { - return label; - } - - std::string result = label; - for (std::size_t i = 0; i < children.size(); ++i) { - result += "\n"; - result += i + 1 == children.size() ? "`-- " : "|-- "; - result += indent(children[i], i + 1 == children.size() ? " " : "| "); - } - - return result; -} - -static std::string indent(const std::string& text, const std::string& prefix) { - const std::vector lines = splitLines(text); - if (lines.empty()) { - return {}; - } - - std::string result = lines.front(); - for (std::size_t i = 1; i < lines.size(); ++i) { - result += "\n" + prefix + lines[i]; - } - - return result; -} - -static std::vector splitLines(const std::string& text) { - std::istringstream input(text); - std::vector lines; - std::string line; - - while (std::getline(input, line)) { - lines.push_back(line); - } - - return lines; -} - }; } // namespace evaluators diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index 23ffff7c..a480128c 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -1,4 +1,5 @@ #pragma once + #include #include #include @@ -7,8 +8,9 @@ namespace ast::nodes { -struct Statement; struct TypeExpression; +struct ValueExpr; +struct Statement; template std::unique_ptr clonePtr(const std::unique_ptr& ptr) { @@ -19,55 +21,60 @@ std::unique_ptr clonePtr(const std::unique_ptr& ptr) { return std::make_unique(*ptr); } +template +std::vector> clonePtrVector(const std::vector>& items) { + std::vector> copies; + copies.reserve(items.size()); + for (const auto& item : items) { + copies.push_back(clonePtr(item)); + } + return copies; +} + struct NameType { std::string name; - std::vector generics; + std::vector> generics; + + NameType(std::string name, std::vector> generics) + : name(std::move(name)), generics(std::move(generics)) {} + NameType(const NameType& other) + : name(other.name), generics(clonePtrVector(other.generics)) {} }; struct FunctionType { - std::vector paramTypes; + std::vector> paramTypes; std::unique_ptr returnType; - FunctionType() = default; - FunctionType(std::vector paramTypes, std::unique_ptr returnType); - FunctionType(const FunctionType& other); - FunctionType& operator=(const FunctionType& other); - FunctionType(FunctionType&&) noexcept = default; - FunctionType& operator=(FunctionType&&) noexcept = default; + FunctionType(std::vector> paramTypes, std::unique_ptr returnType) + : paramTypes(std::move(paramTypes)), returnType(std::move(returnType)) {} + FunctionType(const FunctionType& other) + : paramTypes(clonePtrVector(other.paramTypes)), returnType(clonePtr(other.returnType)) {} }; struct TypeExpression { std::variant data; - TypeExpression() = default; - TypeExpression(std::variant data) : data(std::move(data)) {} - TypeExpression(const TypeExpression&) = default; - TypeExpression& operator=(const TypeExpression&) = default; - TypeExpression(TypeExpression&&) noexcept = default; - TypeExpression& operator=(TypeExpression&&) noexcept = default; + template + explicit TypeExpression(T value) : data(std::move(value)) {} }; struct Scope { std::vector> statements; - Scope() = default; - Scope(const Scope& other); - Scope& operator=(const Scope& other); - Scope(Scope&&) noexcept = default; - Scope& operator=(Scope&&) noexcept = default; + explicit Scope(std::vector> statements) + : statements(std::move(statements)) {} + Scope(const Scope& other) + : statements(clonePtrVector(other.statements)) {} }; struct Parameter { std::unique_ptr type; std::string name; - Parameter() = default; Parameter(std::unique_ptr type, std::string name) : type(std::move(type)), name(std::move(name)) {} - Parameter(const Parameter& other); - Parameter& operator=(const Parameter& other); - Parameter(Parameter&&) noexcept = default; - Parameter& operator=(Parameter&&) noexcept = default; + Parameter(const Parameter& other) + : type(clonePtr(other.type)), name(other.name) {} }; struct FunctionDecl { @@ -77,144 +84,57 @@ struct FunctionDecl { Scope functionBody; bool mutating; - FunctionDecl() = default; FunctionDecl(std::string name, std::vector parameters, TypeExpression returnType, Scope functionBody, bool mutating) : name(std::move(name)), parameters(std::move(parameters)), returnType(std::move(returnType)), functionBody(std::move(functionBody)), mutating(mutating) {} - FunctionDecl(const FunctionDecl&) = default; - FunctionDecl& operator=(const FunctionDecl&) = default; - FunctionDecl(FunctionDecl&&) noexcept = default; - FunctionDecl& operator=(FunctionDecl&&) noexcept = default; }; - - -// values -struct ValueExpr; - struct FunctionCall { - std::unique_ptr callee; - std::vector arguments; - - FunctionCall() = default; - FunctionCall(std::unique_ptr callee, std::vector arguments); - FunctionCall(const FunctionCall& other); - FunctionCall& operator=(const FunctionCall& other); - FunctionCall(FunctionCall&&) noexcept = default; - FunctionCall& operator=(FunctionCall&&) noexcept = default; + std::unique_ptr callee; + std::vector> arguments; + + FunctionCall(std::unique_ptr callee, std::vector> arguments) + : callee(std::move(callee)), arguments(std::move(arguments)) {} + FunctionCall(const FunctionCall& other) + : callee(clonePtr(other.callee)), arguments(clonePtrVector(other.arguments)) {} }; -/// does not include quotes struct StringLiteral { std::string data; + + explicit StringLiteral(std::string data) : data(std::move(data)) {} }; struct ValueSymbol { std::string name; + + explicit ValueSymbol(std::string name) : name(std::move(name)) {} }; struct ValueExpr { - /// decided not to distinguish between callable and objects, since not verifyable at parse time std::variant data; - ValueExpr() = default; - ValueExpr(std::variant data) : data(std::move(data)) {} - ValueExpr(const ValueExpr&) = default; - ValueExpr& operator=(const ValueExpr&) = default; - ValueExpr(ValueExpr&&) noexcept = default; - ValueExpr& operator=(ValueExpr&&) noexcept = default; + template + explicit ValueExpr(T value) : data(std::move(value)) {} }; -// end values struct Statement { std::variant data; - Statement() = default; - Statement(std::variant data) : data(std::move(data)) {} - Statement(const Statement&) = default; - Statement& operator=(const Statement&) = default; - Statement(Statement&&) noexcept = default; - Statement& operator=(Statement&&) noexcept = default; + template + explicit Statement(T value) : data(std::move(value)) {} }; using Declaration = std::variant; + struct Package { std::vector declarations; - explicit Package() : declarations() {} - Package(std::vector declarations) : declarations(std::move(declarations)) {} - Package(const Package&) = default; - Package& operator=(const Package&) = default; - Package(Package&&) noexcept = default; - Package& operator=(Package&&) noexcept = default; + explicit Package(std::vector declarations) + : declarations(std::move(declarations)) {} }; -inline FunctionType::FunctionType(const FunctionType& other) - : paramTypes(other.paramTypes), returnType(clonePtr(other.returnType)) {} - -inline FunctionType::FunctionType(std::vector paramTypes, std::unique_ptr returnType) - : paramTypes(std::move(paramTypes)), returnType(std::move(returnType)) {} - -inline FunctionType& FunctionType::operator=(const FunctionType& other) { - if (this == &other) { - return *this; - } - - paramTypes = other.paramTypes; - returnType = clonePtr(other.returnType); - return *this; -} - -inline Parameter::Parameter(const Parameter& other) - : type(clonePtr(other.type)), name(other.name) {} - -inline Parameter& Parameter::operator=(const Parameter& other) { - if (this == &other) { - return *this; - } - - type = clonePtr(other.type); - name = other.name; - return *this; -} - -inline FunctionCall::FunctionCall(const FunctionCall& other) - : callee(clonePtr(other.callee)), arguments(other.arguments) {} - -inline FunctionCall::FunctionCall(std::unique_ptr callee, std::vector arguments) - : callee(std::move(callee)), arguments(std::move(arguments)) {} - -inline FunctionCall& FunctionCall::operator=(const FunctionCall& other) { - if (this == &other) { - return *this; - } - - callee = clonePtr(other.callee); - arguments = other.arguments; - return *this; -} - -inline Scope::Scope(const Scope& other) { - statements.reserve(other.statements.size()); - for (const auto& statement : other.statements) { - statements.push_back(clonePtr(statement)); - } -} - -inline Scope& Scope::operator=(const Scope& other) { - if (this == &other) { - return *this; - } - - statements.clear(); - statements.reserve(other.statements.size()); - for (const auto& statement : other.statements) { - statements.push_back(clonePtr(statement)); - } - return *this; -} - -} // namespace nodes +} // namespace ast::nodes diff --git a/src/grammar/parser.y b/src/grammar/parser.y index d645cb1c..08ec1d84 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -32,54 +32,55 @@ %token ERROR // --- non-terminal types --- -%type package -%type declaration -%type function_decl +%type > package +%type > declaration +%type > function_decl %type > parameters param_list -%type parameter -%type type_expr -%type name_type -%type function_type -%type > type_expr_list type_expr_list_ne -%type scope +%type > parameter +%type > type_expr +%type > name_type +%type > function_type +%type >> type_expr_list type_expr_list_ne +%type > scope %type >> statements -%type statement -%type function_call -%type value_expr -%type > arguments arg_list +%type > statement +%type > function_call +%type > value_expr +%type >> arguments arg_list %% package : %empty { - $$ = ast::nodes::Package(); - ast = new ast::nodes::Package($$); + $$ = std::make_unique(std::vector()); + ast = new ast::nodes::Package(*$$); } | package[pkg] declaration[decl] { - $pkg.declarations.push_back(std::move($decl)); + auto declarations = std::move($pkg->declarations); + declarations.push_back(std::move(*$decl)); delete ast; - ast = new ast::nodes::Package($pkg); - $$ = std::move($pkg); + $$ = std::make_unique(std::move(declarations)); + ast = new ast::nodes::Package(*$$); } ; declaration : function_decl[fd] - { $$ = ast::nodes::Declaration(std::move($fd)); } + { $$ = std::make_unique(ast::nodes::Declaration(std::move(*$fd))); } ; function_decl : type_expr[return_type] IDENT[name] LPAREN parameters[params] RPAREN scope[body] { - $$ = ast::nodes::FunctionDecl{ + $$ = std::make_unique(ast::nodes::FunctionDecl( std::move($name), std::move($params), - std::move($return_type), - std::move($body), + std::move(*$return_type), + std::move(*$body), false - }; + )); } ; @@ -94,36 +95,36 @@ param_list : parameter[p] { $$ = std::vector(); - $$.push_back(std::move($p)); + $$.push_back(std::move(*$p)); } | param_list[list] COMMA parameter[p] - { $list.push_back(std::move($p)); $$ = std::move($list); } + { $list.push_back(std::move(*$p)); $$ = std::move($list); } ; parameter : IDENT[name] type_expr[type] { - $$ = ast::nodes::Parameter{ - std::make_unique(std::move($type)), + $$ = std::make_unique(ast::nodes::Parameter( + std::move($type), std::move($name) - }; + )); } ; type_expr : name_type[nt] - { $$ = ast::nodes::TypeExpression{ std::move($nt) }; } + { $$ = std::make_unique(ast::nodes::TypeExpression(std::move(*$nt))); } ; // assumed syntax: Name or Name(T, U, ...) for generics name_type : IDENT[id] - { $$ = ast::nodes::NameType{ std::move($id), {} }; } + { $$ = std::make_unique(ast::nodes::NameType(std::move($id), {})); } ; type_expr_list : %empty - { $$ = std::vector(); } + { $$ = std::vector>(); } | type_expr_list_ne[list] { $$ = std::move($list); } ; @@ -131,19 +132,17 @@ type_expr_list type_expr_list_ne : type_expr[t] { - $$ = std::vector(); - $$.push_back(std::move($t)); + $$ = std::vector>(); + $$.push_back(std::make_unique($t.take())); } | type_expr_list_ne[list] COMMA type_expr[t] - { $list.push_back(std::move($t)); $$ = std::move($list); } + { $list.push_back(std::make_unique($t.take())); $$ = std::move($list); } ; scope : LCURLY statements[stmts] RCURLY { - ast::nodes::Scope s; - s.statements = std::move($stmts); - $$ = std::move(s); + $$ = std::make_unique(ast::nodes::Scope(std::move($stmts))); } ; @@ -152,44 +151,44 @@ statements { $$ = std::vector>(); } | statements[list] statement[stmt] { - $list.push_back(std::make_unique(std::move($stmt))); + $list.push_back(std::move($stmt)); $$ = std::move($list); } | statements[list] statement[stmt] SEMICOLON { - $list.push_back(std::make_unique(std::move($stmt))); + $list.push_back(std::move($stmt)); $$ = std::move($list); } ; statement : function_call[fc] - { $$ = ast::nodes::Statement{ std::move($fc) }; } + { $$ = std::make_unique(ast::nodes::Statement(std::move(*$fc))); } ; // value_expr left-recursion handles chained calls: foo(a)(b) value_expr : IDENT[id] - { $$ = ast::nodes::ValueExpr{ ast::nodes::ValueSymbol{ std::move($id) } }; } + { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::ValueSymbol(std::move($id)))); } | STRING[s] - { $$ = ast::nodes::ValueExpr{ ast::nodes::StringLiteral{ std::move($s) } }; } + { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::StringLiteral(std::move($s)))); } | function_call[fc] - { $$ = ast::nodes::ValueExpr{ std::move($fc) }; } + { $$ = std::make_unique(ast::nodes::ValueExpr(std::move(*$fc))); } ; function_call : value_expr[callee] LPAREN arguments[args] RPAREN { - $$ = ast::nodes::FunctionCall{ - std::make_unique(std::move($callee)), + $$ = std::make_unique(ast::nodes::FunctionCall( + std::move($callee), std::move($args) - }; + )); } ; arguments : %empty - { $$ = std::vector(); } + { $$ = std::vector>(); } | arg_list[list] { $$ = std::move($list); } ; @@ -197,7 +196,7 @@ arguments arg_list : value_expr[v] { - $$ = std::vector(); + $$ = std::vector>(); $$.push_back(std::move($v)); } | arg_list[list] COMMA value_expr[v] From ffee9515e4f236fa122928674321077933e32c5f Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Mon, 25 May 2026 14:29:04 +0200 Subject: [PATCH 019/154] polish ascii tree --- src/ast/evaluators/to_string.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index ddf12327..9d67e787 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -62,8 +62,8 @@ inline std::string node(const std::string& label, const std::vector std::string result = label; for (std::size_t i = 0; i < children.size(); ++i) { result += "\n"; - result += i + 1 == children.size() ? "`-- " : "|-- "; - result += indent(children[i], i + 1 == children.size() ? " " : "| "); + result += i + 1 == children.size() ? "└── " : "├── "; + result += indent(children[i], i + 1 == children.size() ? " " : "│ "); } return result; From a7577f8025d4e7cf00b38d2fd0c0db1c21f4aeb9 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Mon, 25 May 2026 19:25:23 +0200 Subject: [PATCH 020/154] add ops + int float literals --- src/ast/evaluators/to_string.hpp | 30 +++++++++++++++++++++++++++ src/ast/nodes.hpp | 35 +++++++++++++++++++++++++++++++- src/grammar/lexer.re | 26 +++++++++++++++++++++++- src/grammar/parser.y | 34 ++++++++++++++++++++++++++++++- src/types/primitives.hpp | 18 ++++++++++++++++ test-parser/main.zn | 1 + 6 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 src/types/primitives.hpp diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index 9d67e787..f1f7b305 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -72,6 +72,14 @@ inline std::string node(const std::string& label, const std::vector } // namespace detail::tree struct ToString { +std::string operator()(const nodes::IntLiteral& literal) const { + return detail::tree::node("IntLiteral \"" + literal.data + "\"", {}); +} + +std::string operator()(const nodes::FloatLiteral& literal) const { + return detail::tree::node("FloatLiteral \"" + literal.data + "\"", {}); +} + std::string operator()(const nodes::StringLiteral& literal) const { return detail::tree::node("StringLiteral \"" + literal.data + "\"", {}); } @@ -80,6 +88,28 @@ std::string operator()(const nodes::ValueSymbol& symbol) const { return detail::tree::node("ValueSymbol " + symbol.name, {}); } +std::string operator()(const nodes::OperatorFlipCall& call) const { + std::vector children; + if (call.value != nullptr) { + children.push_back(detail::tree::branch("value", render(*call.value))); + } + + return detail::tree::node("OperatorCall", children); +} + +std::string operator()(const nodes::OperatorCall& call) const { + std::vector children; + children.push_back(detail::tree::branch("op", call.op)); + if (call.left != nullptr) { + children.push_back(detail::tree::branch("left", render(*call.left))); + } + if (call.right != nullptr) { + children.push_back(detail::tree::branch("right", render(*call.right))); + } + + return detail::tree::node("OperatorCall", children); +} + std::string operator()(const nodes::FunctionCall& call) const { std::vector children; if (call.callee != nullptr) { diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index a480128c..58f6b5fa 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -92,6 +92,27 @@ struct FunctionDecl { mutating(mutating) {} }; +/// The only unary operator +struct OperatorFlipCall { + std::unique_ptr value; + + OperatorFlipCall(std::unique_ptr value) + : value(std::move(value)) {} + OperatorFlipCall(const OperatorFlipCall& other) + : value(clonePtr(other.value)) {} +}; + +struct OperatorCall { + std::string op; + std::unique_ptr left; + std::unique_ptr right; + + OperatorCall(std::string op, std::unique_ptr left, std::unique_ptr right) + : op(std::move(op)), left(std::move(left)), right(std::move(right)) {} + OperatorCall(const OperatorCall& other) + : op(std::move(other.op)), left(clonePtr(other.left)), right(clonePtr(other.right)) {} +}; + struct FunctionCall { std::unique_ptr callee; std::vector> arguments; @@ -108,6 +129,18 @@ struct StringLiteral { explicit StringLiteral(std::string data) : data(std::move(data)) {} }; +struct IntLiteral { + std::string data; + + explicit IntLiteral(std::string data) : data(data) {} +}; + +struct FloatLiteral { + std::string data; + + explicit FloatLiteral(std::string data) : data(std::move(data)) {} +}; + struct ValueSymbol { std::string name; @@ -115,7 +148,7 @@ struct ValueSymbol { }; struct ValueExpr { - std::variant data; + std::variant data; template explicit ValueExpr(T value) : data(std::move(value)) {} diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 950a0cdc..f589d453 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -44,6 +44,16 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, nonascii = [\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]; ident = [a-zA-Z_] | nonascii; str_char = [^"\\] | "\\" [^]; + // Digit groups: plain or swiss-separated (e.g. 1'000'000) + digit = [0-9]; + digits = digit+; + sw_digits = digit{1,3} ("'" digit{3})*; // swiss thousands groups + + // INT: optional swiss grouping, no decimal point + // FLOAT: optional swiss grouping, mandatory decimal point + fractional digits + int_lit = sw_digits | digits; + float_lit = sw_digits "." digits | digits "." digits; + operator_ = "+" | "-" | "*" | "/"; [ \t\n]+ { continue; } "(" { return yy::Parser::token::LPAREN; } @@ -52,7 +62,21 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, "}" { return yy::Parser::token::RCURLY; } "," { return yy::Parser::token::COMMA; } ":" { return yy::Parser::token::COLON; } - ";" { return yy::Parser::token::SEMICOLON; } + + "~" { return yy::Parser::token::TILDE; } + + operator_ { + yylval->emplace(toStr(start, cursor)); + return yy::Parser::token::OPERATOR; + } + float_lit { + yylval->emplace(toStr(start, cursor)); + return yy::Parser::token::FLOAT; + } + int_lit { + yylval->emplace(toStr(start, cursor)); + return yy::Parser::token::INT; + } ["] str_char* ["] { yylval->emplace(unescape(start+1, cursor-1)); return yy::Parser::token::STRING; } ident+ { yylval->emplace(toStr(start, cursor)); diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 08ec1d84..55a44b86 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -28,7 +28,8 @@ // --- tokens --- %token LPAREN RPAREN LCURLY RCURLY %token COMMA COLON SEMICOLON -%token STRING IDENT +%token TILDE +%token STRING IDENT INT FLOAT OPERATOR %token ERROR // --- non-terminal types --- @@ -44,6 +45,8 @@ %type > scope %type >> statements %type > statement +%type > operator_call +%type > operator_flip_call %type > function_call %type > value_expr %type >> arguments arg_list @@ -170,10 +173,18 @@ statement value_expr : IDENT[id] { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::ValueSymbol(std::move($id)))); } + | INT[i] + { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::IntLiteral(std::move($i)))); } + | FLOAT[f] + { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::FloatLiteral(std::move($f)))); } | STRING[s] { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::StringLiteral(std::move($s)))); } | function_call[fc] { $$ = std::make_unique(ast::nodes::ValueExpr(std::move(*$fc))); } + | operator_call[op] + { $$ = std::make_unique(ast::nodes::ValueExpr(std::move(*$op))); } + | operator_flip_call[op_flip] + { $$ = std::make_unique(ast::nodes::ValueExpr(std::move(*$op_flip))); } ; function_call @@ -186,6 +197,27 @@ function_call } ; +operator_flip_call + : TILDE value_expr[value] + { + $$ = std::make_unique(ast::nodes::OperatorFlipCall( + std::move($value) + )); + } + ; + +operator_call + : value_expr[left] OPERATOR[op] value_expr[right] + { + $$ = std::make_unique(ast::nodes::OperatorCall( + std::move($op), + std::move($left), + std::move($right) + )); + } + ; + + arguments : %empty { $$ = std::vector>(); } diff --git a/src/types/primitives.hpp b/src/types/primitives.hpp new file mode 100644 index 00000000..aabeee5a --- /dev/null +++ b/src/types/primitives.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +using i64 = std::int64_t; +using f64 = double; + +inline bool try_build_i64(std::string_view s, i64& out) { + auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), out); + return ec == std::errc{} && ptr == s.data() + s.size(); +} + +inline bool try_build_f64(std::string_view s, f64& out) { + auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), out); + return ec == std::errc{} && ptr == s.data() + s.size(); +} diff --git a/test-parser/main.zn b/test-parser/main.zn index 13a02c2a..6a81b063 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,3 +1,4 @@ Void main() { print("hello") + print(1 + 1) } From b7b556dd682d07fb4b6613d1676076d17c26f319 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Mon, 25 May 2026 22:33:08 +0200 Subject: [PATCH 021/154] improve ops add parantheses --- src/ast/evaluators/to_string.hpp | 4 +++ src/ast/nodes.hpp | 14 +++++++-- src/grammar/lexer.re | 9 +++--- src/grammar/parser.y | 50 ++++++++++++++++++++++++++++++-- test-parser/main.zn | 2 +- 5 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index f1f7b305..4b4468e1 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -206,6 +206,10 @@ std::string operator()(const nodes::Package& package) const { return detail::tree::node("Package", children); } +std::string operator()(const nodes::ParenthizedValue& expression) const { + return std::visit(*this, expression.data->data); +} + std::string operator()(const nodes::ValueExpr& expression) const { return std::visit(*this, expression.data); } diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index 58f6b5fa..db3c43f6 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -147,11 +147,19 @@ struct ValueSymbol { explicit ValueSymbol(std::string name) : name(std::move(name)) {} }; +struct ParenthizedValue { + std::unique_ptr data; + + explicit ParenthizedValue(std::unique_ptr value) : data(std::move(value)) {} + ParenthizedValue(const ParenthizedValue& other) : data(clonePtr(other.data)) {} +}; + struct ValueExpr { - std::variant data; + std::variant data; - template - explicit ValueExpr(T value) : data(std::move(value)) {} + template + explicit ValueExpr(T value) : data(std::move(value)) {} + ValueExpr(const ValueExpr& other) : data(other.data) {} }; struct Statement { diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index f589d453..6904cced 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -53,7 +53,6 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, // FLOAT: optional swiss grouping, mandatory decimal point + fractional digits int_lit = sw_digits | digits; float_lit = sw_digits "." digits | digits "." digits; - operator_ = "+" | "-" | "*" | "/"; [ \t\n]+ { continue; } "(" { return yy::Parser::token::LPAREN; } @@ -65,10 +64,10 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, "~" { return yy::Parser::token::TILDE; } - operator_ { - yylval->emplace(toStr(start, cursor)); - return yy::Parser::token::OPERATOR; - } + "+" { yylval->emplace("+"); return yy::Parser::token::PLUS; } + "-" { yylval->emplace("-"); return yy::Parser::token::MINUS; } + "*" { yylval->emplace("*"); return yy::Parser::token::STAR; } + "/" { yylval->emplace("/"); return yy::Parser::token::SLASH; } float_lit { yylval->emplace(toStr(start, cursor)); return yy::Parser::token::FLOAT; diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 55a44b86..330e7027 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -29,9 +29,14 @@ %token LPAREN RPAREN LCURLY RCURLY %token COMMA COLON SEMICOLON %token TILDE -%token STRING IDENT INT FLOAT OPERATOR +%token STRING IDENT INT FLOAT %token ERROR +// --- associativity --- +%left PLUS MINUS +%left STAR SLASH +%right TILDE + // --- non-terminal types --- %type > package %type > declaration @@ -48,6 +53,7 @@ %type > operator_call %type > operator_flip_call %type > function_call +%type > parenthized_value %type > value_expr %type >> arguments arg_list @@ -185,6 +191,17 @@ value_expr { $$ = std::make_unique(ast::nodes::ValueExpr(std::move(*$op))); } | operator_flip_call[op_flip] { $$ = std::make_unique(ast::nodes::ValueExpr(std::move(*$op_flip))); } + | parenthized_value[pv] + { $$ = std::make_unique(ast::nodes::ValueExpr(std::move(*$pv))); } + ; + +parenthized_value + : LPAREN value_expr[val] RPAREN + { + $$ = std::make_unique( + ast::nodes::ParenthizedValue(std::move($val)) + ); + } ; function_call @@ -207,7 +224,31 @@ operator_flip_call ; operator_call - : value_expr[left] OPERATOR[op] value_expr[right] + : value_expr[left] PLUS[op] value_expr[right] + { + $$ = std::make_unique(ast::nodes::OperatorCall( + std::move($op), + std::move($left), + std::move($right) + )); + } + | value_expr[left] MINUS[op] value_expr[right] + { + $$ = std::make_unique(ast::nodes::OperatorCall( + std::move($op), + std::move($left), + std::move($right) + )); + } + | value_expr[left] STAR[op] value_expr[right] + { + $$ = std::make_unique(ast::nodes::OperatorCall( + std::move($op), + std::move($left), + std::move($right) + )); + } + | value_expr[left] SLASH[op] value_expr[right] { $$ = std::make_unique(ast::nodes::OperatorCall( std::move($op), @@ -237,6 +278,11 @@ arg_list %% +template +std::unique_ptr wrap(U&& val) { + return std::make_unique(std::forward(val)); +} + void yy::Parser::error(const location_type& loc, const std::string& msg) { std::cerr << loc.begin.line << ":" << loc.begin.column << ": " << msg << "\n"; } diff --git a/test-parser/main.zn b/test-parser/main.zn index 6a81b063..3d8ee586 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,4 +1,4 @@ Void main() { print("hello") - print(1 + 1) + print(1 + 1 + 3 + 4) } From 93161b2655abf616281c27c9829fa8c9bfc71066 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 10:10:10 +0200 Subject: [PATCH 022/154] add line-break --- src/grammar/lexer.re | 80 +++++++++++++++++++++++++++----------------- src/grammar/parser.y | 42 ++++++++++++++--------- src/main.cpp | 35 +++++++++---------- test-parser/main.zn | 6 ++-- 4 files changed, 96 insertions(+), 67 deletions(-) diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 6904cced..44f9898c 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -27,12 +27,18 @@ static std::string unescape(const char* b, const char* e) { return out; } -int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, +int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, const char*& cursor, const char*& marker, const char* limit, - ast::nodes::Package*&) { + ast::nodes::Package*&, int& line, const char*& line_start) { for (;;) { if (cursor >= limit) return 0; const char* start = cursor; + + yylloc->begin.line = line; + yylloc->begin.column = (int)(start - line_start) + 1; + + int tok = -1; + /*!re2c re2c:flags:utf-8 = 1; re2c:define:YYCTYPE = "char"; @@ -41,46 +47,60 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, re2c:define:YYMARKER = marker; re2c:yyfill:enable = 0; - nonascii = [\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]; - ident = [a-zA-Z_] | nonascii; - str_char = [^"\\] | "\\" [^]; - // Digit groups: plain or swiss-separated (e.g. 1'000'000) + nonascii = [\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]; + ident = [a-zA-Z_] | nonascii; + str_char = [^"\\] | "\\" [^]; digit = [0-9]; digits = digit+; - sw_digits = digit{1,3} ("'" digit{3})*; // swiss thousands groups - - // INT: optional swiss grouping, no decimal point - // FLOAT: optional swiss grouping, mandatory decimal point + fractional digits + sw_digits = digit{1,3} ("'" digit{3})*; int_lit = sw_digits | digits; float_lit = sw_digits "." digits | digits "." digits; - [ \t\n]+ { continue; } - "(" { return yy::Parser::token::LPAREN; } - ")" { return yy::Parser::token::RPAREN; } - "{" { return yy::Parser::token::LCURLY; } - "}" { return yy::Parser::token::RCURLY; } - "," { return yy::Parser::token::COMMA; } - ":" { return yy::Parser::token::COLON; } + [ \t]+ { continue; } + + [\r\n]+ { + for (const char* p = start; p < cursor; ++p) + if (*p == '\n') { ++line; line_start = p + 1; } + yylloc->end.line = line; + yylloc->end.column = (int)(cursor - line_start) + 1; + return yy::Parser::token::LINE_BREAK; + } - "~" { return yy::Parser::token::TILDE; } + "(" { tok = yy::Parser::token::LPAREN; goto done; } + ")" { tok = yy::Parser::token::RPAREN; goto done; } + "{" { tok = yy::Parser::token::LCURLY; goto done; } + "}" { tok = yy::Parser::token::RCURLY; goto done; } + "," { tok = yy::Parser::token::COMMA; goto done; } + ":" { tok = yy::Parser::token::COLON; goto done; } + "~" { tok = yy::Parser::token::TILDE; goto done; } - "+" { yylval->emplace("+"); return yy::Parser::token::PLUS; } - "-" { yylval->emplace("-"); return yy::Parser::token::MINUS; } - "*" { yylval->emplace("*"); return yy::Parser::token::STAR; } - "/" { yylval->emplace("/"); return yy::Parser::token::SLASH; } - float_lit { + "+" { yylval->emplace("+"); tok = yy::Parser::token::PLUS; goto done; } + "-" { yylval->emplace("-"); tok = yy::Parser::token::MINUS; goto done; } + "*" { yylval->emplace("*"); tok = yy::Parser::token::STAR; goto done; } + "/" { yylval->emplace("/"); tok = yy::Parser::token::SLASH; goto done; } + + float_lit { yylval->emplace(toStr(start, cursor)); - return yy::Parser::token::FLOAT; + tok = yy::Parser::token::FLOAT; goto done; } int_lit { yylval->emplace(toStr(start, cursor)); - return yy::Parser::token::INT; + tok = yy::Parser::token::INT; goto done; + } + ["] str_char* ["] { + yylval->emplace(unescape(start + 1, cursor - 1)); + tok = yy::Parser::token::STRING; goto done; } - ["] str_char* ["] { yylval->emplace(unescape(start+1, cursor-1)); - return yy::Parser::token::STRING; } - ident+ { yylval->emplace(toStr(start, cursor)); - return yy::Parser::token::IDENT; } - * { return yy::Parser::token::ERROR; } + ident+ { + yylval->emplace(toStr(start, cursor)); + tok = yy::Parser::token::IDENT; goto done; + } + * { tok = yy::Parser::token::ERROR; goto done; } */ + + done: + yylloc->end.line = line; + yylloc->end.column = (int)(cursor - line_start) + 1; + return tok; } } diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 330e7027..7eb5d549 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -4,6 +4,7 @@ %define api.value.type variant %define parse.error detailed %locations +%start package %code requires { #include "ast/.hpp" @@ -15,19 +16,21 @@ %code { int yylex( - yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, - const char*& cursor, const char*& marker, const char* limit, - ast::nodes::Package*& ast); + yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, + const char*& cursor, const char*& marker, const char* limit, + ast::nodes::Package*& ast, int& line, const char*& line_start); } %param { const char*& cursor } %param { const char*& marker } %param { const char* limit } %param { ast::nodes::Package*& ast } +%param { int& line } +%param { const char*& line_start } // --- tokens --- %token LPAREN RPAREN LCURLY RCURLY -%token COMMA COLON SEMICOLON +%token COMMA COLON LINE_BREAK %token TILDE %token STRING IDENT INT FLOAT %token ERROR @@ -39,6 +42,7 @@ // --- non-terminal types --- %type > package +%type > global_scope %type > declaration %type > function_decl %type > parameters param_list @@ -60,18 +64,29 @@ %% package - : %empty + : may_break global_scope[glb] may_break { - $$ = std::make_unique(std::vector()); + $$ = std::make_unique(std::move($glb)); ast = new ast::nodes::Package(*$$); } - | package[pkg] declaration[decl] + ; + +may_break + : %empty + | LINE_BREAK + ; + +global_scope + : declaration[decl] { - auto declarations = std::move($pkg->declarations); + auto declarations = std::vector(); declarations.push_back(std::move(*$decl)); - delete ast; - $$ = std::make_unique(std::move(declarations)); - ast = new ast::nodes::Package(*$$); + $$ = std::move(declarations); + } + | global_scope[glb] LINE_BREAK declaration[decl] + { + $glb.push_back(std::move(*$decl)); + $$ = std::move($glb); } ; @@ -163,11 +178,6 @@ statements $list.push_back(std::move($stmt)); $$ = std::move($list); } - | statements[list] statement[stmt] SEMICOLON - { - $list.push_back(std::move($stmt)); - $$ = std::move($list); - } ; statement diff --git a/src/main.cpp b/src/main.cpp index 72a4ec4b..9db2522f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,35 +3,36 @@ #include #include #include -#include -int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type*, +int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, const char*& cursor, const char*& marker, const char* limit, - ast::nodes::Package*& ast); + ast::nodes::Package*& ast, int& line, const char*& line_start); std::string readFile(const std::string& path) { - std::ifstream file(path); - if (!file.is_open()) - throw std::runtime_error("Could not open file: " + path); - - return std::string((std::istreambuf_iterator(file)), - std::istreambuf_iterator()); + std::ifstream file(path); + if (!file.is_open()) + throw std::runtime_error("Could not open file: " + path); + return std::string((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); } int main() { std::string input = readFile("test-parser/main.zn"); - const char* cursor = input.c_str(); - const char* marker = cursor; - const char* limit = cursor + input.size(); + + const char* cursor = input.c_str(); + const char* marker = cursor; + const char* limit = cursor + input.size(); + const char* line_start = cursor; + int line = 1; ast::nodes::Package* ast = nullptr; - - yy::Parser parser(cursor, marker, limit, ast); + + yy::Parser parser(cursor, marker, limit, ast, line, line_start); int res = parser.parse(); - + if (ast != nullptr) { - std::cout << ast::evaluators::ToString {}(*ast) << '\n'; + std::cout << ast::evaluators::ToString{}(*ast) << '\n'; delete ast; } - + return res; } diff --git a/test-parser/main.zn b/test-parser/main.zn index 3d8ee586..132bb773 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,4 +1,2 @@ -Void main() { - print("hello") - print(1 + 1 + 3 + 4) -} +Void main() { print("hello") print(1 + 1 + 3 + 4) } + From 582e3e9f675352e70e8862970a4fe33b26e41784 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 10:20:39 +0200 Subject: [PATCH 023/154] decided not to restrict linebreak --- src/grammar/lexer.re | 11 +---------- src/grammar/parser.y | 11 +++-------- test-parser/main.zn | 7 ++++++- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 44f9898c..50b0042d 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -56,16 +56,7 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, int_lit = sw_digits | digits; float_lit = sw_digits "." digits | digits "." digits; - [ \t]+ { continue; } - - [\r\n]+ { - for (const char* p = start; p < cursor; ++p) - if (*p == '\n') { ++line; line_start = p + 1; } - yylloc->end.line = line; - yylloc->end.column = (int)(cursor - line_start) + 1; - return yy::Parser::token::LINE_BREAK; - } - + [ \t\r\n]+ { continue; } "(" { tok = yy::Parser::token::LPAREN; goto done; } ")" { tok = yy::Parser::token::RPAREN; goto done; } "{" { tok = yy::Parser::token::LCURLY; goto done; } diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 7eb5d549..8359aa05 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -30,7 +30,7 @@ // --- tokens --- %token LPAREN RPAREN LCURLY RCURLY -%token COMMA COLON LINE_BREAK +%token COMMA COLON %token TILDE %token STRING IDENT INT FLOAT %token ERROR @@ -64,18 +64,13 @@ %% package - : may_break global_scope[glb] may_break + : global_scope[glb] { $$ = std::make_unique(std::move($glb)); ast = new ast::nodes::Package(*$$); } ; -may_break - : %empty - | LINE_BREAK - ; - global_scope : declaration[decl] { @@ -83,7 +78,7 @@ global_scope declarations.push_back(std::move(*$decl)); $$ = std::move(declarations); } - | global_scope[glb] LINE_BREAK declaration[decl] + | global_scope[glb] declaration[decl] { $glb.push_back(std::move(*$decl)); $$ = std::move($glb); diff --git a/test-parser/main.zn b/test-parser/main.zn index 132bb773..f54320f4 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,2 +1,7 @@ -Void main() { print("hello") print(1 + 1 + 3 + 4) } +Void main() { + print("hello") + + print(1 + 1 + 3 + 4) + +} From 4fd300d6eb693900ebae4ea06869f1895a5a4df4 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 11:19:50 +0200 Subject: [PATCH 024/154] add more value expressions --- src/ast/evaluators/to_string.hpp | 4 ++++ src/ast/nodes.hpp | 9 ++++++++- src/grammar/lexer.re | 2 ++ src/grammar/parser.y | 4 +++- test-parser/main.zn | 5 +---- test-parser/nextStep.zn | 7 +++++++ 6 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 test-parser/nextStep.zn diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index 4b4468e1..0aecfb9b 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -84,6 +84,10 @@ std::string operator()(const nodes::StringLiteral& literal) const { return detail::tree::node("StringLiteral \"" + literal.data + "\"", {}); } +std::string operator()(const nodes::PackageValueSymbol& symbol) const { + return detail::tree::node("PackageValueSymbol " + symbol.package + "$" + symbol.name, {}); +} + std::string operator()(const nodes::ValueSymbol& symbol) const { return detail::tree::node("ValueSymbol " + symbol.name, {}); } diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index db3c43f6..99975998 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -141,6 +141,13 @@ struct FloatLiteral { explicit FloatLiteral(std::string data) : data(std::move(data)) {} }; +struct PackageValueSymbol { + std::string name; + std::string package; + + explicit PackageValueSymbol(std::string name, std::string package) : name(std::move(name)), package(std::move(package)) {} +}; + struct ValueSymbol { std::string name; @@ -155,7 +162,7 @@ struct ParenthizedValue { }; struct ValueExpr { - std::variant data; + std::variant data; template explicit ValueExpr(T value) : data(std::move(value)) {} diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 50b0042d..b6b2f7d5 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -70,6 +70,8 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, "*" { yylval->emplace("*"); tok = yy::Parser::token::STAR; goto done; } "/" { yylval->emplace("/"); tok = yy::Parser::token::SLASH; goto done; } + "$" { tok = yy::Parser::token::DOLLAR; goto done; } + float_lit { yylval->emplace(toStr(start, cursor)); tok = yy::Parser::token::FLOAT; goto done; diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 8359aa05..191e9cf1 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -30,7 +30,7 @@ // --- tokens --- %token LPAREN RPAREN LCURLY RCURLY -%token COMMA COLON +%token COMMA COLON DOLLAR %token TILDE %token STRING IDENT INT FLOAT %token ERROR @@ -184,6 +184,8 @@ statement value_expr : IDENT[id] { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::ValueSymbol(std::move($id)))); } + | IDENT[pkg] DOLLAR IDENT[id] + { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::PackageValueSymbol(std::move($id), std::move($pkg)))); } | INT[i] { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::IntLiteral(std::move($i)))); } | FLOAT[f] diff --git a/test-parser/main.zn b/test-parser/main.zn index f54320f4..46bacfaf 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,7 +1,4 @@ Void main() { - print("hello") - - print(1 + 1 + 3 + 4) - + Std$print(1 + 1 + 3 + 4) } diff --git a/test-parser/nextStep.zn b/test-parser/nextStep.zn new file mode 100644 index 00000000..7afda325 --- /dev/null +++ b/test-parser/nextStep.zn @@ -0,0 +1,7 @@ +Void main() { + print("hello") + Std$print(1 + 1 + 3 + 4) + @Intrinsics$print("hello") + print(res.value) + print(res:getValue()) +} From daa34e3f965d3d04071cdcb0bec7589273c70921 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 11:42:20 +0200 Subject: [PATCH 025/154] use wrap helper --- src/grammar/parser.y | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 191e9cf1..0e120b64 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -19,6 +19,11 @@ yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, const char*& cursor, const char*& marker, const char* limit, ast::nodes::Package*& ast, int& line, const char*& line_start); + + template + std::unique_ptr wrap(Args&&... args) { + return std::make_unique(std::forward(args)...); + } } %param { const char*& cursor } @@ -87,7 +92,7 @@ global_scope declaration : function_decl[fd] - { $$ = std::make_unique(ast::nodes::Declaration(std::move(*$fd))); } + { $$ = wrap(std::move(*$fd)); } ; function_decl @@ -132,13 +137,13 @@ parameter type_expr : name_type[nt] - { $$ = std::make_unique(ast::nodes::TypeExpression(std::move(*$nt))); } + { $$ = wrap(std::move(*$nt)); } ; // assumed syntax: Name or Name(T, U, ...) for generics name_type : IDENT[id] - { $$ = std::make_unique(ast::nodes::NameType(std::move($id), {})); } + { $$ = wrap(std::move($id), std::vector>()); } ; type_expr_list @@ -161,7 +166,7 @@ type_expr_list_ne scope : LCURLY statements[stmts] RCURLY { - $$ = std::make_unique(ast::nodes::Scope(std::move($stmts))); + $$ = wrap(std::move($stmts)); } ; @@ -177,29 +182,29 @@ statements statement : function_call[fc] - { $$ = std::make_unique(ast::nodes::Statement(std::move(*$fc))); } + { $$ = wrap(std::move(*$fc)); } ; // value_expr left-recursion handles chained calls: foo(a)(b) value_expr : IDENT[id] - { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::ValueSymbol(std::move($id)))); } + { $$ = wrap(ast::nodes::ValueSymbol(std::move($id))); } | IDENT[pkg] DOLLAR IDENT[id] - { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::PackageValueSymbol(std::move($id), std::move($pkg)))); } + { $$ = wrap(ast::nodes::PackageValueSymbol(std::move($id), std::move($pkg))); } | INT[i] - { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::IntLiteral(std::move($i)))); } + { $$ = wrap(ast::nodes::IntLiteral(std::move($i))); } | FLOAT[f] - { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::FloatLiteral(std::move($f)))); } + { $$ = wrap(ast::nodes::FloatLiteral(std::move($f))); } | STRING[s] - { $$ = std::make_unique(ast::nodes::ValueExpr(ast::nodes::StringLiteral(std::move($s)))); } + { $$ = wrap(ast::nodes::StringLiteral(std::move($s))); } | function_call[fc] - { $$ = std::make_unique(ast::nodes::ValueExpr(std::move(*$fc))); } + { $$ = wrap(std::move(*$fc)); } | operator_call[op] - { $$ = std::make_unique(ast::nodes::ValueExpr(std::move(*$op))); } + { $$ = wrap(std::move(*$op)); } | operator_flip_call[op_flip] - { $$ = std::make_unique(ast::nodes::ValueExpr(std::move(*$op_flip))); } + { $$ = wrap(std::move(*$op_flip)); } | parenthized_value[pv] - { $$ = std::make_unique(ast::nodes::ValueExpr(std::move(*$pv))); } + { $$ = wrap(std::move(*$pv)); } ; parenthized_value @@ -285,11 +290,6 @@ arg_list %% -template -std::unique_ptr wrap(U&& val) { - return std::make_unique(std::forward(val)); -} - void yy::Parser::error(const location_type& loc, const std::string& msg) { std::cerr << loc.begin.line << ":" << loc.begin.column << ": " << msg << "\n"; } From c2a317f34ffd4595d39078881516dd78722aa084 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 15:05:00 +0200 Subject: [PATCH 026/154] use wrap for everything --- src/grammar/parser.y | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 0e120b64..b9692e95 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -98,13 +98,13 @@ declaration function_decl : type_expr[return_type] IDENT[name] LPAREN parameters[params] RPAREN scope[body] { - $$ = std::make_unique(ast::nodes::FunctionDecl( + $$ = wrap( std::move($name), std::move($params), std::move(*$return_type), std::move(*$body), false - )); + ); } ; @@ -128,10 +128,10 @@ param_list parameter : IDENT[name] type_expr[type] { - $$ = std::make_unique(ast::nodes::Parameter( + $$ = wrap( std::move($type), std::move($name) - )); + ); } ; @@ -219,54 +219,54 @@ parenthized_value function_call : value_expr[callee] LPAREN arguments[args] RPAREN { - $$ = std::make_unique(ast::nodes::FunctionCall( + $$ = wrap( std::move($callee), std::move($args) - )); + ); } ; operator_flip_call : TILDE value_expr[value] { - $$ = std::make_unique(ast::nodes::OperatorFlipCall( + $$ = wrap( std::move($value) - )); + ); } ; operator_call : value_expr[left] PLUS[op] value_expr[right] { - $$ = std::make_unique(ast::nodes::OperatorCall( + $$ = wrap( std::move($op), std::move($left), std::move($right) - )); + ); } | value_expr[left] MINUS[op] value_expr[right] { - $$ = std::make_unique(ast::nodes::OperatorCall( + $$ = wrap( std::move($op), std::move($left), std::move($right) - )); + ); } | value_expr[left] STAR[op] value_expr[right] { - $$ = std::make_unique(ast::nodes::OperatorCall( + $$ = wrap( std::move($op), std::move($left), std::move($right) - )); + ); } | value_expr[left] SLASH[op] value_expr[right] { - $$ = std::make_unique(ast::nodes::OperatorCall( + $$ = wrap( std::move($op), std::move($left), std::move($right) - )); + ); } ; From a8f40abab373f355915c7586388acc5cea8a89df Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 17:20:22 +0200 Subject: [PATCH 027/154] update --- src/ast/nodes2.hpp | 197 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 src/ast/nodes2.hpp diff --git a/src/ast/nodes2.hpp b/src/ast/nodes2.hpp new file mode 100644 index 00000000..b1e8abf3 --- /dev/null +++ b/src/ast/nodes2.hpp @@ -0,0 +1,197 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace ast::nodes { + +struct TypeExpression; +struct ValueExpr; +struct Statement; + +template +std::unique_ptr clonePtr(const std::unique_ptr& ptr) { + if (ptr == nullptr) { + return nullptr; + } + + return std::make_unique(*ptr); +} + +template +std::vector> clonePtrVector(const std::vector>& items) { + std::vector> copies; + copies.reserve(items.size()); + for (const auto& item : items) { + copies.push_back(clonePtr(item)); + } + return copies; +} + +#define NODE(name, ...) \ +struct name { \ + __VA_ARGS__ \ + name(name&&) = default; \ + name& operator=(name&&) = default; \ +} + +NODE(NameType , + std::string name; + std::vector> generics; + + NameType(std::string name, std::vector> generics) + : name(std::move(name)), generics(std::move(generics)) {} + NameType(const NameType& other) + : name(other.name), generics(clonePtrVector(other.generics)) {} +); + +NODE(FunctionType , + std::vector> paramTypes; + std::unique_ptr returnType; + + FunctionType(std::vector> paramTypes, std::unique_ptr returnType) + : paramTypes(std::move(paramTypes)), returnType(std::move(returnType)) {} + FunctionType(const FunctionType& other) + : paramTypes(clonePtrVector(other.paramTypes)), returnType(clonePtr(other.returnType)) {} +); + +NODE(TypeExpression , + std::variant data; + + template + explicit TypeExpression(T value) : data(std::move(value)) {} +); + +NODE(Scope , + std::vector> statements; + + explicit Scope(std::vector> statements) + : statements(std::move(statements)) {} + Scope(const Scope& other) + : statements(clonePtrVector(other.statements)) {} +); + +NODE(Parameter , + std::unique_ptr type; + std::string name; + + Parameter(std::unique_ptr type, std::string name) + : type(std::move(type)), name(std::move(name)) {} + Parameter(const Parameter& other) + : type(clonePtr(other.type)), name(other.name) {} +); + +NODE(FunctionDecl , + std::string name; + std::vector parameters; + TypeExpression returnType; + Scope functionBody; + bool mutating; + + FunctionDecl(std::string name, std::vector parameters, TypeExpression returnType, Scope functionBody, bool mutating) + : name(std::move(name)), + parameters(std::move(parameters)), + returnType(std::move(returnType)), + functionBody(std::move(functionBody)), + mutating(mutating) {} +); + +/// The only unary operator +NODE(OperatorFlipCall , + std::unique_ptr value; + + OperatorFlipCall(std::unique_ptr value) + : value(std::move(value)) {} + OperatorFlipCall(const OperatorFlipCall& other) + : value(clonePtr(other.value)) {} +); + +NODE(OperatorCall , + std::string op; + std::unique_ptr left; + std::unique_ptr right; + + OperatorCall(std::string op, std::unique_ptr left, std::unique_ptr right) + : op(std::move(op)), left(std::move(left)), right(std::move(right)) {} + OperatorCall(const OperatorCall& other) + : op(std::move(other.op)), left(clonePtr(other.left)), right(clonePtr(other.right)) {} +); + +NODE(FunctionCall , + std::unique_ptr callee; + std::vector> arguments; + + FunctionCall(std::unique_ptr callee, std::vector> arguments) + : callee(std::move(callee)), arguments(std::move(arguments)) {} + FunctionCall(const FunctionCall& other) + : callee(clonePtr(other.callee)), arguments(clonePtrVector(other.arguments)) {} +); + +NODE(StringLiteral , + std::string data; + + explicit StringLiteral(std::string data) : data(std::move(data)) {} +); + +NODE(IntLiteral , + std::string data; + + explicit IntLiteral(std::string data) : data(data) {} +); + +NODE(FloatLiteral , + std::string data; + + explicit FloatLiteral(std::string data) : data(std::move(data)) {} +); + +NODE(PackageValueSymbol , + std::string name; + std::string package; + + explicit PackageValueSymbol(std::string name, std::string package) : name(std::move(name)), package(std::move(package)) {} +); + +NODE(ValueSymbol , + std::string name; + + explicit ValueSymbol(std::string name) : name(std::move(name)) {} +); + +NODE(ParenthizedValue , + std::unique_ptr data; + + explicit ParenthizedValue(std::unique_ptr value) : data(std::move(value)) {} + ParenthizedValue(const ParenthizedValue& other) : data(clonePtr(other.data)) {} +); + +NODE(ValueExpr , + std::variant data; + + template + explicit ValueExpr(T value) : data(std::move(value)) {} + ValueExpr(const ValueExpr& other) : data(other.data) {} +); + +NODE(Statement , + std::variant data; + + template + explicit Statement(T value) : data(std::move(value)) {} +); + +using Declaration = std::variant; + +NODE(Package , + std::vector declarations; + + explicit Package(std::vector declarations) + : declarations(std::move(declarations)) {} +); + +#undef NODE + +} // namespace ast::nodes From 73c1f37600c470f61d50ccf2af30fa449dd1ebdc Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 20:13:30 +0200 Subject: [PATCH 028/154] update --- src/ast/nodes2.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ast/nodes2.hpp b/src/ast/nodes2.hpp index b1e8abf3..19c18ca3 100644 --- a/src/ast/nodes2.hpp +++ b/src/ast/nodes2.hpp @@ -63,6 +63,7 @@ NODE(TypeExpression , template explicit TypeExpression(T value) : data(std::move(value)) {} + TypeExpression(const TypeExpression& other) : data(other.data) {} ); NODE(Scope , From 4cd8a333c0fdaaecb8d8b75917334dd303964e17 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 20:18:48 +0200 Subject: [PATCH 029/154] update --- src/ast/nodes2.hpp | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/ast/nodes2.hpp b/src/ast/nodes2.hpp index 19c18ca3..c4de19ef 100644 --- a/src/ast/nodes2.hpp +++ b/src/ast/nodes2.hpp @@ -12,25 +12,6 @@ struct TypeExpression; struct ValueExpr; struct Statement; -template -std::unique_ptr clonePtr(const std::unique_ptr& ptr) { - if (ptr == nullptr) { - return nullptr; - } - - return std::make_unique(*ptr); -} - -template -std::vector> clonePtrVector(const std::vector>& items) { - std::vector> copies; - copies.reserve(items.size()); - for (const auto& item : items) { - copies.push_back(clonePtr(item)); - } - return copies; -} - #define NODE(name, ...) \ struct name { \ __VA_ARGS__ \ @@ -44,8 +25,6 @@ NODE(NameType , NameType(std::string name, std::vector> generics) : name(std::move(name)), generics(std::move(generics)) {} - NameType(const NameType& other) - : name(other.name), generics(clonePtrVector(other.generics)) {} ); NODE(FunctionType , @@ -54,8 +33,6 @@ NODE(FunctionType , FunctionType(std::vector> paramTypes, std::unique_ptr returnType) : paramTypes(std::move(paramTypes)), returnType(std::move(returnType)) {} - FunctionType(const FunctionType& other) - : paramTypes(clonePtrVector(other.paramTypes)), returnType(clonePtr(other.returnType)) {} ); NODE(TypeExpression , @@ -63,7 +40,6 @@ NODE(TypeExpression , template explicit TypeExpression(T value) : data(std::move(value)) {} - TypeExpression(const TypeExpression& other) : data(other.data) {} ); NODE(Scope , @@ -71,8 +47,6 @@ NODE(Scope , explicit Scope(std::vector> statements) : statements(std::move(statements)) {} - Scope(const Scope& other) - : statements(clonePtrVector(other.statements)) {} ); NODE(Parameter , @@ -81,8 +55,6 @@ NODE(Parameter , Parameter(std::unique_ptr type, std::string name) : type(std::move(type)), name(std::move(name)) {} - Parameter(const Parameter& other) - : type(clonePtr(other.type)), name(other.name) {} ); NODE(FunctionDecl , @@ -106,8 +78,6 @@ NODE(OperatorFlipCall , OperatorFlipCall(std::unique_ptr value) : value(std::move(value)) {} - OperatorFlipCall(const OperatorFlipCall& other) - : value(clonePtr(other.value)) {} ); NODE(OperatorCall , @@ -117,8 +87,6 @@ NODE(OperatorCall , OperatorCall(std::string op, std::unique_ptr left, std::unique_ptr right) : op(std::move(op)), left(std::move(left)), right(std::move(right)) {} - OperatorCall(const OperatorCall& other) - : op(std::move(other.op)), left(clonePtr(other.left)), right(clonePtr(other.right)) {} ); NODE(FunctionCall , @@ -127,8 +95,6 @@ NODE(FunctionCall , FunctionCall(std::unique_ptr callee, std::vector> arguments) : callee(std::move(callee)), arguments(std::move(arguments)) {} - FunctionCall(const FunctionCall& other) - : callee(clonePtr(other.callee)), arguments(clonePtrVector(other.arguments)) {} ); NODE(StringLiteral , @@ -166,7 +132,6 @@ NODE(ParenthizedValue , std::unique_ptr data; explicit ParenthizedValue(std::unique_ptr value) : data(std::move(value)) {} - ParenthizedValue(const ParenthizedValue& other) : data(clonePtr(other.data)) {} ); NODE(ValueExpr , @@ -174,7 +139,6 @@ NODE(ValueExpr , template explicit ValueExpr(T value) : data(std::move(value)) {} - ValueExpr(const ValueExpr& other) : data(other.data) {} ); NODE(Statement , From b12ff0dc5502b4ba92954b15aff6e0db6662918d Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 20:23:04 +0200 Subject: [PATCH 030/154] update --- src/ast/nodes.hpp | 140 ++++++++++++++++++------------------------- src/ast/nodes2.hpp | 140 +++++++++++++++++++++++++------------------ src/grammar/parser.y | 61 ++++--------------- 3 files changed, 152 insertions(+), 189 deletions(-) diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index 99975998..c4de19ef 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -12,72 +12,52 @@ struct TypeExpression; struct ValueExpr; struct Statement; -template -std::unique_ptr clonePtr(const std::unique_ptr& ptr) { - if (ptr == nullptr) { - return nullptr; - } - - return std::make_unique(*ptr); -} - -template -std::vector> clonePtrVector(const std::vector>& items) { - std::vector> copies; - copies.reserve(items.size()); - for (const auto& item : items) { - copies.push_back(clonePtr(item)); - } - return copies; +#define NODE(name, ...) \ +struct name { \ + __VA_ARGS__ \ + name(name&&) = default; \ + name& operator=(name&&) = default; \ } -struct NameType { +NODE(NameType , std::string name; std::vector> generics; NameType(std::string name, std::vector> generics) - : name(std::move(name)), generics(std::move(generics)) {} - NameType(const NameType& other) - : name(other.name), generics(clonePtrVector(other.generics)) {} -}; + : name(std::move(name)), generics(std::move(generics)) {} +); -struct FunctionType { +NODE(FunctionType , std::vector> paramTypes; std::unique_ptr returnType; FunctionType(std::vector> paramTypes, std::unique_ptr returnType) - : paramTypes(std::move(paramTypes)), returnType(std::move(returnType)) {} - FunctionType(const FunctionType& other) - : paramTypes(clonePtrVector(other.paramTypes)), returnType(clonePtr(other.returnType)) {} -}; + : paramTypes(std::move(paramTypes)), returnType(std::move(returnType)) {} +); -struct TypeExpression { +NODE(TypeExpression , std::variant data; template explicit TypeExpression(T value) : data(std::move(value)) {} -}; +); -struct Scope { +NODE(Scope , std::vector> statements; explicit Scope(std::vector> statements) - : statements(std::move(statements)) {} - Scope(const Scope& other) - : statements(clonePtrVector(other.statements)) {} -}; + : statements(std::move(statements)) {} +); -struct Parameter { +NODE(Parameter , std::unique_ptr type; std::string name; Parameter(std::unique_ptr type, std::string name) - : type(std::move(type)), name(std::move(name)) {} - Parameter(const Parameter& other) - : type(clonePtr(other.type)), name(other.name) {} -}; + : type(std::move(type)), name(std::move(name)) {} +); -struct FunctionDecl { +NODE(FunctionDecl , std::string name; std::vector parameters; TypeExpression returnType; @@ -86,103 +66,97 @@ struct FunctionDecl { FunctionDecl(std::string name, std::vector parameters, TypeExpression returnType, Scope functionBody, bool mutating) : name(std::move(name)), - parameters(std::move(parameters)), - returnType(std::move(returnType)), - functionBody(std::move(functionBody)), - mutating(mutating) {} -}; + parameters(std::move(parameters)), + returnType(std::move(returnType)), + functionBody(std::move(functionBody)), + mutating(mutating) {} +); /// The only unary operator -struct OperatorFlipCall { +NODE(OperatorFlipCall , std::unique_ptr value; OperatorFlipCall(std::unique_ptr value) - : value(std::move(value)) {} - OperatorFlipCall(const OperatorFlipCall& other) - : value(clonePtr(other.value)) {} -}; + : value(std::move(value)) {} +); -struct OperatorCall { +NODE(OperatorCall , std::string op; std::unique_ptr left; std::unique_ptr right; OperatorCall(std::string op, std::unique_ptr left, std::unique_ptr right) - : op(std::move(op)), left(std::move(left)), right(std::move(right)) {} - OperatorCall(const OperatorCall& other) - : op(std::move(other.op)), left(clonePtr(other.left)), right(clonePtr(other.right)) {} -}; + : op(std::move(op)), left(std::move(left)), right(std::move(right)) {} +); -struct FunctionCall { +NODE(FunctionCall , std::unique_ptr callee; std::vector> arguments; FunctionCall(std::unique_ptr callee, std::vector> arguments) - : callee(std::move(callee)), arguments(std::move(arguments)) {} - FunctionCall(const FunctionCall& other) - : callee(clonePtr(other.callee)), arguments(clonePtrVector(other.arguments)) {} -}; + : callee(std::move(callee)), arguments(std::move(arguments)) {} +); -struct StringLiteral { +NODE(StringLiteral , std::string data; explicit StringLiteral(std::string data) : data(std::move(data)) {} -}; +); -struct IntLiteral { +NODE(IntLiteral , std::string data; explicit IntLiteral(std::string data) : data(data) {} -}; +); -struct FloatLiteral { +NODE(FloatLiteral , std::string data; explicit FloatLiteral(std::string data) : data(std::move(data)) {} -}; +); -struct PackageValueSymbol { +NODE(PackageValueSymbol , std::string name; std::string package; explicit PackageValueSymbol(std::string name, std::string package) : name(std::move(name)), package(std::move(package)) {} -}; +); -struct ValueSymbol { +NODE(ValueSymbol , std::string name; explicit ValueSymbol(std::string name) : name(std::move(name)) {} -}; +); -struct ParenthizedValue { +NODE(ParenthizedValue , std::unique_ptr data; explicit ParenthizedValue(std::unique_ptr value) : data(std::move(value)) {} - ParenthizedValue(const ParenthizedValue& other) : data(clonePtr(other.data)) {} -}; +); -struct ValueExpr { +NODE(ValueExpr , std::variant data; - template - explicit ValueExpr(T value) : data(std::move(value)) {} - ValueExpr(const ValueExpr& other) : data(other.data) {} -}; + template + explicit ValueExpr(T value) : data(std::move(value)) {} +); -struct Statement { +NODE(Statement , std::variant data; template explicit Statement(T value) : data(std::move(value)) {} -}; +); using Declaration = std::variant; -struct Package { +NODE(Package , std::vector declarations; explicit Package(std::vector declarations) - : declarations(std::move(declarations)) {} -}; + : declarations(std::move(declarations)) {} +); + +#undef NODE } // namespace ast::nodes diff --git a/src/ast/nodes2.hpp b/src/ast/nodes2.hpp index c4de19ef..99975998 100644 --- a/src/ast/nodes2.hpp +++ b/src/ast/nodes2.hpp @@ -12,52 +12,72 @@ struct TypeExpression; struct ValueExpr; struct Statement; -#define NODE(name, ...) \ -struct name { \ - __VA_ARGS__ \ - name(name&&) = default; \ - name& operator=(name&&) = default; \ +template +std::unique_ptr clonePtr(const std::unique_ptr& ptr) { + if (ptr == nullptr) { + return nullptr; + } + + return std::make_unique(*ptr); +} + +template +std::vector> clonePtrVector(const std::vector>& items) { + std::vector> copies; + copies.reserve(items.size()); + for (const auto& item : items) { + copies.push_back(clonePtr(item)); + } + return copies; } -NODE(NameType , +struct NameType { std::string name; std::vector> generics; NameType(std::string name, std::vector> generics) - : name(std::move(name)), generics(std::move(generics)) {} -); + : name(std::move(name)), generics(std::move(generics)) {} + NameType(const NameType& other) + : name(other.name), generics(clonePtrVector(other.generics)) {} +}; -NODE(FunctionType , +struct FunctionType { std::vector> paramTypes; std::unique_ptr returnType; FunctionType(std::vector> paramTypes, std::unique_ptr returnType) - : paramTypes(std::move(paramTypes)), returnType(std::move(returnType)) {} -); + : paramTypes(std::move(paramTypes)), returnType(std::move(returnType)) {} + FunctionType(const FunctionType& other) + : paramTypes(clonePtrVector(other.paramTypes)), returnType(clonePtr(other.returnType)) {} +}; -NODE(TypeExpression , +struct TypeExpression { std::variant data; template explicit TypeExpression(T value) : data(std::move(value)) {} -); +}; -NODE(Scope , +struct Scope { std::vector> statements; explicit Scope(std::vector> statements) - : statements(std::move(statements)) {} -); + : statements(std::move(statements)) {} + Scope(const Scope& other) + : statements(clonePtrVector(other.statements)) {} +}; -NODE(Parameter , +struct Parameter { std::unique_ptr type; std::string name; Parameter(std::unique_ptr type, std::string name) - : type(std::move(type)), name(std::move(name)) {} -); + : type(std::move(type)), name(std::move(name)) {} + Parameter(const Parameter& other) + : type(clonePtr(other.type)), name(other.name) {} +}; -NODE(FunctionDecl , +struct FunctionDecl { std::string name; std::vector parameters; TypeExpression returnType; @@ -66,97 +86,103 @@ NODE(FunctionDecl , FunctionDecl(std::string name, std::vector parameters, TypeExpression returnType, Scope functionBody, bool mutating) : name(std::move(name)), - parameters(std::move(parameters)), - returnType(std::move(returnType)), - functionBody(std::move(functionBody)), - mutating(mutating) {} -); + parameters(std::move(parameters)), + returnType(std::move(returnType)), + functionBody(std::move(functionBody)), + mutating(mutating) {} +}; /// The only unary operator -NODE(OperatorFlipCall , +struct OperatorFlipCall { std::unique_ptr value; OperatorFlipCall(std::unique_ptr value) - : value(std::move(value)) {} -); + : value(std::move(value)) {} + OperatorFlipCall(const OperatorFlipCall& other) + : value(clonePtr(other.value)) {} +}; -NODE(OperatorCall , +struct OperatorCall { std::string op; std::unique_ptr left; std::unique_ptr right; OperatorCall(std::string op, std::unique_ptr left, std::unique_ptr right) - : op(std::move(op)), left(std::move(left)), right(std::move(right)) {} -); + : op(std::move(op)), left(std::move(left)), right(std::move(right)) {} + OperatorCall(const OperatorCall& other) + : op(std::move(other.op)), left(clonePtr(other.left)), right(clonePtr(other.right)) {} +}; -NODE(FunctionCall , +struct FunctionCall { std::unique_ptr callee; std::vector> arguments; FunctionCall(std::unique_ptr callee, std::vector> arguments) - : callee(std::move(callee)), arguments(std::move(arguments)) {} -); + : callee(std::move(callee)), arguments(std::move(arguments)) {} + FunctionCall(const FunctionCall& other) + : callee(clonePtr(other.callee)), arguments(clonePtrVector(other.arguments)) {} +}; -NODE(StringLiteral , +struct StringLiteral { std::string data; explicit StringLiteral(std::string data) : data(std::move(data)) {} -); +}; -NODE(IntLiteral , +struct IntLiteral { std::string data; explicit IntLiteral(std::string data) : data(data) {} -); +}; -NODE(FloatLiteral , +struct FloatLiteral { std::string data; explicit FloatLiteral(std::string data) : data(std::move(data)) {} -); +}; -NODE(PackageValueSymbol , +struct PackageValueSymbol { std::string name; std::string package; explicit PackageValueSymbol(std::string name, std::string package) : name(std::move(name)), package(std::move(package)) {} -); +}; -NODE(ValueSymbol , +struct ValueSymbol { std::string name; explicit ValueSymbol(std::string name) : name(std::move(name)) {} -); +}; -NODE(ParenthizedValue , +struct ParenthizedValue { std::unique_ptr data; explicit ParenthizedValue(std::unique_ptr value) : data(std::move(value)) {} -); + ParenthizedValue(const ParenthizedValue& other) : data(clonePtr(other.data)) {} +}; -NODE(ValueExpr , +struct ValueExpr { std::variant data; - template - explicit ValueExpr(T value) : data(std::move(value)) {} -); + template + explicit ValueExpr(T value) : data(std::move(value)) {} + ValueExpr(const ValueExpr& other) : data(other.data) {} +}; -NODE(Statement , +struct Statement { std::variant data; template explicit Statement(T value) : data(std::move(value)) {} -); +}; using Declaration = std::variant; -NODE(Package , +struct Package { std::vector declarations; explicit Package(std::vector declarations) - : declarations(std::move(declarations)) {} -); - -#undef NODE + : declarations(std::move(declarations)) {} +}; } // namespace ast::nodes diff --git a/src/grammar/parser.y b/src/grammar/parser.y index b9692e95..35d9a9a7 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -21,7 +21,7 @@ ast::nodes::Package*& ast, int& line, const char*& line_start); template - std::unique_ptr wrap(Args&&... args) { + std::unique_ptr wrap(Args&&... args) { return std::make_unique(std::forward(args)...); } } @@ -72,12 +72,12 @@ package : global_scope[glb] { $$ = std::make_unique(std::move($glb)); - ast = new ast::nodes::Package(*$$); + ast = $$.release(); // fix: was copying with *$$ } ; global_scope - : declaration[decl] + : declaration[decl] { auto declarations = std::vector(); declarations.push_back(std::move(*$decl)); @@ -140,7 +140,6 @@ type_expr { $$ = wrap(std::move(*$nt)); } ; -// assumed syntax: Name or Name(T, U, ...) for generics name_type : IDENT[id] { $$ = wrap(std::move($id), std::vector>()); } @@ -157,17 +156,15 @@ type_expr_list_ne : type_expr[t] { $$ = std::vector>(); - $$.push_back(std::make_unique($t.take())); + $$.push_back(std::move($t)); // fix: was $t.take() + redundant make_unique } | type_expr_list_ne[list] COMMA type_expr[t] - { $list.push_back(std::make_unique($t.take())); $$ = std::move($list); } + { $list.push_back(std::move($t)); $$ = std::move($list); } ; scope : LCURLY statements[stmts] RCURLY - { - $$ = wrap(std::move($stmts)); - } + { $$ = wrap(std::move($stmts)); } ; statements @@ -185,7 +182,6 @@ statement { $$ = wrap(std::move(*$fc)); } ; -// value_expr left-recursion handles chained calls: foo(a)(b) value_expr : IDENT[id] { $$ = wrap(ast::nodes::ValueSymbol(std::move($id))); } @@ -209,11 +205,7 @@ value_expr parenthized_value : LPAREN value_expr[val] RPAREN - { - $$ = std::make_unique( - ast::nodes::ParenthizedValue(std::move($val)) - ); - } + { $$ = wrap(std::move($val)); } // fix: was constructing twice ; function_call @@ -228,49 +220,20 @@ function_call operator_flip_call : TILDE value_expr[value] - { - $$ = wrap( - std::move($value) - ); - } + { $$ = wrap(std::move($value)); } ; operator_call : value_expr[left] PLUS[op] value_expr[right] - { - $$ = wrap( - std::move($op), - std::move($left), - std::move($right) - ); - } + { $$ = wrap(std::move($op), std::move($left), std::move($right)); } | value_expr[left] MINUS[op] value_expr[right] - { - $$ = wrap( - std::move($op), - std::move($left), - std::move($right) - ); - } + { $$ = wrap(std::move($op), std::move($left), std::move($right)); } | value_expr[left] STAR[op] value_expr[right] - { - $$ = wrap( - std::move($op), - std::move($left), - std::move($right) - ); - } + { $$ = wrap(std::move($op), std::move($left), std::move($right)); } | value_expr[left] SLASH[op] value_expr[right] - { - $$ = wrap( - std::move($op), - std::move($left), - std::move($right) - ); - } + { $$ = wrap(std::move($op), std::move($left), std::move($right)); } ; - arguments : %empty { $$ = std::vector>(); } From 89822ddb0fcbb736544f7ba5e71e6c62c69b517f Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 20:47:15 +0200 Subject: [PATCH 031/154] update --- src/ast/evaluators/to_string.hpp | 9 ++- src/ast/nodes.hpp | 23 +++--- src/grammar/lexer.re | 1 + src/grammar/parser.y | 123 ++++++++++++++++--------------- 4 files changed, 83 insertions(+), 73 deletions(-) diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index 0aecfb9b..d26b908f 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -142,10 +142,11 @@ std::string operator()(const nodes::NameType& type) const { std::string operator()(const nodes::FunctionType& type) const { std::vector children; - for (std::size_t i = 0; i < type.paramTypes.size(); ++i) { - if (type.paramTypes[i] != nullptr) { - children.push_back(detail::tree::branch("paramType[" + std::to_string(i) + "]", render(*type.paramTypes[i]))); - } + for (std::size_t i = 0; i < type.parameters.size(); ++i) { + children.push_back(detail::tree::branch( + "parameter[" + std::to_string(i) + "]", + type.parameters[i].name + " " + render(*type.parameters[i].type) + )); } if (type.returnType != nullptr) { diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index c4de19ef..cacd6830 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -15,6 +15,7 @@ struct Statement; #define NODE(name, ...) \ struct name { \ __VA_ARGS__ \ + name() = default; \ name(name&&) = default; \ name& operator=(name&&) = default; \ } @@ -27,12 +28,20 @@ NODE(NameType , : name(std::move(name)), generics(std::move(generics)) {} ); +NODE(Parameter , + std::unique_ptr type; + std::string name; + + Parameter(std::unique_ptr type, std::string name) + : type(std::move(type)), name(std::move(name)) {} +); + NODE(FunctionType , - std::vector> paramTypes; + std::vector parameters; std::unique_ptr returnType; - FunctionType(std::vector> paramTypes, std::unique_ptr returnType) - : paramTypes(std::move(paramTypes)), returnType(std::move(returnType)) {} + FunctionType(std::vector params, std::unique_ptr returnType) + : parameters(std::move(params)), returnType(std::move(returnType)) {} ); NODE(TypeExpression , @@ -49,14 +58,6 @@ NODE(Scope , : statements(std::move(statements)) {} ); -NODE(Parameter , - std::unique_ptr type; - std::string name; - - Parameter(std::unique_ptr type, std::string name) - : type(std::move(type)), name(std::move(name)) {} -); - NODE(FunctionDecl , std::string name; std::vector parameters; diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index b6b2f7d5..e7b1c03c 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -71,6 +71,7 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, "/" { yylval->emplace("/"); tok = yy::Parser::token::SLASH; goto done; } "$" { tok = yy::Parser::token::DOLLAR; goto done; } + "->" { tok = yy::Parser::token::THIN_ARROW; goto done; } float_lit { yylval->emplace(toStr(start, cursor)); diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 35d9a9a7..5f8f580f 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -19,11 +19,6 @@ yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, const char*& cursor, const char*& marker, const char* limit, ast::nodes::Package*& ast, int& line, const char*& line_start); - - template - std::unique_ptr wrap(Args&&... args) { - return std::make_unique(std::forward(args)...); - } } %param { const char*& cursor } @@ -35,7 +30,7 @@ // --- tokens --- %token LPAREN RPAREN LCURLY RCURLY -%token COMMA COLON DOLLAR +%token COMMA COLON DOLLAR THIN_ARROW %token TILDE %token STRING IDENT INT FLOAT %token ERROR @@ -46,24 +41,24 @@ %right TILDE // --- non-terminal types --- -%type > package +%type package %type > global_scope -%type > declaration -%type > function_decl +%type declaration +%type function_decl %type > parameters param_list -%type > parameter -%type > type_expr -%type > name_type -%type > function_type +%type parameter +%type type_expr +%type name_type +%type function_type %type >> type_expr_list type_expr_list_ne -%type > scope +%type scope %type >> statements -%type > statement -%type > operator_call -%type > operator_flip_call -%type > function_call -%type > parenthized_value -%type > value_expr +%type statement +%type operator_call +%type operator_flip_call +%type function_call +%type parenthized_value +%type value_expr %type >> arguments arg_list %% @@ -71,8 +66,8 @@ package : global_scope[glb] { - $$ = std::make_unique(std::move($glb)); - ast = $$.release(); // fix: was copying with *$$ + $$ = ast::nodes::Package(std::move($glb)); + ast = new ast::nodes::Package(std::move($$)); } ; @@ -80,29 +75,29 @@ global_scope : declaration[decl] { auto declarations = std::vector(); - declarations.push_back(std::move(*$decl)); + declarations.push_back(std::move($decl)); $$ = std::move(declarations); } | global_scope[glb] declaration[decl] { - $glb.push_back(std::move(*$decl)); + $glb.push_back(std::move($decl)); $$ = std::move($glb); } ; declaration : function_decl[fd] - { $$ = wrap(std::move(*$fd)); } + { $$ = ast::nodes::Declaration(std::move($fd)); } ; function_decl : type_expr[return_type] IDENT[name] LPAREN parameters[params] RPAREN scope[body] { - $$ = wrap( + $$ = ast::nodes::FunctionDecl( std::move($name), std::move($params), - std::move(*$return_type), - std::move(*$body), + std::move($return_type), + std::move($body), false ); } @@ -119,30 +114,42 @@ param_list : parameter[p] { $$ = std::vector(); - $$.push_back(std::move(*$p)); + $$.push_back(std::move($p)); } | param_list[list] COMMA parameter[p] - { $list.push_back(std::move(*$p)); $$ = std::move($list); } + { $list.push_back(std::move($p)); $$ = std::move($list); } ; parameter : IDENT[name] type_expr[type] { - $$ = wrap( - std::move($type), + $$ = ast::nodes::Parameter( + std::make_unique(std::move($type)), std::move($name) ); } ; +function_type + : LPAREN parameters[params] RPAREN THIN_ARROW type_expr[ret_type] + { + $$ = ast::nodes::FunctionType( + std::move($params), + std::make_unique(std::move($ret_type)) + ); + } + ; + type_expr : name_type[nt] - { $$ = wrap(std::move(*$nt)); } + { $$ = ast::nodes::TypeExpression(std::move($nt)); } + | function_type[ft] + { $$ = ast::nodes::TypeExpression(std::move($ft)); } ; name_type : IDENT[id] - { $$ = wrap(std::move($id), std::vector>()); } + { $$ = ast::nodes::NameType(std::move($id), std::vector>()); } ; type_expr_list @@ -156,15 +163,15 @@ type_expr_list_ne : type_expr[t] { $$ = std::vector>(); - $$.push_back(std::move($t)); // fix: was $t.take() + redundant make_unique + $$.push_back(std::make_unique(std::move($t))); } | type_expr_list_ne[list] COMMA type_expr[t] - { $list.push_back(std::move($t)); $$ = std::move($list); } + { $list.push_back(std::make_unique(std::move($t))); $$ = std::move($list); } ; scope : LCURLY statements[stmts] RCURLY - { $$ = wrap(std::move($stmts)); } + { $$ = ast::nodes::Scope(std::move($stmts)); } ; statements @@ -172,47 +179,47 @@ statements { $$ = std::vector>(); } | statements[list] statement[stmt] { - $list.push_back(std::move($stmt)); + $list.push_back(std::make_unique(std::move($stmt))); $$ = std::move($list); } ; statement : function_call[fc] - { $$ = wrap(std::move(*$fc)); } + { $$ = ast::nodes::Statement(std::move($fc)); } ; value_expr : IDENT[id] - { $$ = wrap(ast::nodes::ValueSymbol(std::move($id))); } + { $$ = ast::nodes::ValueExpr(ast::nodes::ValueSymbol(std::move($id))); } | IDENT[pkg] DOLLAR IDENT[id] - { $$ = wrap(ast::nodes::PackageValueSymbol(std::move($id), std::move($pkg))); } + { $$ = ast::nodes::ValueExpr(ast::nodes::PackageValueSymbol(std::move($id), std::move($pkg))); } | INT[i] - { $$ = wrap(ast::nodes::IntLiteral(std::move($i))); } + { $$ = ast::nodes::ValueExpr(ast::nodes::IntLiteral(std::move($i))); } | FLOAT[f] - { $$ = wrap(ast::nodes::FloatLiteral(std::move($f))); } + { $$ = ast::nodes::ValueExpr(ast::nodes::FloatLiteral(std::move($f))); } | STRING[s] - { $$ = wrap(ast::nodes::StringLiteral(std::move($s))); } + { $$ = ast::nodes::ValueExpr(ast::nodes::StringLiteral(std::move($s))); } | function_call[fc] - { $$ = wrap(std::move(*$fc)); } + { $$ = ast::nodes::ValueExpr(std::move($fc)); } | operator_call[op] - { $$ = wrap(std::move(*$op)); } + { $$ = ast::nodes::ValueExpr(std::move($op)); } | operator_flip_call[op_flip] - { $$ = wrap(std::move(*$op_flip)); } + { $$ = ast::nodes::ValueExpr(std::move($op_flip)); } | parenthized_value[pv] - { $$ = wrap(std::move(*$pv)); } + { $$ = ast::nodes::ValueExpr(std::move($pv)); } ; parenthized_value : LPAREN value_expr[val] RPAREN - { $$ = wrap(std::move($val)); } // fix: was constructing twice + { $$ = ast::nodes::ParenthizedValue(std::make_unique(std::move($val))); } ; function_call : value_expr[callee] LPAREN arguments[args] RPAREN { - $$ = wrap( - std::move($callee), + $$ = ast::nodes::FunctionCall( + std::make_unique(std::move($callee)), std::move($args) ); } @@ -220,18 +227,18 @@ function_call operator_flip_call : TILDE value_expr[value] - { $$ = wrap(std::move($value)); } + { $$ = ast::nodes::OperatorFlipCall(std::make_unique(std::move($value))); } ; operator_call : value_expr[left] PLUS[op] value_expr[right] - { $$ = wrap(std::move($op), std::move($left), std::move($right)); } + { $$ = ast::nodes::OperatorCall(std::move($op), std::make_unique(std::move($left)), std::make_unique(std::move($right))); } | value_expr[left] MINUS[op] value_expr[right] - { $$ = wrap(std::move($op), std::move($left), std::move($right)); } + { $$ = ast::nodes::OperatorCall(std::move($op), std::make_unique(std::move($left)), std::make_unique(std::move($right))); } | value_expr[left] STAR[op] value_expr[right] - { $$ = wrap(std::move($op), std::move($left), std::move($right)); } + { $$ = ast::nodes::OperatorCall(std::move($op), std::make_unique(std::move($left)), std::make_unique(std::move($right))); } | value_expr[left] SLASH[op] value_expr[right] - { $$ = wrap(std::move($op), std::move($left), std::move($right)); } + { $$ = ast::nodes::OperatorCall(std::move($op), std::make_unique(std::move($left)), std::make_unique(std::move($right))); } ; arguments @@ -245,10 +252,10 @@ arg_list : value_expr[v] { $$ = std::vector>(); - $$.push_back(std::move($v)); + $$.push_back(std::make_unique(std::move($v))); } | arg_list[list] COMMA value_expr[v] - { $list.push_back(std::move($v)); $$ = std::move($list); } + { $list.push_back(std::make_unique(std::move($v))); $$ = std::move($list); } ; %% From e8152f4da2af3f82f3ae758ca05acb2e9e405ac7 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 20:49:02 +0200 Subject: [PATCH 032/154] rm nodes2.hpp --- src/ast/nodes2.hpp | 188 --------------------------------------------- 1 file changed, 188 deletions(-) delete mode 100644 src/ast/nodes2.hpp diff --git a/src/ast/nodes2.hpp b/src/ast/nodes2.hpp deleted file mode 100644 index 99975998..00000000 --- a/src/ast/nodes2.hpp +++ /dev/null @@ -1,188 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace ast::nodes { - -struct TypeExpression; -struct ValueExpr; -struct Statement; - -template -std::unique_ptr clonePtr(const std::unique_ptr& ptr) { - if (ptr == nullptr) { - return nullptr; - } - - return std::make_unique(*ptr); -} - -template -std::vector> clonePtrVector(const std::vector>& items) { - std::vector> copies; - copies.reserve(items.size()); - for (const auto& item : items) { - copies.push_back(clonePtr(item)); - } - return copies; -} - -struct NameType { - std::string name; - std::vector> generics; - - NameType(std::string name, std::vector> generics) - : name(std::move(name)), generics(std::move(generics)) {} - NameType(const NameType& other) - : name(other.name), generics(clonePtrVector(other.generics)) {} -}; - -struct FunctionType { - std::vector> paramTypes; - std::unique_ptr returnType; - - FunctionType(std::vector> paramTypes, std::unique_ptr returnType) - : paramTypes(std::move(paramTypes)), returnType(std::move(returnType)) {} - FunctionType(const FunctionType& other) - : paramTypes(clonePtrVector(other.paramTypes)), returnType(clonePtr(other.returnType)) {} -}; - -struct TypeExpression { - std::variant data; - - template - explicit TypeExpression(T value) : data(std::move(value)) {} -}; - -struct Scope { - std::vector> statements; - - explicit Scope(std::vector> statements) - : statements(std::move(statements)) {} - Scope(const Scope& other) - : statements(clonePtrVector(other.statements)) {} -}; - -struct Parameter { - std::unique_ptr type; - std::string name; - - Parameter(std::unique_ptr type, std::string name) - : type(std::move(type)), name(std::move(name)) {} - Parameter(const Parameter& other) - : type(clonePtr(other.type)), name(other.name) {} -}; - -struct FunctionDecl { - std::string name; - std::vector parameters; - TypeExpression returnType; - Scope functionBody; - bool mutating; - - FunctionDecl(std::string name, std::vector parameters, TypeExpression returnType, Scope functionBody, bool mutating) - : name(std::move(name)), - parameters(std::move(parameters)), - returnType(std::move(returnType)), - functionBody(std::move(functionBody)), - mutating(mutating) {} -}; - -/// The only unary operator -struct OperatorFlipCall { - std::unique_ptr value; - - OperatorFlipCall(std::unique_ptr value) - : value(std::move(value)) {} - OperatorFlipCall(const OperatorFlipCall& other) - : value(clonePtr(other.value)) {} -}; - -struct OperatorCall { - std::string op; - std::unique_ptr left; - std::unique_ptr right; - - OperatorCall(std::string op, std::unique_ptr left, std::unique_ptr right) - : op(std::move(op)), left(std::move(left)), right(std::move(right)) {} - OperatorCall(const OperatorCall& other) - : op(std::move(other.op)), left(clonePtr(other.left)), right(clonePtr(other.right)) {} -}; - -struct FunctionCall { - std::unique_ptr callee; - std::vector> arguments; - - FunctionCall(std::unique_ptr callee, std::vector> arguments) - : callee(std::move(callee)), arguments(std::move(arguments)) {} - FunctionCall(const FunctionCall& other) - : callee(clonePtr(other.callee)), arguments(clonePtrVector(other.arguments)) {} -}; - -struct StringLiteral { - std::string data; - - explicit StringLiteral(std::string data) : data(std::move(data)) {} -}; - -struct IntLiteral { - std::string data; - - explicit IntLiteral(std::string data) : data(data) {} -}; - -struct FloatLiteral { - std::string data; - - explicit FloatLiteral(std::string data) : data(std::move(data)) {} -}; - -struct PackageValueSymbol { - std::string name; - std::string package; - - explicit PackageValueSymbol(std::string name, std::string package) : name(std::move(name)), package(std::move(package)) {} -}; - -struct ValueSymbol { - std::string name; - - explicit ValueSymbol(std::string name) : name(std::move(name)) {} -}; - -struct ParenthizedValue { - std::unique_ptr data; - - explicit ParenthizedValue(std::unique_ptr value) : data(std::move(value)) {} - ParenthizedValue(const ParenthizedValue& other) : data(clonePtr(other.data)) {} -}; - -struct ValueExpr { - std::variant data; - - template - explicit ValueExpr(T value) : data(std::move(value)) {} - ValueExpr(const ValueExpr& other) : data(other.data) {} -}; - -struct Statement { - std::variant data; - - template - explicit Statement(T value) : data(std::move(value)) {} -}; - -using Declaration = std::variant; - -struct Package { - std::vector declarations; - - explicit Package(std::vector declarations) - : declarations(std::move(declarations)) {} -}; - -} // namespace ast::nodes From fe2d4ccc96c1e4c5ca9ba02970ec6bc5edb5f416 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 22:28:28 +0200 Subject: [PATCH 033/154] imrpove parser --- docs/bison.md | 14 ++++++++++ src/ast/evaluators/to_string.hpp | 4 +++ src/ast/nodes.hpp | 45 +++++++++++++++++------------- src/grammar/lexer.re | 1 + src/grammar/parser.y | 47 ++++++-------------------------- test-parser/main.zn | 3 +- 6 files changed, 56 insertions(+), 58 deletions(-) create mode 100644 docs/bison.md diff --git a/docs/bison.md b/docs/bison.md new file mode 100644 index 00000000..0194c221 --- /dev/null +++ b/docs/bison.md @@ -0,0 +1,14 @@ +for recursion dont need to specify the single node variant when empty a variant. +also: empty doesnt need explicit instantiation. + +``` +parameters + : %empty + | parameters[params] COMMA parameter[p] + { + $params.push_back(std::move($p)); + $$ = std::move($params); + } + ; +``` +only use single node variant if we dont allow empty. diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index d26b908f..a5ac2e04 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -84,6 +84,10 @@ std::string operator()(const nodes::StringLiteral& literal) const { return detail::tree::node("StringLiteral \"" + literal.data + "\"", {}); } +std::string operator()(const nodes::IntrinsicValueSymbol& symbol) const { + return detail::tree::node("IntrinsicValueSymbol @" + symbol.package + "$" + symbol.name, {}); +} + std::string operator()(const nodes::PackageValueSymbol& symbol) const { return detail::tree::node("PackageValueSymbol " + symbol.package + "$" + symbol.name, {}); } diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index cacd6830..822383f5 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -20,7 +20,7 @@ struct name { \ name& operator=(name&&) = default; \ } -NODE(NameType , +NODE(NameType , std::string name; std::vector> generics; @@ -28,7 +28,7 @@ NODE(NameType , : name(std::move(name)), generics(std::move(generics)) {} ); -NODE(Parameter , +NODE(Parameter , std::unique_ptr type; std::string name; @@ -36,7 +36,7 @@ NODE(Parameter , : type(std::move(type)), name(std::move(name)) {} ); -NODE(FunctionType , +NODE(FunctionType , std::vector parameters; std::unique_ptr returnType; @@ -44,21 +44,21 @@ NODE(FunctionType , : parameters(std::move(params)), returnType(std::move(returnType)) {} ); -NODE(TypeExpression , +NODE(TypeExpression , std::variant data; template explicit TypeExpression(T value) : data(std::move(value)) {} ); -NODE(Scope , +NODE(Scope , std::vector> statements; explicit Scope(std::vector> statements) : statements(std::move(statements)) {} ); -NODE(FunctionDecl , +NODE(FunctionDecl , std::string name; std::vector parameters; TypeExpression returnType; @@ -74,14 +74,14 @@ NODE(FunctionDecl , ); /// The only unary operator -NODE(OperatorFlipCall , +NODE(OperatorFlipCall , std::unique_ptr value; OperatorFlipCall(std::unique_ptr value) : value(std::move(value)) {} ); -NODE(OperatorCall , +NODE(OperatorCall , std::string op; std::unique_ptr left; std::unique_ptr right; @@ -90,7 +90,7 @@ NODE(OperatorCall , : op(std::move(op)), left(std::move(left)), right(std::move(right)) {} ); -NODE(FunctionCall , +NODE(FunctionCall , std::unique_ptr callee; std::vector> arguments; @@ -98,51 +98,58 @@ NODE(FunctionCall , : callee(std::move(callee)), arguments(std::move(arguments)) {} ); -NODE(StringLiteral , +NODE(StringLiteral , std::string data; explicit StringLiteral(std::string data) : data(std::move(data)) {} ); -NODE(IntLiteral , +NODE(IntLiteral , std::string data; explicit IntLiteral(std::string data) : data(data) {} ); -NODE(FloatLiteral , +NODE(FloatLiteral , std::string data; explicit FloatLiteral(std::string data) : data(std::move(data)) {} ); -NODE(PackageValueSymbol , +NODE(IntrinsicValueSymbol, + std::string name; + std::string package; + + explicit IntrinsicValueSymbol(std::string name, std::string package) : name(std::move(name)), package(std::move(package)) {} +); + +NODE(PackageValueSymbol , std::string name; std::string package; explicit PackageValueSymbol(std::string name, std::string package) : name(std::move(name)), package(std::move(package)) {} ); -NODE(ValueSymbol , +NODE(ValueSymbol , std::string name; explicit ValueSymbol(std::string name) : name(std::move(name)) {} ); -NODE(ParenthizedValue , +NODE(ParenthizedValue , std::unique_ptr data; explicit ParenthizedValue(std::unique_ptr value) : data(std::move(value)) {} ); -NODE(ValueExpr , - std::variant data; +NODE(ValueExpr , + std::variant data; template explicit ValueExpr(T value) : data(std::move(value)) {} ); -NODE(Statement , +NODE(Statement , std::variant data; template @@ -151,7 +158,7 @@ NODE(Statement , using Declaration = std::variant; -NODE(Package , +NODE(Package , std::vector declarations; explicit Package(std::vector declarations) diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index e7b1c03c..745436a4 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -71,6 +71,7 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, "/" { yylval->emplace("/"); tok = yy::Parser::token::SLASH; goto done; } "$" { tok = yy::Parser::token::DOLLAR; goto done; } + "@" { tok = yy::Parser::token::AT; goto done; } "->" { tok = yy::Parser::token::THIN_ARROW; goto done; } float_lit { diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 5f8f580f..e01a06f9 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -30,8 +30,8 @@ // --- tokens --- %token LPAREN RPAREN LCURLY RCURLY -%token COMMA COLON DOLLAR THIN_ARROW -%token TILDE +%token COMMA COLON +%token DOLLAR THIN_ARROW AT %token STRING IDENT INT FLOAT %token ERROR @@ -45,12 +45,11 @@ %type > global_scope %type declaration %type function_decl -%type > parameters param_list +%type > parameters %type parameter %type type_expr %type name_type %type function_type -%type >> type_expr_list type_expr_list_ne %type scope %type >> statements %type statement @@ -72,12 +71,7 @@ package ; global_scope - : declaration[decl] - { - auto declarations = std::vector(); - declarations.push_back(std::move($decl)); - $$ = std::move(declarations); - } + : %empty | global_scope[glb] declaration[decl] { $glb.push_back(std::move($decl)); @@ -105,19 +99,11 @@ function_decl parameters : %empty - { $$ = std::vector(); } - | param_list[list] - { $$ = std::move($list); } - ; - -param_list - : parameter[p] + | parameters[params] COMMA parameter[p] { - $$ = std::vector(); - $$.push_back(std::move($p)); + $params.push_back(std::move($p)); + $$ = std::move($params); } - | param_list[list] COMMA parameter[p] - { $list.push_back(std::move($p)); $$ = std::move($list); } ; parameter @@ -152,23 +138,6 @@ name_type { $$ = ast::nodes::NameType(std::move($id), std::vector>()); } ; -type_expr_list - : %empty - { $$ = std::vector>(); } - | type_expr_list_ne[list] - { $$ = std::move($list); } - ; - -type_expr_list_ne - : type_expr[t] - { - $$ = std::vector>(); - $$.push_back(std::make_unique(std::move($t))); - } - | type_expr_list_ne[list] COMMA type_expr[t] - { $list.push_back(std::make_unique(std::move($t))); $$ = std::move($list); } - ; - scope : LCURLY statements[stmts] RCURLY { $$ = ast::nodes::Scope(std::move($stmts)); } @@ -194,6 +163,8 @@ value_expr { $$ = ast::nodes::ValueExpr(ast::nodes::ValueSymbol(std::move($id))); } | IDENT[pkg] DOLLAR IDENT[id] { $$ = ast::nodes::ValueExpr(ast::nodes::PackageValueSymbol(std::move($id), std::move($pkg))); } + | AT IDENT[pkg] DOLLAR IDENT[id] + { $$ = ast::nodes::ValueExpr(ast::nodes::IntrinsicValueSymbol(std::move($id), std::move($pkg))); } | INT[i] { $$ = ast::nodes::ValueExpr(ast::nodes::IntLiteral(std::move($i))); } | FLOAT[f] diff --git a/test-parser/main.zn b/test-parser/main.zn index 46bacfaf..356da15b 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,4 +1,5 @@ Void main() { - print("hello") + print(2, 2) Std$print(1 + 1 + 3 + 4) + @Intrinsics$print("hello", "bye") } From 1a94e1ad621b287fe27a3c8c1f4216160a7662c3 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 22:37:49 +0200 Subject: [PATCH 034/154] clean up parser --- docs/bison.md | 41 +++++++++++++++++++++++++++++++++++++++++ src/grammar/parser.y | 22 ++++++++++++---------- test-parser/main.zn | 2 +- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/docs/bison.md b/docs/bison.md index 0194c221..82dab4ee 100644 --- a/docs/bison.md +++ b/docs/bison.md @@ -12,3 +12,44 @@ parameters ; ``` only use single node variant if we dont allow empty. + +actually, this is incorrect, as only allowing empty nodes mess with commas, which would only allow: +``` +Void main(, test Int) { + print(2, 2) + Std$print(1 + 1 + 3 + 4) + @Intrinsics$print("hello", "bye") +} +``` +instead of: +``` +Void main(test Int) { + print(2, 2) + Std$print(1 + 1 + 3 + 4) + @Intrinsics$print("hello", "bye") +} +``` + +so we use: +``` +parameters + : %empty + | parameters[params] COMMA parameter[p] + { + $params.push_back(std::move($p)); + $$ = std::move($params); + } + ; +``` +but possible in homologous: +``` +statements + : %empty + { $$ = std::vector>(); } + | statements[list] statement[stmt] + { + $list.push_back(std::make_unique(std::move($stmt))); + $$ = std::move($list); + } + ; +``` diff --git a/src/grammar/parser.y b/src/grammar/parser.y index e01a06f9..49f6f19c 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -58,7 +58,7 @@ %type function_call %type parenthized_value %type value_expr -%type >> arguments arg_list +%type >> arguments %% @@ -99,6 +99,11 @@ function_decl parameters : %empty + | parameter[p] + { + $$ = std::vector(); + $$.push_back(std::move($p)); + } | parameters[params] COMMA parameter[p] { $params.push_back(std::move($p)); @@ -214,19 +219,16 @@ operator_call arguments : %empty - { $$ = std::vector>(); } - | arg_list[list] - { $$ = std::move($list); } - ; - -arg_list - : value_expr[v] + | value_expr[v] { $$ = std::vector>(); $$.push_back(std::make_unique(std::move($v))); } - | arg_list[list] COMMA value_expr[v] - { $list.push_back(std::make_unique(std::move($v))); $$ = std::move($list); } + | arguments[args] COMMA value_expr[v] + { + $args.push_back(std::make_unique(std::move($v))); + $$ = std::move($args); + } ; %% diff --git a/test-parser/main.zn b/test-parser/main.zn index 356da15b..1c16cb21 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,4 +1,4 @@ -Void main() { +Void main(test Int) { print(2, 2) Std$print(1 + 1 + 3 + 4) @Intrinsics$print("hello", "bye") From a79d491fa96f51556276baf5f85a02f906ee9954 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 22:49:22 +0200 Subject: [PATCH 035/154] add carret indicator --- src/grammar/lexer.re | 16 +++++++++++++-- src/grammar/parser.y | 47 +++++++++++++++++++++++++++++++++++++++++++- src/main.cpp | 4 ++-- test-parser/main.zn | 1 + 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 745436a4..b55b6837 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -27,9 +27,18 @@ static std::string unescape(const char* b, const char* e) { return out; } +static void updateLocation(const char* begin, const char* end, int& line, const char*& line_start) { + for (const char* cursor = begin; cursor < end; ++cursor) { + if (*cursor == '\n') { + ++line; + line_start = cursor + 1; + } + } +} + int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, const char*& cursor, const char*& marker, const char* limit, - ast::nodes::Package*&, int& line, const char*& line_start) { + const std::string&, ast::nodes::Package*&, int& line, const char*& line_start) { for (;;) { if (cursor >= limit) return 0; const char* start = cursor; @@ -56,7 +65,10 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, int_lit = sw_digits | digits; float_lit = sw_digits "." digits | digits "." digits; - [ \t\r\n]+ { continue; } + [ \t\r\n]+ { + updateLocation(start, cursor, line, line_start); + continue; + } "(" { tok = yy::Parser::token::LPAREN; goto done; } ")" { tok = yy::Parser::token::RPAREN; goto done; } "{" { tok = yy::Parser::token::LCURLY; goto done; } diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 49f6f19c..d3cf4398 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -8,6 +8,7 @@ %code requires { #include "ast/.hpp" + #include #include #include #include @@ -18,12 +19,14 @@ int yylex( yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, const char*& cursor, const char*& marker, const char* limit, - ast::nodes::Package*& ast, int& line, const char*& line_start); + const std::string& source, ast::nodes::Package*& ast, int& line, const char*& line_start); } %param { const char*& cursor } %param { const char*& marker } %param { const char* limit } + +%param { const std::string& source } %param { ast::nodes::Package*& ast } %param { int& line } %param { const char*& line_start } @@ -233,6 +236,48 @@ arguments %% +static std::string findLine(const std::string& source, int line_number) { + int current_line = 1; + size_t line_start = 0; + + while (line_start <= source.size()) { + size_t line_end = source.find('\n', line_start); + if (line_end == std::string::npos) { + line_end = source.size(); + } + + if (current_line == line_number) { + return source.substr(line_start, line_end - line_start); + } + + if (line_end == source.size()) { + break; + } + + line_start = line_end + 1; + ++current_line; + } + + return std::string(); +} + void yy::Parser::error(const location_type& loc, const std::string& msg) { std::cerr << loc.begin.line << ":" << loc.begin.column << ": " << msg << "\n"; + + const std::string line = findLine(source, loc.begin.line); + if (line.empty()) { + return; + } + + std::cerr << line << "\n"; + + std::string caret_line; + caret_line.reserve(line.size()); + for (int column = 1; column < loc.begin.column; ++column) { + caret_line += static_cast(column - 1) < line.size() && line[static_cast(column - 1)] == '\t' ? '\t' : ' '; + } + + const int highlight_width = std::max(1, loc.end.column - loc.begin.column); + caret_line.append(static_cast(highlight_width), '^'); + std::cerr << caret_line << "\n"; } diff --git a/src/main.cpp b/src/main.cpp index 9db2522f..0ec5c3cd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,7 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, const char*& cursor, const char*& marker, const char* limit, - ast::nodes::Package*& ast, int& line, const char*& line_start); + const std::string& source, ast::nodes::Package*& ast, int& line, const char*& line_start); std::string readFile(const std::string& path) { std::ifstream file(path); @@ -26,7 +26,7 @@ int main() { int line = 1; ast::nodes::Package* ast = nullptr; - yy::Parser parser(cursor, marker, limit, ast, line, line_start); + yy::Parser parser(cursor, marker, limit, input, ast, line, line_start); int res = parser.parse(); if (ast != nullptr) { diff --git a/test-parser/main.zn b/test-parser/main.zn index 1c16cb21..205f772e 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -2,4 +2,5 @@ Void main(test Int) { print(2, 2) Std$print(1 + 1 + 3 + 4) @Intrinsics$print("hello", "bye") + @@ } From 940f66e06e3c1d453da9afa928a4bf27e391f78b Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 22:57:44 +0200 Subject: [PATCH 036/154] make caret nicer --- src/grammar/lexer.re | 2 +- src/grammar/parser.y | 46 ++++++++++++++++++++++++-------------------- src/main.cpp | 7 ++++--- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index b55b6837..e9043d16 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -38,7 +38,7 @@ static void updateLocation(const char* begin, const char* end, int& line, const int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, const char*& cursor, const char*& marker, const char* limit, - const std::string&, ast::nodes::Package*&, int& line, const char*& line_start) { + const std::string&, const std::string&, ast::nodes::Package*&, int& line, const char*& line_start) { for (;;) { if (cursor >= limit) return 0; const char* start = cursor; diff --git a/src/grammar/parser.y b/src/grammar/parser.y index d3cf4398..9bc61e6e 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -19,13 +19,14 @@ int yylex( yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, const char*& cursor, const char*& marker, const char* limit, - const std::string& source, ast::nodes::Package*& ast, int& line, const char*& line_start); + const std::string& sourcePath, const std::string& source, ast::nodes::Package*& ast, int& line, const char*& line_start); } %param { const char*& cursor } %param { const char*& marker } %param { const char* limit } +%param { const std::string& sourcePath } %param { const std::string& source } %param { ast::nodes::Package*& ast } %param { int& line } @@ -236,48 +237,51 @@ arguments %% -static std::string findLine(const std::string& source, int line_number) { - int current_line = 1; - size_t line_start = 0; +static std::string findLine(const std::string& source, int lineNumber) { + int currentLine = 1; + size_t lineStart = 0; - while (line_start <= source.size()) { - size_t line_end = source.find('\n', line_start); - if (line_end == std::string::npos) { - line_end = source.size(); + while (lineStart <= source.size()) { + size_t lineEnd = source.find('\n', lineStart); + if (lineEnd == std::string::npos) { + lineEnd = source.size(); } - if (current_line == line_number) { - return source.substr(line_start, line_end - line_start); + if (currentLine == lineNumber) { + return source.substr(lineStart, lineEnd - lineStart); } - if (line_end == source.size()) { + if (lineEnd == source.size()) { break; } - line_start = line_end + 1; - ++current_line; + lineStart = lineEnd + 1; + ++currentLine; } return std::string(); } void yy::Parser::error(const location_type& loc, const std::string& msg) { - std::cerr << loc.begin.line << ":" << loc.begin.column << ": " << msg << "\n"; + std::cerr << sourcePath << ":" << loc.begin.line << ":" << loc.begin.column << ": error: " << msg << "\n"; const std::string line = findLine(source, loc.begin.line); if (line.empty()) { return; } - std::cerr << line << "\n"; + const std::string lineNumber = std::to_string(loc.begin.line); + std::cerr << lineNumber << " | " << line << "\n"; - std::string caret_line; - caret_line.reserve(line.size()); + std::string caretLine; + caretLine.reserve(lineNumber.size() + 3 + line.size()); + caretLine.append(lineNumber.size(), ' '); + caretLine += " | "; for (int column = 1; column < loc.begin.column; ++column) { - caret_line += static_cast(column - 1) < line.size() && line[static_cast(column - 1)] == '\t' ? '\t' : ' '; + caretLine += static_cast(column - 1) < line.size() && line[static_cast(column - 1)] == '\t' ? '\t' : ' '; } - const int highlight_width = std::max(1, loc.end.column - loc.begin.column); - caret_line.append(static_cast(highlight_width), '^'); - std::cerr << caret_line << "\n"; + const int highlightWidth = std::max(1, loc.end.column - loc.begin.column); + caretLine.append(static_cast(highlightWidth), '^'); + std::cerr << caretLine << "\n"; } diff --git a/src/main.cpp b/src/main.cpp index 0ec5c3cd..8c7c5a69 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,7 @@ int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, const char*& cursor, const char*& marker, const char* limit, - const std::string& source, ast::nodes::Package*& ast, int& line, const char*& line_start); + const std::string& sourcePath, const std::string& source, ast::nodes::Package*& ast, int& line, const char*& line_start); std::string readFile(const std::string& path) { std::ifstream file(path); @@ -17,7 +17,8 @@ std::string readFile(const std::string& path) { } int main() { - std::string input = readFile("test-parser/main.zn"); + const std::string inputPath = "test-parser/main.zn"; + std::string input = readFile(inputPath); const char* cursor = input.c_str(); const char* marker = cursor; @@ -26,7 +27,7 @@ int main() { int line = 1; ast::nodes::Package* ast = nullptr; - yy::Parser parser(cursor, marker, limit, input, ast, line, line_start); + yy::Parser parser(cursor, marker, limit, inputPath, input, ast, line, line_start); int res = parser.parse(); if (ast != nullptr) { From e75aa7a053019504d9428936c68940b00e3d5f0f Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 26 May 2026 23:00:11 +0200 Subject: [PATCH 037/154] add param names --- src/grammar/lexer.re | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index e9043d16..7066ad6e 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -36,9 +36,10 @@ static void updateLocation(const char* begin, const char* end, int& line, const } } -int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, - const char*& cursor, const char*& marker, const char* limit, - const std::string&, const std::string&, ast::nodes::Package*&, int& line, const char*& line_start) { +int yylex( + yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, + const char*& cursor, const char*& marker, const char* limit, const std::string& sourcePath, + const std::string& source, ast::nodes::Package*& ast, int& line, const char*& line_start) { for (;;) { if (cursor >= limit) return 0; const char* start = cursor; From 8795fdbc300ff83e5b6adef9085f25245c5fc60f Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 27 May 2026 12:14:30 +0200 Subject: [PATCH 038/154] add VariableDecl --- src/ast/evaluators/to_string.hpp | 9 ++++++ src/ast/nodes.hpp | 28 +++++++++++++++++-- src/grammar/lexer.re | 3 ++ src/grammar/parser.y | 48 ++++++++++++++++++++++++++++++-- test-parser/main.zn | 6 ++-- 5 files changed, 87 insertions(+), 7 deletions(-) diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index a5ac2e04..25ddc2af 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -188,8 +188,17 @@ std::string operator()(const nodes::Scope& scope) const { return detail::tree::node("Scope", children); } +std::string operator()(const nodes::VariableDecl& declaration) const { + std::vector children; + children.push_back(detail::tree::branch("type", render(declaration.type))); + children.push_back(detail::tree::branch("value", render(*declaration.value))); + + return detail::tree::node("VariableDecl " + declaration.name, children); +} + std::string operator()(const nodes::FunctionDecl& declaration) const { std::vector children; + children.push_back(detail::tree::leaf("isMEthod", declaration.isMethod ? "true" : "false")); children.push_back(detail::tree::leaf("mutating", declaration.mutating ? "true" : "false")); for (std::size_t i = 0; i < declaration.parameters.size(); ++i) { diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index 822383f5..bd4914ea 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -58,18 +58,42 @@ NODE(Scope , : statements(std::move(statements)) {} ); +NODE(VariableDecl, + std::string name; + TypeExpression type; + std::unique_ptr value; + + VariableDecl( + std::string name, + TypeExpression type, + std::unique_ptr value + ) + : name(std::move(name)), + type(std::move(type)), + value(std::move(value)) {} +); + NODE(FunctionDecl , std::string name; std::vector parameters; TypeExpression returnType; Scope functionBody; + bool isMethod; bool mutating; - FunctionDecl(std::string name, std::vector parameters, TypeExpression returnType, Scope functionBody, bool mutating) + FunctionDecl( + std::string name, + std::vector parameters, + TypeExpression returnType, + Scope functionBody, + bool isMethod, + bool mutating + ) : name(std::move(name)), parameters(std::move(parameters)), returnType(std::move(returnType)), functionBody(std::move(functionBody)), + isMethod(isMethod), mutating(mutating) {} ); @@ -150,7 +174,7 @@ NODE(ValueExpr , ); NODE(Statement , - std::variant data; + std::variant data; template explicit Statement(T value) : data(std::move(value)) {} diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 7066ad6e..6fbc85ea 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -70,6 +70,7 @@ int yylex( updateLocation(start, cursor, line, line_start); continue; } + "=" { tok = yy::Parser::token::EQUAL; goto done; } "(" { tok = yy::Parser::token::LPAREN; goto done; } ")" { tok = yy::Parser::token::RPAREN; goto done; } "{" { tok = yy::Parser::token::LCURLY; goto done; } @@ -99,6 +100,8 @@ int yylex( yylval->emplace(unescape(start + 1, cursor - 1)); tok = yy::Parser::token::STRING; goto done; } + "mut" { tok = yy::Parser::token::MUT; goto done; } + "this" { tok = yy::Parser::token::THIS; goto done; } ident+ { yylval->emplace(toStr(start, cursor)); tok = yy::Parser::token::IDENT; goto done; diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 9bc61e6e..063555df 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -34,8 +34,9 @@ // --- tokens --- %token LPAREN RPAREN LCURLY RCURLY -%token COMMA COLON +%token COMMA COLON EQUAL %token DOLLAR THIN_ARROW AT +%token MUT THIS %token STRING IDENT INT FLOAT %token ERROR @@ -48,6 +49,7 @@ %type package %type > global_scope %type declaration +%type variable_decl %type function_decl %type > parameters %type parameter @@ -60,6 +62,7 @@ %type operator_call %type operator_flip_call %type function_call +%type statement_function_call %type parenthized_value %type value_expr %type >> arguments @@ -76,6 +79,7 @@ package global_scope : %empty + { $$ = std::vector(); } | global_scope[glb] declaration[decl] { $glb.push_back(std::move($decl)); @@ -88,6 +92,17 @@ declaration { $$ = ast::nodes::Declaration(std::move($fd)); } ; +variable_decl + : IDENT[name] type_expr[type] EQUAL value_expr[val] + { + $$ = ast::nodes::VariableDecl( + std::move($name), + std::move($type), + std::make_unique(std::move($val)) + ); + } + ; + function_decl : type_expr[return_type] IDENT[name] LPAREN parameters[params] RPAREN scope[body] { @@ -96,6 +111,7 @@ function_decl std::move($params), std::move($return_type), std::move($body), + false, false ); } @@ -103,6 +119,7 @@ function_decl parameters : %empty + { $$ = std::vector(); } | parameter[p] { $$ = std::vector(); @@ -163,8 +180,34 @@ statements ; statement - : function_call[fc] + : statement_function_call[fc] { $$ = ast::nodes::Statement(std::move($fc)); } + | variable_decl[var_decl] + { $$ = ast::nodes::Statement(std::move($var_decl)); } + ; + +statement_function_call + : IDENT[name] LPAREN arguments[args] RPAREN + { + $$ = ast::nodes::FunctionCall( + std::make_unique(ast::nodes::ValueExpr(ast::nodes::ValueSymbol(std::move($name)))), + std::move($args) + ); + } + | IDENT[pkg] DOLLAR IDENT[name] LPAREN arguments[args] RPAREN + { + $$ = ast::nodes::FunctionCall( + std::make_unique(ast::nodes::ValueExpr(ast::nodes::PackageValueSymbol(std::move($name), std::move($pkg)))), + std::move($args) + ); + } + | AT IDENT[pkg] DOLLAR IDENT[name] LPAREN arguments[args] RPAREN + { + $$ = ast::nodes::FunctionCall( + std::make_unique(ast::nodes::ValueExpr(ast::nodes::IntrinsicValueSymbol(std::move($name), std::move($pkg)))), + std::move($args) + ); + } ; value_expr @@ -223,6 +266,7 @@ operator_call arguments : %empty + { $$ = std::vector>(); } | value_expr[v] { $$ = std::vector>(); diff --git a/test-parser/main.zn b/test-parser/main.zn index 205f772e..418a3aa3 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,6 +1,6 @@ -Void main(test Int) { +Void main(b Int, a Bool) { print(2, 2) Std$print(1 + 1 + 3 + 4) - @Intrinsics$print("hello", "bye") - @@ + @Intrinsics$print("hello") + test Int = 3 } From 98bf788d46743904f5092939a98d1c2dc2a22aa4 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 27 May 2026 12:19:40 +0200 Subject: [PATCH 039/154] improve tree graph --- docs/bison.md | 2 ++ src/ast/evaluators/to_string.hpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/bison.md b/docs/bison.md index 82dab4ee..3aefd35a 100644 --- a/docs/bison.md +++ b/docs/bison.md @@ -53,3 +53,5 @@ statements } ; ``` + +no ambiguaty must exist that would be resolved through following sub-nodes, because sub-nodes are reduced before matching. otherwise we would use glr, but it is slower and lalr(1) is linear. diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index 25ddc2af..5e2a5ed2 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -174,7 +174,7 @@ std::string operator()(const nodes::Parameter& parameter) const { } std::string operator()(const nodes::Statement& statement) const { - return detail::tree::node("Statement", {detail::tree::branch("data", std::visit(*this, statement.data))}); + return std::visit(*this, statement.data); } std::string operator()(const nodes::Scope& scope) const { @@ -198,7 +198,7 @@ std::string operator()(const nodes::VariableDecl& declaration) const { std::string operator()(const nodes::FunctionDecl& declaration) const { std::vector children; - children.push_back(detail::tree::leaf("isMEthod", declaration.isMethod ? "true" : "false")); + children.push_back(detail::tree::leaf("isMethod", declaration.isMethod ? "true" : "false")); children.push_back(detail::tree::leaf("mutating", declaration.mutating ? "true" : "false")); for (std::size_t i = 0; i < declaration.parameters.size(); ++i) { From 9d8091d68714a6a124242684fdd5fd016ea6bb45 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 27 May 2026 12:34:49 +0200 Subject: [PATCH 040/154] update --- src/ast/nodes.hpp | 49 ++++++++++++++++++++++++++------------------- test-parser/main.zn | 1 + 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index bd4914ea..06da2ea9 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -20,7 +20,7 @@ struct name { \ name& operator=(name&&) = default; \ } -NODE(NameType , +NODE(NameType, std::string name; std::vector> generics; @@ -28,7 +28,7 @@ NODE(NameType , : name(std::move(name)), generics(std::move(generics)) {} ); -NODE(Parameter , +NODE(Parameter, std::unique_ptr type; std::string name; @@ -36,22 +36,29 @@ NODE(Parameter , : type(std::move(type)), name(std::move(name)) {} ); -NODE(FunctionType , - std::vector parameters; +NODE(FunctionType, + std::vector> parameters; std::unique_ptr returnType; + bool isMethod; + bool isMutating; - FunctionType(std::vector params, std::unique_ptr returnType) - : parameters(std::move(params)), returnType(std::move(returnType)) {} + FunctionType( + std::vector> parameters, + std::unique_ptr returnType, + bool isMethod, + bool isMutating + ) + : parameters(std::move(parameters)), returnType(std::move(returnType)), isMethod(isMethod), isMutating(isMutating) {} ); -NODE(TypeExpression , +NODE(TypeExpression, std::variant data; template explicit TypeExpression(T value) : data(std::move(value)) {} ); -NODE(Scope , +NODE(Scope, std::vector> statements; explicit Scope(std::vector> statements) @@ -73,7 +80,7 @@ NODE(VariableDecl, value(std::move(value)) {} ); -NODE(FunctionDecl , +NODE(FunctionDecl, std::string name; std::vector parameters; TypeExpression returnType; @@ -98,14 +105,14 @@ NODE(FunctionDecl , ); /// The only unary operator -NODE(OperatorFlipCall , +NODE(OperatorFlipCall, std::unique_ptr value; OperatorFlipCall(std::unique_ptr value) : value(std::move(value)) {} ); -NODE(OperatorCall , +NODE(OperatorCall, std::string op; std::unique_ptr left; std::unique_ptr right; @@ -114,7 +121,7 @@ NODE(OperatorCall , : op(std::move(op)), left(std::move(left)), right(std::move(right)) {} ); -NODE(FunctionCall , +NODE(FunctionCall, std::unique_ptr callee; std::vector> arguments; @@ -122,19 +129,19 @@ NODE(FunctionCall , : callee(std::move(callee)), arguments(std::move(arguments)) {} ); -NODE(StringLiteral , +NODE(StringLiteral, std::string data; explicit StringLiteral(std::string data) : data(std::move(data)) {} ); -NODE(IntLiteral , +NODE(IntLiteral, std::string data; explicit IntLiteral(std::string data) : data(data) {} ); -NODE(FloatLiteral , +NODE(FloatLiteral, std::string data; explicit FloatLiteral(std::string data) : data(std::move(data)) {} @@ -147,33 +154,33 @@ NODE(IntrinsicValueSymbol, explicit IntrinsicValueSymbol(std::string name, std::string package) : name(std::move(name)), package(std::move(package)) {} ); -NODE(PackageValueSymbol , +NODE(PackageValueSymbol, std::string name; std::string package; explicit PackageValueSymbol(std::string name, std::string package) : name(std::move(name)), package(std::move(package)) {} ); -NODE(ValueSymbol , +NODE(ValueSymbol, std::string name; explicit ValueSymbol(std::string name) : name(std::move(name)) {} ); -NODE(ParenthizedValue , +NODE(ParenthizedValue, std::unique_ptr data; explicit ParenthizedValue(std::unique_ptr value) : data(std::move(value)) {} ); -NODE(ValueExpr , +NODE(ValueExpr, std::variant data; template explicit ValueExpr(T value) : data(std::move(value)) {} ); -NODE(Statement , +NODE(Statement, std::variant data; template @@ -182,7 +189,7 @@ NODE(Statement , using Declaration = std::variant; -NODE(Package , +NODE(Package, std::vector declarations; explicit Package(std::vector declarations) diff --git a/test-parser/main.zn b/test-parser/main.zn index 418a3aa3..ed095601 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -3,4 +3,5 @@ Void main(b Int, a Bool) { Std$print(1 + 1 + 3 + 4) @Intrinsics$print("hello") test Int = 3 + func (Int) -> Void = 3 } From e56feb39ce77ddbe34b39ad7712f5e13708e3da7 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 27 May 2026 12:53:24 +0200 Subject: [PATCH 041/154] update --- src/ast/evaluators/to_string.hpp | 6 ++-- src/ast/nodes.hpp | 6 ++-- src/grammar/parser.y | 53 ++++++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index 5e2a5ed2..fdb0dc62 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -149,13 +149,15 @@ std::string operator()(const nodes::FunctionType& type) const { for (std::size_t i = 0; i < type.parameters.size(); ++i) { children.push_back(detail::tree::branch( "parameter[" + std::to_string(i) + "]", - type.parameters[i].name + " " + render(*type.parameters[i].type) + std::visit(*this, type.parameters[i]->data) )); } if (type.returnType != nullptr) { children.push_back(detail::tree::branch("returnType", render(*type.returnType))); } + children.push_back(detail::tree::leaf("isMethod", type.isMethod ? "true" : "false")); + children.push_back(detail::tree::leaf("isMutating", type.isMutating ? "true" : "false")); return detail::tree::node("FunctionType", children); } @@ -199,7 +201,7 @@ std::string operator()(const nodes::VariableDecl& declaration) const { std::string operator()(const nodes::FunctionDecl& declaration) const { std::vector children; children.push_back(detail::tree::leaf("isMethod", declaration.isMethod ? "true" : "false")); - children.push_back(detail::tree::leaf("mutating", declaration.mutating ? "true" : "false")); + children.push_back(detail::tree::leaf("isMutating", declaration.isMutating ? "true" : "false")); for (std::size_t i = 0; i < declaration.parameters.size(); ++i) { children.push_back(detail::tree::branch("parameter[" + std::to_string(i) + "]", render(declaration.parameters[i]))); diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index 06da2ea9..5294e2fe 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -86,7 +86,7 @@ NODE(FunctionDecl, TypeExpression returnType; Scope functionBody; bool isMethod; - bool mutating; + bool isMutating; FunctionDecl( std::string name, @@ -94,14 +94,14 @@ NODE(FunctionDecl, TypeExpression returnType, Scope functionBody, bool isMethod, - bool mutating + bool isMutating ) : name(std::move(name)), parameters(std::move(parameters)), returnType(std::move(returnType)), functionBody(std::move(functionBody)), isMethod(isMethod), - mutating(mutating) {} + isMutating(isMutating) {} ); /// The only unary operator diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 063555df..26e81121 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -52,6 +52,7 @@ %type variable_decl %type function_decl %type > parameters +%type >> type_list type_list_ne %type parameter %type type_expr %type name_type @@ -142,12 +143,60 @@ parameter } ; +type_list + : %empty + { $$ = std::vector>(); } + | type_expr[expr] + { + $$ = std::vector>(); + $$.push_back(std::make_unique(std::move($expr))); + } + | type_list[list] COMMA type_expr[expr] + { + $list.push_back(std::make_unique(std::move($expr))); + $$ = std::move($list); + } + ; + +type_list_ne + : type_expr[expr] + { + $$ = std::vector>(); + $$.push_back(std::make_unique(std::move($expr))); + } + | type_list[list] COMMA type_expr[expr] + { + $list.push_back(std::make_unique(std::move($expr))); + $$ = std::move($list); + } + ; + function_type - : LPAREN parameters[params] RPAREN THIN_ARROW type_expr[ret_type] + : LPAREN type_list[params] RPAREN THIN_ARROW type_expr[ret_type] + { + $$ = ast::nodes::FunctionType( + std::move($params), + std::make_unique(std::move($ret_type)), + false, + false + ); + } + | LPAREN THIS type_list_ne[params] RPAREN THIN_ARROW type_expr[ret_type] + { + $$ = ast::nodes::FunctionType( + std::move($params), + std::make_unique(std::move($ret_type)), + true, + false + ); + } + | LPAREN THIS type_list_ne[params] RPAREN MUT THIN_ARROW type_expr[ret_type] { $$ = ast::nodes::FunctionType( std::move($params), - std::make_unique(std::move($ret_type)) + std::make_unique(std::move($ret_type)), + true, + true ); } ; From c210f0a2525c3bf7890d52a83d6ea4b60181189e Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 27 May 2026 15:48:38 +0200 Subject: [PATCH 042/154] add method functions --- src/grammar/parser.y | 45 +++++++++++++++++++++++++++++++++++++++++++- test-parser/main.zn | 4 ++-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 26e81121..b8befb94 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -51,7 +51,7 @@ %type declaration %type variable_decl %type function_decl -%type > parameters +%type > parameters method_parameters %type >> type_list type_list_ne %type parameter %type type_expr @@ -116,6 +116,49 @@ function_decl false ); } + | type_expr[return_type] IDENT[name] LPAREN method_parameters[params] RPAREN scope[body] + { + $$ = ast::nodes::FunctionDecl( + std::move($name), + std::move($params), + std::move($return_type), + std::move($body), + true, + false + ); + } + + | type_expr[return_type] IDENT[name] LPAREN method_parameters[params] RPAREN MUT scope[body] + { + $$ = ast::nodes::FunctionDecl( + std::move($name), + std::move($params), + std::move($return_type), + std::move($body), + true, + true + ); + } + ; + +method_parameters + : %empty + { $$ = std::vector(); } + | THIS type_expr[type] + { + $$ = std::vector(); + $$.push_back(std::move( + ast::nodes::Parameter( + std::make_unique(std::move($type)), + "this" + ) + )); + } + | method_parameters[params] COMMA parameter[p] + { + $params.push_back(std::move($p)); + $$ = std::move($params); + } ; parameters diff --git a/test-parser/main.zn b/test-parser/main.zn index ed095601..5993801e 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,7 +1,7 @@ -Void main(b Int, a Bool) { +Void main(this Int, a Bool) { print(2, 2) Std$print(1 + 1 + 3 + 4) @Intrinsics$print("hello") test Int = 3 - func (Int) -> Void = 3 + func (Int) -> Void = 3.0 } From 0eb744f4106b19439c00b2cf5f3510d634c5a8ab Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 27 May 2026 16:03:20 +0200 Subject: [PATCH 043/154] split methods and functions --- src/ast/evaluators/to_string.hpp | 16 ++++++++++++++-- src/ast/nodes.hpp | 25 ++++++++++++++++++++----- src/grammar/parser.y | 18 ++++++++++-------- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index fdb0dc62..55374c90 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -200,8 +200,6 @@ std::string operator()(const nodes::VariableDecl& declaration) const { std::string operator()(const nodes::FunctionDecl& declaration) const { std::vector children; - children.push_back(detail::tree::leaf("isMethod", declaration.isMethod ? "true" : "false")); - children.push_back(detail::tree::leaf("isMutating", declaration.isMutating ? "true" : "false")); for (std::size_t i = 0; i < declaration.parameters.size(); ++i) { children.push_back(detail::tree::branch("parameter[" + std::to_string(i) + "]", render(declaration.parameters[i]))); @@ -213,6 +211,20 @@ std::string operator()(const nodes::FunctionDecl& declaration) const { return detail::tree::node("FunctionDecl " + declaration.name, children); } +std::string operator()(const nodes::MethodDecl& declaration) const { + std::vector children; + children.push_back(detail::tree::leaf("isMutating", declaration.isMutating ? "true" : "false")); + + for (std::size_t i = 0; i < declaration.parameters.size(); ++i) { + children.push_back(detail::tree::branch("parameter[" + std::to_string(i) + "]", render(declaration.parameters[i]))); + } + + children.push_back(detail::tree::branch("returnType", render(declaration.returnType))); + children.push_back(detail::tree::branch("functionBody", render(declaration.functionBody))); + + return detail::tree::node("MethodDecl " + declaration.name, children); +} + std::string operator()(const nodes::Declaration& declaration) const { return std::visit(*this, declaration); } diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index 5294e2fe..7b1123dd 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -85,22 +85,37 @@ NODE(FunctionDecl, std::vector parameters; TypeExpression returnType; Scope functionBody; - bool isMethod; - bool isMutating; FunctionDecl( + std::string name, + std::vector parameters, + TypeExpression returnType, + Scope functionBody + ) + : name(std::move(name)), + parameters(std::move(parameters)), + returnType(std::move(returnType)), + functionBody(std::move(functionBody)) {} +); + +NODE(MethodDecl, + std::string name; + std::vector parameters; + TypeExpression returnType; + Scope functionBody; + bool isMutating; + + MethodDecl( std::string name, std::vector parameters, TypeExpression returnType, Scope functionBody, - bool isMethod, bool isMutating ) : name(std::move(name)), parameters(std::move(parameters)), returnType(std::move(returnType)), functionBody(std::move(functionBody)), - isMethod(isMethod), isMutating(isMutating) {} ); @@ -187,7 +202,7 @@ NODE(Statement, explicit Statement(T value) : data(std::move(value)) {} ); -using Declaration = std::variant; +using Declaration = std::variant; NODE(Package, std::vector declarations; diff --git a/src/grammar/parser.y b/src/grammar/parser.y index b8befb94..8f168f3a 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -51,6 +51,7 @@ %type declaration %type variable_decl %type function_decl +%type method_decl %type > parameters method_parameters %type >> type_list type_list_ne %type parameter @@ -91,6 +92,8 @@ global_scope declaration : function_decl[fd] { $$ = ast::nodes::Declaration(std::move($fd)); } + | method_decl[md] + { $$ = ast::nodes::Declaration(std::move($md)); } ; variable_decl @@ -111,31 +114,30 @@ function_decl std::move($name), std::move($params), std::move($return_type), - std::move($body), - false, - false + std::move($body) ); } - | type_expr[return_type] IDENT[name] LPAREN method_parameters[params] RPAREN scope[body] + ; + +method_decl + : type_expr[return_type] IDENT[name] LPAREN method_parameters[params] RPAREN scope[body] { - $$ = ast::nodes::FunctionDecl( + $$ = ast::nodes::MethodDecl( std::move($name), std::move($params), std::move($return_type), std::move($body), - true, false ); } | type_expr[return_type] IDENT[name] LPAREN method_parameters[params] RPAREN MUT scope[body] { - $$ = ast::nodes::FunctionDecl( + $$ = ast::nodes::MethodDecl( std::move($name), std::move($params), std::move($return_type), std::move($body), - true, true ); } From 3ec7578c601c923735b99307522f250ea04372b9 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 27 May 2026 16:10:15 +0200 Subject: [PATCH 044/154] also split FunctionType/MethodType --- src/ast/evaluators/to_string.hpp | 19 +++++++++++++++++-- src/ast/nodes.hpp | 19 ++++++++++++++----- src/grammar/parser.y | 18 ++++++++++-------- test-parser/main.zn | 2 +- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp index 55374c90..362f3852 100644 --- a/src/ast/evaluators/to_string.hpp +++ b/src/ast/evaluators/to_string.hpp @@ -156,12 +156,27 @@ std::string operator()(const nodes::FunctionType& type) const { if (type.returnType != nullptr) { children.push_back(detail::tree::branch("returnType", render(*type.returnType))); } - children.push_back(detail::tree::leaf("isMethod", type.isMethod ? "true" : "false")); - children.push_back(detail::tree::leaf("isMutating", type.isMutating ? "true" : "false")); return detail::tree::node("FunctionType", children); } +std::string operator()(const nodes::MethodType& type) const { + std::vector children; + for (std::size_t i = 0; i < type.parameters.size(); ++i) { + children.push_back(detail::tree::branch( + "parameter[" + std::to_string(i) + "]", + std::visit(*this, type.parameters[i]->data) + )); + } + + if (type.returnType != nullptr) { + children.push_back(detail::tree::branch("returnType", render(*type.returnType))); + } + children.push_back(detail::tree::leaf("isMutating", type.isMutating ? "true" : "false")); + + return detail::tree::node("MethodType", children); +} + std::string operator()(const nodes::TypeExpression& expression) const { return std::visit(*this, expression.data); } diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index 7b1123dd..d63cbd12 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -39,20 +39,29 @@ NODE(Parameter, NODE(FunctionType, std::vector> parameters; std::unique_ptr returnType; - bool isMethod; - bool isMutating; FunctionType( + std::vector> parameters, + std::unique_ptr returnType + ) + : parameters(std::move(parameters)), returnType(std::move(returnType)) {} +); + +NODE(MethodType, + std::vector> parameters; + std::unique_ptr returnType; + bool isMutating; + + MethodType( std::vector> parameters, std::unique_ptr returnType, - bool isMethod, bool isMutating ) - : parameters(std::move(parameters)), returnType(std::move(returnType)), isMethod(isMethod), isMutating(isMutating) {} + : parameters(std::move(parameters)), returnType(std::move(returnType)), isMutating(isMutating) {} ); NODE(TypeExpression, - std::variant data; + std::variant data; template explicit TypeExpression(T value) : data(std::move(value)) {} diff --git a/src/grammar/parser.y b/src/grammar/parser.y index 8f168f3a..d094bbc6 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -58,6 +58,7 @@ %type type_expr %type name_type %type function_type +%type method_type %type scope %type >> statements %type statement @@ -221,26 +222,25 @@ function_type { $$ = ast::nodes::FunctionType( std::move($params), - std::make_unique(std::move($ret_type)), - false, - false + std::make_unique(std::move($ret_type)) ); } - | LPAREN THIS type_list_ne[params] RPAREN THIN_ARROW type_expr[ret_type] + ; + +method_type + : LPAREN THIS type_list_ne[params] RPAREN THIN_ARROW type_expr[ret_type] { - $$ = ast::nodes::FunctionType( + $$ = ast::nodes::MethodType( std::move($params), std::make_unique(std::move($ret_type)), - true, false ); } | LPAREN THIS type_list_ne[params] RPAREN MUT THIN_ARROW type_expr[ret_type] { - $$ = ast::nodes::FunctionType( + $$ = ast::nodes::MethodType( std::move($params), std::make_unique(std::move($ret_type)), - true, true ); } @@ -251,6 +251,8 @@ type_expr { $$ = ast::nodes::TypeExpression(std::move($nt)); } | function_type[ft] { $$ = ast::nodes::TypeExpression(std::move($ft)); } + | method_type[mt] + { $$ = ast::nodes::TypeExpression(std::move($mt)); } ; name_type diff --git a/test-parser/main.zn b/test-parser/main.zn index 5993801e..470a0f85 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -3,5 +3,5 @@ Void main(this Int, a Bool) { Std$print(1 + 1 + 3 + 4) @Intrinsics$print("hello") test Int = 3 - func (Int) -> Void = 3.0 + func (this Int) -> Void = 3.0 } From ef73f8385b06f5d5eef0335bf2f2cae5b88d0157 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 27 May 2026 23:42:35 +0200 Subject: [PATCH 045/154] update --- src/ast/evaluators/.hpp | 2 +- src/ast/evaluators/to-graph.hpp | 191 ++++++++++++++++++++ src/ast/evaluators/to_string.hpp | 290 ------------------------------- src/main.cpp | 3 +- src/treegraph/.hpp | 3 + src/treegraph/build.hpp | 26 +++ src/treegraph/evaluator.hpp | 155 +++++++++++++++++ src/treegraph/structure.hpp | 43 +++++ 8 files changed, 421 insertions(+), 292 deletions(-) create mode 100644 src/ast/evaluators/to-graph.hpp delete mode 100644 src/ast/evaluators/to_string.hpp create mode 100644 src/treegraph/.hpp create mode 100644 src/treegraph/build.hpp create mode 100644 src/treegraph/evaluator.hpp create mode 100644 src/treegraph/structure.hpp diff --git a/src/ast/evaluators/.hpp b/src/ast/evaluators/.hpp index 66fdbeb5..6093a430 100644 --- a/src/ast/evaluators/.hpp +++ b/src/ast/evaluators/.hpp @@ -1,3 +1,3 @@ #pragma once -#include "ast/evaluators/to_string.hpp" +#include "ast/evaluators/to-graph.hpp" diff --git a/src/ast/evaluators/to-graph.hpp b/src/ast/evaluators/to-graph.hpp new file mode 100644 index 00000000..12c29f3f --- /dev/null +++ b/src/ast/evaluators/to-graph.hpp @@ -0,0 +1,191 @@ +#pragma once + +#include "ast/nodes.hpp" +#include "treegraph/build.hpp" +#include "treegraph/structure.hpp" +#include +#include + +namespace ast::evaluators { + +struct ToGraph { + + treegraph::Node operator()(const nodes::IntLiteral& literal) const { + return treegraph::Node{"\"" + literal.data + "\""}; + } + + treegraph::Node operator()(const nodes::FloatLiteral& literal) const { + return treegraph::Node{"\"" + literal.data + "\""}; + } + + treegraph::Node operator()(const nodes::StringLiteral& literal) const { + return treegraph::Node{"\"" + literal.data + "\""}; + } + + treegraph::Node operator()(const nodes::IntrinsicValueSymbol& symbol) const { + return treegraph::Node{"@" + symbol.package + "$" + symbol.name}; + } + + treegraph::Node operator()(const nodes::PackageValueSymbol& symbol) const { + return treegraph::Node{symbol.package + "$" + symbol.name}; + } + + treegraph::Node operator()(const nodes::ValueSymbol& symbol) const { + return treegraph::Node{symbol.name}; + } + + treegraph::Node operator()(const nodes::OperatorFlipCall& call) const { + treegraph::Table table; + if (call.value != nullptr) + table.insert("Value", treegraph::ptr((*this)(*call.value))); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::OperatorCall& call) const { + treegraph::Table table; + table.insert("Operator", treegraph::string(call.op)); + if (call.left != nullptr) + table.insert("Left", treegraph::ptr((*this)(*call.left))); + if (call.right != nullptr) + table.insert("Right", treegraph::ptr((*this)(*call.right))); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::FunctionCall& call) const { + treegraph::Table table; + if (call.callee != nullptr) + table.insert("Callee", treegraph::ptr((*this)(*call.callee))); + treegraph::List arguments; + for (const auto& argument : call.arguments) + if (argument != nullptr) + arguments.push({}, treegraph::ptr((*this)(*argument))); + if (!arguments.children.empty()) + table.insert("Arguments", treegraph::list(std::move(arguments))); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::NameType& type) const { + treegraph::Table table; + table.insert("Name", treegraph::string(type.name)); + treegraph::List generics; + for (const auto& generic : type.generics) + if (generic != nullptr) + generics.push({}, treegraph::ptr((*this)(*generic))); + if (!generics.children.empty()) + table.insert("Generics", treegraph::list(std::move(generics))); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::FunctionType& type) const { + treegraph::Table table; + treegraph::List parameters; + for (const auto& parameter : type.parameters) + if (parameter != nullptr) + parameters.push({}, treegraph::ptr(std::visit([this](const auto& p) { return (*this)(p); }, parameter->data))); + if (!parameters.children.empty()) + table.insert("Parameters", treegraph::list(std::move(parameters))); + if (type.returnType != nullptr) + table.insert("ReturnType", treegraph::ptr((*this)(*type.returnType))); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::MethodType& type) const { + treegraph::Table table; + treegraph::List parameters; + for (const auto& parameter : type.parameters) + if (parameter != nullptr) + parameters.push({}, treegraph::ptr(std::visit([this](const auto& p) { return (*this)(p); }, parameter->data))); + if (!parameters.children.empty()) + table.insert("Parameters", treegraph::list(std::move(parameters))); + if (type.returnType != nullptr) + table.insert("ReturnType", treegraph::ptr((*this)(*type.returnType))); + table.insert("IsMutating", treegraph::string(type.isMutating ? "true" : "false")); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::TypeExpression& expression) const { + return std::visit([this](const auto& e) { return (*this)(e); }, expression.data); + } + + treegraph::Node operator()(const nodes::Parameter& parameter) const { + treegraph::Table table; + table.insert("Name", treegraph::string(parameter.name)); + if (parameter.type != nullptr) + table.insert("Type", treegraph::ptr((*this)(*parameter.type))); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::Statement& statement) const { + return std::visit([this](const auto& s) { return (*this)(s); }, statement.data); + } + + treegraph::Node operator()(const nodes::Scope& scope) const { + treegraph::Table table; + treegraph::List statements; + for (const auto& statement : scope.statements) + if (statement != nullptr) + statements.push({}, treegraph::ptr((*this)(*statement))); + if (!statements.children.empty()) + table.insert("Statements", treegraph::list(std::move(statements))); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::VariableDecl& declaration) const { + treegraph::Table table; + table.insert("Name", treegraph::string(declaration.name)); + table.insert("Type", treegraph::ptr((*this)(declaration.type))); + table.insert("Value", treegraph::ptr((*this)(*declaration.value))); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::FunctionDecl& declaration) const { + treegraph::Table table; + table.insert("Name", treegraph::string(declaration.name)); + treegraph::List parameters; + for (const auto& parameter : declaration.parameters) + parameters.push({}, treegraph::ptr((*this)(parameter))); + if (!parameters.children.empty()) + table.insert("Parameters", treegraph::list(std::move(parameters))); + table.insert("ReturnType", treegraph::ptr((*this)(declaration.returnType))); + table.insert("FunctionBody", treegraph::ptr((*this)(declaration.functionBody))); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::MethodDecl& declaration) const { + treegraph::Table table; + table.insert("Name", treegraph::string(declaration.name)); + table.insert("IsMutating", treegraph::string(declaration.isMutating ? "true" : "false")); + treegraph::List parameters; + for (const auto& parameter : declaration.parameters) + parameters.push({}, treegraph::ptr((*this)(parameter))); + if (!parameters.children.empty()) + table.insert("Parameters", treegraph::list(std::move(parameters))); + table.insert("ReturnType", treegraph::ptr((*this)(declaration.returnType))); + table.insert("FunctionBody", treegraph::ptr((*this)(declaration.functionBody))); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::Declaration& declaration) const { + return std::visit([this](const auto& d) { return (*this)(d); }, declaration); + } + + treegraph::Node operator()(const nodes::Package& package) const { + treegraph::Table table; + treegraph::List declarations; + for (const auto& declaration : package.declarations) + declarations.push({}, treegraph::ptr((*this)(declaration))); + if (!declarations.children.empty()) + table.insert("Declarations", treegraph::list(std::move(declarations))); + return treegraph::Node{std::move(table)}; + } + + treegraph::Node operator()(const nodes::ParenthizedValue& expression) const { + return (*this)(*expression.data); + } + + treegraph::Node operator()(const nodes::ValueExpr& expression) const { + return std::visit([this](const auto& e) { return (*this)(e); }, expression.data); + } +}; + +} // namespace ast::evaluators diff --git a/src/ast/evaluators/to_string.hpp b/src/ast/evaluators/to_string.hpp deleted file mode 100644 index 362f3852..00000000 --- a/src/ast/evaluators/to_string.hpp +++ /dev/null @@ -1,290 +0,0 @@ -#pragma once - -#include "ast/nodes.hpp" -#include -#include -#include -#include - -namespace ast::evaluators { - -namespace detail::tree { - -inline std::vector splitLines(const std::string& text) { - std::istringstream input(text); - std::vector lines; - std::string line; - - while (std::getline(input, line)) { - lines.push_back(line); - } - - return lines; -} - -inline std::string indent(const std::string& text, const std::string& prefix) { - const std::vector lines = splitLines(text); - if (lines.empty()) { - return {}; - } - - std::string result = lines.front(); - for (std::size_t i = 1; i < lines.size(); ++i) { - result += "\n" + prefix + lines[i]; - } - - return result; -} - -inline std::string leaf(const std::string& label, const std::string& value) { - return label + ": " + value; -} - -inline std::string branch(const std::string& label, const std::string& subtree) { - const std::vector lines = splitLines(subtree); - if (lines.empty()) { - return label; - } - - std::string result = label + ": " + lines.front(); - for (std::size_t i = 1; i < lines.size(); ++i) { - result += "\n " + lines[i]; - } - - return result; -} - -inline std::string node(const std::string& label, const std::vector& children) { - if (children.empty()) { - return label; - } - - std::string result = label; - for (std::size_t i = 0; i < children.size(); ++i) { - result += "\n"; - result += i + 1 == children.size() ? "└── " : "├── "; - result += indent(children[i], i + 1 == children.size() ? " " : "│ "); - } - - return result; -} - -} // namespace detail::tree - -struct ToString { -std::string operator()(const nodes::IntLiteral& literal) const { - return detail::tree::node("IntLiteral \"" + literal.data + "\"", {}); -} - -std::string operator()(const nodes::FloatLiteral& literal) const { - return detail::tree::node("FloatLiteral \"" + literal.data + "\"", {}); -} - -std::string operator()(const nodes::StringLiteral& literal) const { - return detail::tree::node("StringLiteral \"" + literal.data + "\"", {}); -} - -std::string operator()(const nodes::IntrinsicValueSymbol& symbol) const { - return detail::tree::node("IntrinsicValueSymbol @" + symbol.package + "$" + symbol.name, {}); -} - -std::string operator()(const nodes::PackageValueSymbol& symbol) const { - return detail::tree::node("PackageValueSymbol " + symbol.package + "$" + symbol.name, {}); -} - -std::string operator()(const nodes::ValueSymbol& symbol) const { - return detail::tree::node("ValueSymbol " + symbol.name, {}); -} - -std::string operator()(const nodes::OperatorFlipCall& call) const { - std::vector children; - if (call.value != nullptr) { - children.push_back(detail::tree::branch("value", render(*call.value))); - } - - return detail::tree::node("OperatorCall", children); -} - -std::string operator()(const nodes::OperatorCall& call) const { - std::vector children; - children.push_back(detail::tree::branch("op", call.op)); - if (call.left != nullptr) { - children.push_back(detail::tree::branch("left", render(*call.left))); - } - if (call.right != nullptr) { - children.push_back(detail::tree::branch("right", render(*call.right))); - } - - return detail::tree::node("OperatorCall", children); -} - -std::string operator()(const nodes::FunctionCall& call) const { - std::vector children; - if (call.callee != nullptr) { - children.push_back(detail::tree::branch("callee", render(*call.callee))); - } - - for (std::size_t i = 0; i < call.arguments.size(); ++i) { - if (call.arguments[i] != nullptr) { - children.push_back(detail::tree::branch("argument[" + std::to_string(i) + "]", render(*call.arguments[i]))); - } - } - - return detail::tree::node("FunctionCall", children); -} - -std::string operator()(const nodes::NameType& type) const { - std::vector children; - for (std::size_t i = 0; i < type.generics.size(); ++i) { - if (type.generics[i] != nullptr) { - children.push_back(detail::tree::branch("generic[" + std::to_string(i) + "]", render(*type.generics[i]))); - } - } - - return detail::tree::node("NameType " + type.name, children); -} - -std::string operator()(const nodes::FunctionType& type) const { - std::vector children; - for (std::size_t i = 0; i < type.parameters.size(); ++i) { - children.push_back(detail::tree::branch( - "parameter[" + std::to_string(i) + "]", - std::visit(*this, type.parameters[i]->data) - )); - } - - if (type.returnType != nullptr) { - children.push_back(detail::tree::branch("returnType", render(*type.returnType))); - } - - return detail::tree::node("FunctionType", children); -} - -std::string operator()(const nodes::MethodType& type) const { - std::vector children; - for (std::size_t i = 0; i < type.parameters.size(); ++i) { - children.push_back(detail::tree::branch( - "parameter[" + std::to_string(i) + "]", - std::visit(*this, type.parameters[i]->data) - )); - } - - if (type.returnType != nullptr) { - children.push_back(detail::tree::branch("returnType", render(*type.returnType))); - } - children.push_back(detail::tree::leaf("isMutating", type.isMutating ? "true" : "false")); - - return detail::tree::node("MethodType", children); -} - -std::string operator()(const nodes::TypeExpression& expression) const { - return std::visit(*this, expression.data); -} - -std::string operator()(const nodes::Parameter& parameter) const { - std::vector children; - if (parameter.type != nullptr) { - children.push_back(detail::tree::branch("type", render(*parameter.type))); - } - - return detail::tree::node("Parameter " + parameter.name, children); -} - -std::string operator()(const nodes::Statement& statement) const { - return std::visit(*this, statement.data); -} - -std::string operator()(const nodes::Scope& scope) const { - std::vector children; - for (std::size_t i = 0; i < scope.statements.size(); ++i) { - if (scope.statements[i] != nullptr) { - children.push_back(detail::tree::branch("statement[" + std::to_string(i) + "]", render(*scope.statements[i]))); - } - } - - return detail::tree::node("Scope", children); -} - -std::string operator()(const nodes::VariableDecl& declaration) const { - std::vector children; - children.push_back(detail::tree::branch("type", render(declaration.type))); - children.push_back(detail::tree::branch("value", render(*declaration.value))); - - return detail::tree::node("VariableDecl " + declaration.name, children); -} - -std::string operator()(const nodes::FunctionDecl& declaration) const { - std::vector children; - - for (std::size_t i = 0; i < declaration.parameters.size(); ++i) { - children.push_back(detail::tree::branch("parameter[" + std::to_string(i) + "]", render(declaration.parameters[i]))); - } - - children.push_back(detail::tree::branch("returnType", render(declaration.returnType))); - children.push_back(detail::tree::branch("functionBody", render(declaration.functionBody))); - - return detail::tree::node("FunctionDecl " + declaration.name, children); -} - -std::string operator()(const nodes::MethodDecl& declaration) const { - std::vector children; - children.push_back(detail::tree::leaf("isMutating", declaration.isMutating ? "true" : "false")); - - for (std::size_t i = 0; i < declaration.parameters.size(); ++i) { - children.push_back(detail::tree::branch("parameter[" + std::to_string(i) + "]", render(declaration.parameters[i]))); - } - - children.push_back(detail::tree::branch("returnType", render(declaration.returnType))); - children.push_back(detail::tree::branch("functionBody", render(declaration.functionBody))); - - return detail::tree::node("MethodDecl " + declaration.name, children); -} - -std::string operator()(const nodes::Declaration& declaration) const { - return std::visit(*this, declaration); -} - -std::string operator()(const nodes::Package& package) const { - std::vector children; - for (std::size_t i = 0; i < package.declarations.size(); ++i) { - children.push_back(detail::tree::branch("declaration[" + std::to_string(i) + "]", render(package.declarations[i]))); - } - - return detail::tree::node("Package", children); -} - -std::string operator()(const nodes::ParenthizedValue& expression) const { - return std::visit(*this, expression.data->data); -} - -std::string operator()(const nodes::ValueExpr& expression) const { - return std::visit(*this, expression.data); -} - -private: -std::string render(const nodes::ValueExpr& expression) const { - return (*this)(expression); -} - -std::string render(const nodes::TypeExpression& expression) const { - return (*this)(expression); -} - -std::string render(const nodes::Parameter& parameter) const { - return (*this)(parameter); -} - -std::string render(const nodes::Statement& statement) const { - return (*this)(statement); -} - -std::string render(const nodes::Scope& scope) const { - return (*this)(scope); -} - -std::string render(const nodes::Declaration& declaration) const { - return (*this)(declaration); -} -}; - -} // namespace evaluators diff --git a/src/main.cpp b/src/main.cpp index 8c7c5a69..d618d447 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include "ast/.hpp" #include "parser.tab.h" +#include "treegraph/evaluator.hpp" #include #include #include @@ -31,7 +32,7 @@ int main() { int res = parser.parse(); if (ast != nullptr) { - std::cout << ast::evaluators::ToString{}(*ast) << '\n'; + std::cout << treegraph::Evaluator{}.render(ast::evaluators::ToGraph{}(*ast)) << '\n'; delete ast; } diff --git a/src/treegraph/.hpp b/src/treegraph/.hpp new file mode 100644 index 00000000..99315947 --- /dev/null +++ b/src/treegraph/.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "treegraph/evaluator.hpp" diff --git a/src/treegraph/build.hpp b/src/treegraph/build.hpp new file mode 100644 index 00000000..d5cf588b --- /dev/null +++ b/src/treegraph/build.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "treegraph/structure.hpp" +#include +#include +#include + +namespace treegraph { + +inline std::unique_ptr ptr(Node node) { + return std::make_unique(std::move(node)); +} + +inline std::unique_ptr string(std::string value) { + return ptr(Node{std::move(value)}); +} + +inline std::unique_ptr table(Table table) { + return ptr(Node{std::move(table)}); +} + +inline std::unique_ptr list(List list) { + return ptr(Node{std::move(list)}); +} + +} // namespace treegraph diff --git a/src/treegraph/evaluator.hpp b/src/treegraph/evaluator.hpp new file mode 100644 index 00000000..c2582fa9 --- /dev/null +++ b/src/treegraph/evaluator.hpp @@ -0,0 +1,155 @@ +#pragma once + +#include "treegraph/structure.hpp" +#include +#include +#include + +namespace treegraph { + +namespace detail { + +inline std::vector splitLines(const std::string& text) { + std::istringstream ss(text); + std::vector lines; + std::string line; + while (std::getline(ss, line)) + lines.push_back(line); + return lines; +} + +// Indents every line after the first with `prefix`. +inline std::string indent(const std::string& text, const std::string& prefix) { + const auto lines = splitLines(text); + if (lines.empty()) return {}; + std::string result = lines.front(); + for (std::size_t i = 1; i < lines.size(); ++i) + result += "\n" + prefix + lines[i]; + return result; +} + +// Renders a single named branch: "label: firstLine\n continuation..." +inline std::string branch(const std::string& label, const std::string& subtree) { + const auto lines = splitLines(subtree); + if (lines.empty()) return label; + std::string result = label + ": " + lines.front(); + for (std::size_t i = 1; i < lines.size(); ++i) + result += "\n " + lines[i]; + return result; +} + +// Renders a labelled node with ├──/└── children. +inline std::string node(const std::string& label, const std::vector& children) { + if (children.empty()) return label; + std::string result = label; + for (std::size_t i = 0; i < children.size(); ++i) { + const bool last = (i + 1 == children.size()); + result += "\n"; + result += last ? "└── " : "├── "; + result += indent(children[i], last ? " " : "│ "); + } + return result; +} + +} // namespace detail + +struct Evaluator { + std::string render(const Node& node) const { + return std::visit([&](const auto& data) { + return (*this)(data); + }, node.data); + } + + std::string render(const std::string& key, const Node& node) const { + return std::visit([&](const auto& data) { + return renderWith(key, data); + }, node.data); + } + + std::string operator()(const Node& node) const { return render(node); } + + std::string operator()(const std::string& key, const Node& node) const { return render(key, node); } + + std::string operator()(const Table& table) const { + std::vector rows; + for (const auto& [key, child] : table.children) + appendRenderedChild(rows, key, *child); + return joinLines(rows); + } + + std::string operator()(const List& list) const { + std::vector items; + for (const auto& [key, child] : list.children) + items.push_back(render(key, *child)); + return joinLines(items); + } + + std::string operator()(const std::string& str) const { return str; } + +private: + void appendRenderedChild(std::vector& rows, const std::string& key, const Node& node) const { + if (const auto* list = std::get_if(&node.data)) { + const auto items = renderListEntries(key, *list); + rows.insert(rows.end(), items.begin(), items.end()); + return; + } + rows.push_back(render(key, node)); + } + + std::vector renderListEntries(const std::string& key, const List& list) const { + std::vector children; + for (std::size_t i = 0; i < list.children.size(); ++i) { + const auto& [itemKey, child] = list.children[i]; + children.push_back(render(key + "[" + std::to_string(i) + "]", itemKey, *child)); + } + return children; + } + + std::string render(const std::string& indexedKey, const std::string& itemKey, const Node& node) const { + return std::visit([&](const auto& data) { + return renderIndexed(indexedKey, itemKey, data); + }, node.data); + } + + std::string renderWith(const std::string& key, const std::string& value) const { + return value.empty() ? key : key + ": " + value; + } + + std::string renderWith(const std::string& key, const Table& table) const { + std::vector children; + for (const auto& [childKey, child] : table.children) + appendRenderedChild(children, childKey, *child); + return detail::node(key, children); + } + + std::string renderWith(const std::string& key, const List& list) const { + return detail::node(key, renderListEntries(key, list)); + } + + std::string renderIndexed(const std::string& indexedKey, const std::string& itemKey, const std::string& value) const { + const auto label = value.empty() ? itemKey : itemKey + ": " + value; + return detail::node(indexedKey, {label}); + } + + std::string renderIndexed(const std::string& indexedKey, const std::string& itemKey, const Table& table) const { + std::vector children; + for (const auto& [childKey, child] : table.children) + appendRenderedChild(children, childKey, *child); + return detail::node(indexedKey, {detail::node(itemKey, children)}); + } + + std::string renderIndexed(const std::string& indexedKey, const std::string& itemKey, const List& list) const { + return detail::node(indexedKey, {detail::node(itemKey, renderListEntries(indexedKey, list))}); + } + + static std::string joinLines(const std::vector& parts) { + std::string result; + for (std::size_t i = 0; i < parts.size(); ++i) { + if (i > 0) result += "\n"; + result += parts[i]; + } + return result; + } +}; + +} // namespace treegraph diff --git a/src/treegraph/structure.hpp b/src/treegraph/structure.hpp new file mode 100644 index 00000000..4b0d81e1 --- /dev/null +++ b/src/treegraph/structure.hpp @@ -0,0 +1,43 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace treegraph { + +struct Node; + +struct Table { + std::map> children; + + Table() = default; + explicit Table(std::map> children) + : children(std::move(children)) {} + + Table& insert(std::string key, std::unique_ptr node) { + children.insert_or_assign(std::move(key), std::move(node)); + return *this; + } +}; + +struct List { + std::vector>> children; + + List() = default; + explicit List(std::vector>> children) + : children(std::move(children)) {} + + List& push(std::string key, std::unique_ptr node) { + children.emplace_back(std::move(key), std::move(node)); + return *this; + } +}; + +struct Node { + std::variant data; +}; + +} // namespace treegraph From 54b9cbe38baab2037e3c423b4c29aa4db93b0a78 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 27 May 2026 23:46:28 +0200 Subject: [PATCH 046/154] update --- src/ast/evaluators/to-graph.hpp | 30 +++++++++++++++--------------- src/treegraph/evaluator.hpp | 6 ++++++ src/treegraph/structure.hpp | 5 +++++ 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/ast/evaluators/to-graph.hpp b/src/ast/evaluators/to-graph.hpp index 12c29f3f..c356ccc8 100644 --- a/src/ast/evaluators/to-graph.hpp +++ b/src/ast/evaluators/to-graph.hpp @@ -11,34 +11,34 @@ namespace ast::evaluators { struct ToGraph { treegraph::Node operator()(const nodes::IntLiteral& literal) const { - return treegraph::Node{"\"" + literal.data + "\""}; + return treegraph::Node("\"" + literal.data + "\""); } treegraph::Node operator()(const nodes::FloatLiteral& literal) const { - return treegraph::Node{"\"" + literal.data + "\""}; + return treegraph::Node("\"" + literal.data + "\""); } treegraph::Node operator()(const nodes::StringLiteral& literal) const { - return treegraph::Node{"\"" + literal.data + "\""}; + return treegraph::Node("\"" + literal.data + "\""); } treegraph::Node operator()(const nodes::IntrinsicValueSymbol& symbol) const { - return treegraph::Node{"@" + symbol.package + "$" + symbol.name}; + return treegraph::Node("@" + symbol.package + "$" + symbol.name); } treegraph::Node operator()(const nodes::PackageValueSymbol& symbol) const { - return treegraph::Node{symbol.package + "$" + symbol.name}; + return treegraph::Node(symbol.package + "$" + symbol.name); } treegraph::Node operator()(const nodes::ValueSymbol& symbol) const { - return treegraph::Node{symbol.name}; + return treegraph::Node(symbol.name); } treegraph::Node operator()(const nodes::OperatorFlipCall& call) const { treegraph::Table table; if (call.value != nullptr) table.insert("Value", treegraph::ptr((*this)(*call.value))); - return treegraph::Node{std::move(table)}; + return treegraph::Node(std::move(table)); } treegraph::Node operator()(const nodes::OperatorCall& call) const { @@ -48,7 +48,7 @@ struct ToGraph { table.insert("Left", treegraph::ptr((*this)(*call.left))); if (call.right != nullptr) table.insert("Right", treegraph::ptr((*this)(*call.right))); - return treegraph::Node{std::move(table)}; + return treegraph::Node(std::move(table)); } treegraph::Node operator()(const nodes::FunctionCall& call) const { @@ -61,7 +61,7 @@ struct ToGraph { arguments.push({}, treegraph::ptr((*this)(*argument))); if (!arguments.children.empty()) table.insert("Arguments", treegraph::list(std::move(arguments))); - return treegraph::Node{std::move(table)}; + return treegraph::Node(std::move(table)); } treegraph::Node operator()(const nodes::NameType& type) const { @@ -73,7 +73,7 @@ struct ToGraph { generics.push({}, treegraph::ptr((*this)(*generic))); if (!generics.children.empty()) table.insert("Generics", treegraph::list(std::move(generics))); - return treegraph::Node{std::move(table)}; + return treegraph::Node(std::move(table)); } treegraph::Node operator()(const nodes::FunctionType& type) const { @@ -86,7 +86,7 @@ struct ToGraph { table.insert("Parameters", treegraph::list(std::move(parameters))); if (type.returnType != nullptr) table.insert("ReturnType", treegraph::ptr((*this)(*type.returnType))); - return treegraph::Node{std::move(table)}; + return treegraph::Node(std::move(table)); } treegraph::Node operator()(const nodes::MethodType& type) const { @@ -100,7 +100,7 @@ struct ToGraph { if (type.returnType != nullptr) table.insert("ReturnType", treegraph::ptr((*this)(*type.returnType))); table.insert("IsMutating", treegraph::string(type.isMutating ? "true" : "false")); - return treegraph::Node{std::move(table)}; + return treegraph::Node(std::move(table)); } treegraph::Node operator()(const nodes::TypeExpression& expression) const { @@ -112,7 +112,7 @@ struct ToGraph { table.insert("Name", treegraph::string(parameter.name)); if (parameter.type != nullptr) table.insert("Type", treegraph::ptr((*this)(*parameter.type))); - return treegraph::Node{std::move(table)}; + return treegraph::Node(std::move(table)); } treegraph::Node operator()(const nodes::Statement& statement) const { @@ -127,7 +127,7 @@ struct ToGraph { statements.push({}, treegraph::ptr((*this)(*statement))); if (!statements.children.empty()) table.insert("Statements", treegraph::list(std::move(statements))); - return treegraph::Node{std::move(table)}; + return treegraph::Node(std::move(table)); } treegraph::Node operator()(const nodes::VariableDecl& declaration) const { @@ -135,7 +135,7 @@ struct ToGraph { table.insert("Name", treegraph::string(declaration.name)); table.insert("Type", treegraph::ptr((*this)(declaration.type))); table.insert("Value", treegraph::ptr((*this)(*declaration.value))); - return treegraph::Node{std::move(table)}; + return treegraph::Node(std::move(table)); } treegraph::Node operator()(const nodes::FunctionDecl& declaration) const { diff --git a/src/treegraph/evaluator.hpp b/src/treegraph/evaluator.hpp index c2582fa9..93ff4482 100644 --- a/src/treegraph/evaluator.hpp +++ b/src/treegraph/evaluator.hpp @@ -127,6 +127,8 @@ struct Evaluator { } std::string renderIndexed(const std::string& indexedKey, const std::string& itemKey, const std::string& value) const { + if (itemKey.empty()) + return value.empty() ? indexedKey : indexedKey + ": " + value; const auto label = value.empty() ? itemKey : itemKey + ": " + value; return detail::node(indexedKey, {label}); } @@ -135,10 +137,14 @@ struct Evaluator { std::vector children; for (const auto& [childKey, child] : table.children) appendRenderedChild(children, childKey, *child); + if (itemKey.empty()) + return detail::node(indexedKey, children); return detail::node(indexedKey, {detail::node(itemKey, children)}); } std::string renderIndexed(const std::string& indexedKey, const std::string& itemKey, const List& list) const { + if (itemKey.empty()) + return detail::node(indexedKey, renderListEntries(indexedKey, list)); return detail::node(indexedKey, {detail::node(itemKey, renderListEntries(indexedKey, list))}); } diff --git a/src/treegraph/structure.hpp b/src/treegraph/structure.hpp index 4b0d81e1..c6e96a80 100644 --- a/src/treegraph/structure.hpp +++ b/src/treegraph/structure.hpp @@ -38,6 +38,11 @@ struct List { struct Node { std::variant data; + + Node() = default; + explicit Node(Table data) : data(std::move(data)) {} + explicit Node(List data) : data(std::move(data)) {} + explicit Node(std::string data) : data(std::move(data)) {} }; } // namespace treegraph From 9cfae321db811a94454e80bbdc0961a3105f018f Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 28 May 2026 13:53:41 +0200 Subject: [PATCH 047/154] add render method --- src/main.cpp | 2 +- src/treegraph/evaluator.hpp | 4 ++++ src/treegraph/structure.hpp | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index d618d447..b844c7f3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,7 +32,7 @@ int main() { int res = parser.parse(); if (ast != nullptr) { - std::cout << treegraph::Evaluator{}.render(ast::evaluators::ToGraph{}(*ast)) << '\n'; + std::cout << (ast::evaluators::ToGraph {}(*ast)).render(); delete ast; } diff --git a/src/treegraph/evaluator.hpp b/src/treegraph/evaluator.hpp index 93ff4482..646af9c8 100644 --- a/src/treegraph/evaluator.hpp +++ b/src/treegraph/evaluator.hpp @@ -158,4 +158,8 @@ struct Evaluator { } }; +inline std::string Node::render() const { + return Evaluator{}.render(*this); +} + } // namespace treegraph diff --git a/src/treegraph/structure.hpp b/src/treegraph/structure.hpp index c6e96a80..3da46509 100644 --- a/src/treegraph/structure.hpp +++ b/src/treegraph/structure.hpp @@ -43,6 +43,8 @@ struct Node { explicit Node(Table data) : data(std::move(data)) {} explicit Node(List data) : data(std::move(data)) {} explicit Node(std::string data) : data(std::move(data)) {} + + std::string render() const; }; } // namespace treegraph From aa63192728a2949510ed1c7be0ee39dad538c2ba Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 28 May 2026 14:09:13 +0200 Subject: [PATCH 048/154] update --- src/ast/evaluators/to-graph.hpp | 3 +-- src/main.cpp | 1 - src/treegraph/.hpp | 2 ++ 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ast/evaluators/to-graph.hpp b/src/ast/evaluators/to-graph.hpp index c356ccc8..8f2fd1a3 100644 --- a/src/ast/evaluators/to-graph.hpp +++ b/src/ast/evaluators/to-graph.hpp @@ -1,8 +1,7 @@ #pragma once #include "ast/nodes.hpp" -#include "treegraph/build.hpp" -#include "treegraph/structure.hpp" +#include "treegraph/.hpp" #include #include diff --git a/src/main.cpp b/src/main.cpp index b844c7f3..a7846a58 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,5 @@ #include "ast/.hpp" #include "parser.tab.h" -#include "treegraph/evaluator.hpp" #include #include #include diff --git a/src/treegraph/.hpp b/src/treegraph/.hpp index 99315947..766afa4c 100644 --- a/src/treegraph/.hpp +++ b/src/treegraph/.hpp @@ -1,3 +1,5 @@ #pragma once #include "treegraph/evaluator.hpp" +#include "treegraph/build.hpp" +#include "treegraph/structure.hpp" From 15acfe6f6defe3b45f26ec8990b440d106c90848 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 28 May 2026 14:53:33 +0200 Subject: [PATCH 049/154] update --- src/ast/evaluators/to-graph.hpp | 20 ++++++++++++-------- src/ast/nodes.hpp | 14 ++++++++++---- src/grammar/lexer.re | 1 + src/grammar/parser.y | 32 ++++++++++++++++++++++++++------ 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/ast/evaluators/to-graph.hpp b/src/ast/evaluators/to-graph.hpp index 8f2fd1a3..2885efc7 100644 --- a/src/ast/evaluators/to-graph.hpp +++ b/src/ast/evaluators/to-graph.hpp @@ -80,7 +80,7 @@ struct ToGraph { treegraph::List parameters; for (const auto& parameter : type.parameters) if (parameter != nullptr) - parameters.push({}, treegraph::ptr(std::visit([this](const auto& p) { return (*this)(p); }, parameter->data))); + parameters.push({}, treegraph::ptr(std::visit(*this, parameter->data))); if (!parameters.children.empty()) table.insert("Parameters", treegraph::list(std::move(parameters))); if (type.returnType != nullptr) @@ -93,7 +93,7 @@ struct ToGraph { treegraph::List parameters; for (const auto& parameter : type.parameters) if (parameter != nullptr) - parameters.push({}, treegraph::ptr(std::visit([this](const auto& p) { return (*this)(p); }, parameter->data))); + parameters.push({}, treegraph::ptr(std::visit(*this, parameter->data))); if (!parameters.children.empty()) table.insert("Parameters", treegraph::list(std::move(parameters))); if (type.returnType != nullptr) @@ -103,7 +103,7 @@ struct ToGraph { } treegraph::Node operator()(const nodes::TypeExpression& expression) const { - return std::visit([this](const auto& e) { return (*this)(e); }, expression.data); + return std::visit(*this, expression.data); } treegraph::Node operator()(const nodes::Parameter& parameter) const { @@ -115,7 +115,7 @@ struct ToGraph { } treegraph::Node operator()(const nodes::Statement& statement) const { - return std::visit([this](const auto& s) { return (*this)(s); }, statement.data); + return std::visit(*this, statement.data); } treegraph::Node operator()(const nodes::Scope& scope) const { @@ -137,6 +137,10 @@ struct ToGraph { return treegraph::Node(std::move(table)); } + treegraph::Node operator()(const nodes::ArrowBody& body) const { + return (*this)(*body.returnValue); + } + treegraph::Node operator()(const nodes::FunctionDecl& declaration) const { treegraph::Table table; table.insert("Name", treegraph::string(declaration.name)); @@ -146,7 +150,7 @@ struct ToGraph { if (!parameters.children.empty()) table.insert("Parameters", treegraph::list(std::move(parameters))); table.insert("ReturnType", treegraph::ptr((*this)(declaration.returnType))); - table.insert("FunctionBody", treegraph::ptr((*this)(declaration.functionBody))); + table.insert("FunctionBody", treegraph::ptr(std::visit(*this, declaration.functionBody))); return treegraph::Node{std::move(table)}; } @@ -160,12 +164,12 @@ struct ToGraph { if (!parameters.children.empty()) table.insert("Parameters", treegraph::list(std::move(parameters))); table.insert("ReturnType", treegraph::ptr((*this)(declaration.returnType))); - table.insert("FunctionBody", treegraph::ptr((*this)(declaration.functionBody))); + table.insert("FunctionBody", treegraph::ptr(std::visit(*this, declaration.functionBody))); return treegraph::Node{std::move(table)}; } treegraph::Node operator()(const nodes::Declaration& declaration) const { - return std::visit([this](const auto& d) { return (*this)(d); }, declaration); + return std::visit(*this, declaration); } treegraph::Node operator()(const nodes::Package& package) const { @@ -183,7 +187,7 @@ struct ToGraph { } treegraph::Node operator()(const nodes::ValueExpr& expression) const { - return std::visit([this](const auto& e) { return (*this)(e); }, expression.data); + return std::visit(*this, expression.data); } }; diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp index d63cbd12..70dfdd0c 100644 --- a/src/ast/nodes.hpp +++ b/src/ast/nodes.hpp @@ -89,17 +89,23 @@ NODE(VariableDecl, value(std::move(value)) {} ); +NODE(ArrowBody, + std::unique_ptr returnValue; + + ArrowBody(std::unique_ptr returnValue) : returnValue(std::move(returnValue)) {} +); + NODE(FunctionDecl, std::string name; std::vector parameters; TypeExpression returnType; - Scope functionBody; + std::variant functionBody; FunctionDecl( std::string name, std::vector parameters, TypeExpression returnType, - Scope functionBody + std::variant functionBody ) : name(std::move(name)), parameters(std::move(parameters)), @@ -111,14 +117,14 @@ NODE(MethodDecl, std::string name; std::vector parameters; TypeExpression returnType; - Scope functionBody; + std::variant functionBody; bool isMutating; MethodDecl( std::string name, std::vector parameters, TypeExpression returnType, - Scope functionBody, + std::variant functionBody, bool isMutating ) : name(std::move(name)), diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 6fbc85ea..db1c7454 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -87,6 +87,7 @@ int yylex( "$" { tok = yy::Parser::token::DOLLAR; goto done; } "@" { tok = yy::Parser::token::AT; goto done; } "->" { tok = yy::Parser::token::THIN_ARROW; goto done; } + "=>" { tok = yy::Parser::token::THICK_ARROW; goto done; } float_lit { yylval->emplace(toStr(start, cursor)); diff --git a/src/grammar/parser.y b/src/grammar/parser.y index d094bbc6..0d8903a7 100644 --- a/src/grammar/parser.y +++ b/src/grammar/parser.y @@ -35,7 +35,7 @@ // --- tokens --- %token LPAREN RPAREN LCURLY RCURLY %token COMMA COLON EQUAL -%token DOLLAR THIN_ARROW AT +%token DOLLAR THIN_ARROW THICK_ARROW AT %token MUT THIS %token STRING IDENT INT FLOAT %token ERROR @@ -59,7 +59,9 @@ %type name_type %type function_type %type method_type +%type arrow_body %type scope +%type > function_body %type >> statements %type statement %type operator_call @@ -108,8 +110,26 @@ variable_decl } ; +arrow_body + : THICK_ARROW value_expr[val] + { + $$ = ast::nodes::ArrowBody(std::make_unique(std::move($val))); + } + ; + +function_body + : arrow_body[arrow] + { + $$ = std::move($arrow); + } + | scope[scope] + { + $$ = std::move($scope); + } + ; + function_decl - : type_expr[return_type] IDENT[name] LPAREN parameters[params] RPAREN scope[body] + : type_expr[return_type] IDENT[name] LPAREN parameters[params] RPAREN function_body[body] { $$ = ast::nodes::FunctionDecl( std::move($name), @@ -121,7 +141,7 @@ function_decl ; method_decl - : type_expr[return_type] IDENT[name] LPAREN method_parameters[params] RPAREN scope[body] + : type_expr[return_type] IDENT[name] LPAREN method_parameters[params] RPAREN function_body[body] { $$ = ast::nodes::MethodDecl( std::move($name), @@ -132,7 +152,7 @@ method_decl ); } - | type_expr[return_type] IDENT[name] LPAREN method_parameters[params] RPAREN MUT scope[body] + | type_expr[return_type] IDENT[name] LPAREN method_parameters[params] RPAREN MUT function_body[body] { $$ = ast::nodes::MethodDecl( std::move($name), @@ -150,12 +170,12 @@ method_parameters | THIS type_expr[type] { $$ = std::vector(); - $$.push_back(std::move( + $$.push_back( ast::nodes::Parameter( std::make_unique(std::move($type)), "this" ) - )); + ); } | method_parameters[params] COMMA parameter[p] { From 9655c12bfcfa7b38a7f43ad1deb55ca614f8c673 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 28 May 2026 15:02:49 +0200 Subject: [PATCH 050/154] update --- src/ast/evaluators/to-graph.hpp | 4 +++- test-parser/main.zn | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ast/evaluators/to-graph.hpp b/src/ast/evaluators/to-graph.hpp index 2885efc7..128c84a2 100644 --- a/src/ast/evaluators/to-graph.hpp +++ b/src/ast/evaluators/to-graph.hpp @@ -103,7 +103,9 @@ struct ToGraph { } treegraph::Node operator()(const nodes::TypeExpression& expression) const { - return std::visit(*this, expression.data); + treegraph::Table table; + table.insert("ArrowBody", treegraph::ptr(std::visit(*this, expression.data))); + return treegraph::Node(std::move(table)); } treegraph::Node operator()(const nodes::Parameter& parameter) const { diff --git a/test-parser/main.zn b/test-parser/main.zn index 470a0f85..d8c917e8 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -5,3 +5,5 @@ Void main(this Int, a Bool) { test Int = 3 func (this Int) -> Void = 3.0 } + +Int getNum() => 3 From d2a3de647905026d37b5f62e8c70fb46bf8af7fa Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 28 May 2026 23:19:51 +0200 Subject: [PATCH 051/154] use elkhound --- devbox.json | 2 +- devbox.lock | 166 +++--- meson.build | 17 +- src/grammar/lexer.hpp | 68 +++ src/grammar/lexer.re | 247 ++++++-- src/grammar/parser.gr | 539 ++++++++++++++++++ src/grammar/parser.y | 447 --------------- src/main.cpp | 33 +- test-parser/main.zn | 4 +- vcpkg-configuration.json | 3 + vcpkg-ports/elkhound-runtime/CMakeLists.txt | 88 +++ .../elkhound_runtimeConfig.cmake.in | 3 + vcpkg-ports/elkhound-runtime/portfile.cmake | 20 + vcpkg-ports/elkhound-runtime/vcpkg.json | 7 + vcpkg.json | 3 +- 15 files changed, 1051 insertions(+), 596 deletions(-) create mode 100644 src/grammar/lexer.hpp create mode 100644 src/grammar/parser.gr delete mode 100644 src/grammar/parser.y create mode 100644 vcpkg-ports/elkhound-runtime/CMakeLists.txt create mode 100644 vcpkg-ports/elkhound-runtime/elkhound_runtimeConfig.cmake.in create mode 100644 vcpkg-ports/elkhound-runtime/portfile.cmake create mode 100644 vcpkg-ports/elkhound-runtime/vcpkg.json diff --git a/devbox.json b/devbox.json index c3ac0c96..8b6f145b 100644 --- a/devbox.json +++ b/devbox.json @@ -10,7 +10,7 @@ "ninja@latest", "zig@latest", "clang-tools@latest", - "bison@latest", + "elkhound@latest", "re2c@latest" ], "shell": { diff --git a/devbox.lock b/devbox.lock index 09fc86ec..1e31972e 100644 --- a/devbox.lock +++ b/devbox.lock @@ -1,54 +1,6 @@ { "lockfile_version": "1", "packages": { - "bison@latest": { - "last_modified": "2026-04-23T13:07:47Z", - "resolved": "github:NixOS/nixpkgs/01fbdeef22b76df85ea168fbfe1bfd9e63681b30#bison", - "source": "devbox-search", - "version": "3.8.2", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/h3i7bj2a901ms72d6v92m5jdkk5mbv0w-bison-3.8.2", - "default": true - } - ], - "store_path": "/nix/store/h3i7bj2a901ms72d6v92m5jdkk5mbv0w-bison-3.8.2" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/09i6bzy75cg042106zyf7w0f89ifm4g3-bison-3.8.2", - "default": true - } - ], - "store_path": "/nix/store/09i6bzy75cg042106zyf7w0f89ifm4g3-bison-3.8.2" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/lvlg6r94p22mb9k0ws92p4fz4cjm3vx2-bison-3.8.2", - "default": true - } - ], - "store_path": "/nix/store/lvlg6r94p22mb9k0ws92p4fz4cjm3vx2-bison-3.8.2" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/avysx19spq1m2kzs01nhhqh310zazk40-bison-3.8.2", - "default": true - } - ], - "store_path": "/nix/store/avysx19spq1m2kzs01nhhqh310zazk40-bison-3.8.2" - } - } - }, "clang-tools@latest": { "last_modified": "2026-04-23T13:07:47Z", "resolved": "github:NixOS/nixpkgs/01fbdeef22b76df85ea168fbfe1bfd9e63681b30#clang-tools", @@ -201,97 +153,145 @@ } } }, + "elkhound@latest": { + "last_modified": "2026-04-23T13:07:47Z", + "resolved": "github:NixOS/nixpkgs/01fbdeef22b76df85ea168fbfe1bfd9e63681b30#elkhound", + "source": "devbox-search", + "version": "0-unstable-2020-04-13", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/1i4ny8flqb1pgd1ly7f3c13a6mh9i6bx-elkhound-0-unstable-2020-04-13", + "default": true + } + ], + "store_path": "/nix/store/1i4ny8flqb1pgd1ly7f3c13a6mh9i6bx-elkhound-0-unstable-2020-04-13" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/jzl4xkd3l33ryiqrsbzcjmlwwr8v3w5g-elkhound-0-unstable-2020-04-13", + "default": true + } + ], + "store_path": "/nix/store/jzl4xkd3l33ryiqrsbzcjmlwwr8v3w5g-elkhound-0-unstable-2020-04-13" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/9n87n5khz2kzr3gkj2z6ynwgak0zskw5-elkhound-0-unstable-2020-04-13", + "default": true + } + ], + "store_path": "/nix/store/9n87n5khz2kzr3gkj2z6ynwgak0zskw5-elkhound-0-unstable-2020-04-13" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/macnab366i1q2zps273r05dh1pbs34y2-elkhound-0-unstable-2020-04-13", + "default": true + } + ], + "store_path": "/nix/store/macnab366i1q2zps273r05dh1pbs34y2-elkhound-0-unstable-2020-04-13" + } + } + }, "github:NixOS/nixpkgs/nixpkgs-unstable": { - "last_modified": "2026-04-30T11:26:30Z", - "resolved": "github:NixOS/nixpkgs/7aaa00e7cc9be6c316cb5f6617bd740dd435c59d?lastModified=1777548390&narHash=sha256-WacE23EbHTsBKvr8cu%2B1DFNbP6Rh1brHUH5SDUI0NQI%3D" + "last_modified": "2026-05-27T10:28:13Z", + "resolved": "github:NixOS/nixpkgs/4100e830e085863741bc69b156ec4ccd53ab5be0?lastModified=1779877693&narHash=sha256-NOF9NAREhxr50bbBfVcVOq%2BArCMSoe8dP79Pk2uyARk%3D" }, "just@latest": { - "last_modified": "2026-04-23T13:07:47Z", - "resolved": "github:NixOS/nixpkgs/01fbdeef22b76df85ea168fbfe1bfd9e63681b30#just", + "last_modified": "2026-05-12T01:56:55Z", + "resolved": "github:NixOS/nixpkgs/0a0bf409f3593f415d0a554f33acc63dc7dccb43#just", "source": "devbox-search", - "version": "1.50.0", + "version": "1.51.0", "systems": { "aarch64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/qxqsxk2614qpcb7l32svpjmmb1sm7ya1-just-1.50.0", + "path": "/nix/store/c9vv24f9bdnhnms10nwijn6q8wjz00ak-just-1.51.0", "default": true }, { "name": "man", - "path": "/nix/store/daf30m3si50cl7xga42g0cqgdwaxj6ys-just-1.50.0-man", + "path": "/nix/store/lxfs1naxd1a3934y9xsd1kid5yyw7jbn-just-1.51.0-man", "default": true }, { "name": "doc", - "path": "/nix/store/9n71gassrpdy0nz4gfcrwvmkb4rwyd3g-just-1.50.0-doc" + "path": "/nix/store/c8jdzd2s7hbldm1q1glrjisavxy1vf54-just-1.51.0-doc" } ], - "store_path": "/nix/store/qxqsxk2614qpcb7l32svpjmmb1sm7ya1-just-1.50.0" + "store_path": "/nix/store/c9vv24f9bdnhnms10nwijn6q8wjz00ak-just-1.51.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/ayqw7hgkjs9b0f7v1qh96k316i9jpdw8-just-1.50.0", + "path": "/nix/store/ljwadwqsib4zd6nvg6xi5rnzah9ad2q4-just-1.51.0", "default": true }, { "name": "man", - "path": "/nix/store/59z0bx178i7c3vwmhawgajgpfmv43h5c-just-1.50.0-man", + "path": "/nix/store/5m9rgkzibz19za2nmn83y9l5gsy2z1yh-just-1.51.0-man", "default": true }, { "name": "doc", - "path": "/nix/store/gg298zgvg5vmvzk0lmn9zq7j6kkab3qs-just-1.50.0-doc" + "path": "/nix/store/q80cv2gjn2q640fvsqgdj6ap2iihxwg9-just-1.51.0-doc" } ], - "store_path": "/nix/store/ayqw7hgkjs9b0f7v1qh96k316i9jpdw8-just-1.50.0" + "store_path": "/nix/store/ljwadwqsib4zd6nvg6xi5rnzah9ad2q4-just-1.51.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/bmsgb4l7ldxj2zggcalfidzhkrgp03xq-just-1.50.0", + "path": "/nix/store/w0capgph40qykn19a9ghv38fjf06gg97-just-1.51.0", "default": true }, { "name": "man", - "path": "/nix/store/0pvkn1lzh85sav0cj3v36kpigxwypdhb-just-1.50.0-man", + "path": "/nix/store/97jyxj8d9d4qjq25681ng88jnbdak1dx-just-1.51.0-man", "default": true }, { "name": "doc", - "path": "/nix/store/9d2i12jkmsyqw7bkcw3a9d0xki313xrp-just-1.50.0-doc" + "path": "/nix/store/p8pb01d5w82lf8z0ah4kcc6ziwfvxfkr-just-1.51.0-doc" } ], - "store_path": "/nix/store/bmsgb4l7ldxj2zggcalfidzhkrgp03xq-just-1.50.0" + "store_path": "/nix/store/w0capgph40qykn19a9ghv38fjf06gg97-just-1.51.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/vr4agmy8jw7f8kqynpizagdaqxy0ayw4-just-1.50.0", + "path": "/nix/store/zn7n9xnw5vx6cqf1az8b8p1pfsmrl9vw-just-1.51.0", "default": true }, { "name": "man", - "path": "/nix/store/6mrjsdff8skgnnn0ngyim2i7wabk0c8x-just-1.50.0-man", + "path": "/nix/store/mgc1wdhgkc9246s9a52j17ymw4745bal-just-1.51.0-man", "default": true }, { "name": "doc", - "path": "/nix/store/nk0p7b0n1fqg0sa2vasgavrhgi7xy9rz-just-1.50.0-doc" + "path": "/nix/store/mkdym7bscwpn6y6dvzrblm5p87q9c2g0-just-1.51.0-doc" } ], - "store_path": "/nix/store/vr4agmy8jw7f8kqynpizagdaqxy0ayw4-just-1.50.0" + "store_path": "/nix/store/zn7n9xnw5vx6cqf1az8b8p1pfsmrl9vw-just-1.51.0" } } }, "llvm_21@latest": { - "last_modified": "2026-04-29T01:19:07Z", - "resolved": "github:NixOS/nixpkgs/ebc08544afa77957cc348ba72dc490ec73b87f68#llvm_21", + "last_modified": "2026-05-20T06:38:13Z", + "resolved": "github:NixOS/nixpkgs/d99b013d5d1931ad77fe3912ed218170dec5d9a4#llvm_21", "source": "devbox-search", "version": "21.1.8", "systems": { @@ -302,10 +302,6 @@ "path": "/nix/store/fib2wxwpvlc1q2qrxbhz2i961l2srcjw-llvm-21.1.8", "default": true }, - { - "name": "python", - "path": "/nix/store/6avba57frkpxqlw7d5mljr5a6ymvlygy-llvm-21.1.8-python" - }, { "name": "dev", "path": "/nix/store/x0msv7ql9xm50fvz3x5p2gb01grnyqln-llvm-21.1.8-dev" @@ -313,6 +309,10 @@ { "name": "lib", "path": "/nix/store/4fk7xkk9faias8kqzh1kagdhb87l5kcw-llvm-21.1.8-lib" + }, + { + "name": "python", + "path": "/nix/store/6avba57frkpxqlw7d5mljr5a6ymvlygy-llvm-21.1.8-python" } ], "store_path": "/nix/store/fib2wxwpvlc1q2qrxbhz2i961l2srcjw-llvm-21.1.8" @@ -324,6 +324,10 @@ "path": "/nix/store/dr58nil7xb6v4di6mmlvki3s1d8iwdym-llvm-21.1.8", "default": true }, + { + "name": "dev", + "path": "/nix/store/0hf3wfrd60fhgh7y1x7857pf7a1hypnm-llvm-21.1.8-dev" + }, { "name": "lib", "path": "/nix/store/lr9kz2ky0ys12cx0xz91rnkmbadaqvj0-llvm-21.1.8-lib" @@ -331,13 +335,17 @@ { "name": "python", "path": "/nix/store/45y119pkm1p76bqn7lhp2i0nx0yk2x44-llvm-21.1.8-python" - }, - { - "name": "dev", - "path": "/nix/store/0hf3wfrd60fhgh7y1x7857pf7a1hypnm-llvm-21.1.8-dev" } ], "store_path": "/nix/store/dr58nil7xb6v4di6mmlvki3s1d8iwdym-llvm-21.1.8" + }, + "x86_64-linux": { + "outputs": [ + { + "path": "/nix/store/jp45dqzv8mjpqsvhj99c93pc4vlmhy16-llvm-21.1.8", + "default": true + } + ] } } }, diff --git a/meson.build b/meson.build index 40493fce..f06280b6 100644 --- a/meson.build +++ b/meson.build @@ -3,12 +3,19 @@ project('zane', 'cpp', default_options: ['cpp_std=c++20', 'warning_level=3']) re2c = find_program('re2c', required: true) -bison = find_program('bison', required: true) +elkhound = find_program('elkhound', required: true) + +elkhound_runtime = dependency('elkhound_runtime', + method: 'cmake', + cmake_args: [ + '-DCMAKE_PREFIX_PATH=' + meson.project_source_root() / 'vcpkg_installed/x64-linux/share/elkhound-runtime', + ], + required: true) parser_gen = custom_target('parser', - input: 'src/grammar/parser.y', - output: ['parser.cc', 'parser.tab.h'], - command: [bison, '-d', '-o', '@OUTPUT0@', '--defines=@OUTPUT1@', '@INPUT@'], + input: 'src/grammar/parser.gr', + output: ['zane_parser.cc', 'zane_parser.h'], + command: [elkhound, '-o', '@OUTDIR@/zane_parser', '@INPUT@'], build_by_default: true, ) @@ -17,7 +24,6 @@ lexer_gen = custom_target('lexer', output: 'lexer.cc', command: [re2c, '-o', '@OUTPUT@', '@INPUT@'], build_by_default: true, - depends: [parser_gen], ) executable('zane', @@ -25,4 +31,5 @@ executable('zane', parser_gen[0], # parser.cc lexer_gen, # lexer.cc include_directories: include_directories('src'), + dependencies: [elkhound_runtime], ) diff --git a/src/grammar/lexer.hpp b/src/grammar/lexer.hpp new file mode 100644 index 00000000..4012ace5 --- /dev/null +++ b/src/grammar/lexer.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include "lexerint.h" +#include "str.h" +#include + +enum TokenCode { + TOK_EOF = 0, + TOK_LPAREN, + TOK_RPAREN, + TOK_LCURLY, + TOK_RCURLY, + TOK_COMMA, + TOK_COLON, + TOK_EQUAL, + TOK_DOLLAR, + TOK_THIN_ARROW, + TOK_THICK_ARROW, + TOK_AT, + TOK_MUT, + TOK_THIS, + TOK_STRING, + TOK_IDENT, + TOK_INT, + TOK_FLOAT, + TOK_PLUS, + TOK_MINUS, + TOK_STAR, + TOK_SLASH, + TOK_TILDE, + TOK_ERROR, +}; + +class Lexer : public LexerInterface { +public: + Lexer(const std::string& sourcePath, const std::string& source); + + static void nextToken(LexerInterface* lex); + virtual NextTokenFunc getTokenFunc() const override; + virtual string tokenDesc() const override; + virtual string tokenKindDesc(int kind) const override; + + void reportParseError() const; + + const std::string& sourcePath() const { return sourcePath_; } + int tokenLine() const { return tokenLine_; } + int tokenColumn() const { return tokenColumn_; } + int tokenEndColumn() const { return tokenEndColumn_; } + +private: + std::string sourcePath_; + const std::string& source_; + const char* cursor_; + const char* marker_; + const char* limit_; + const char* lineStart_; + int line_; + int tokenLine_; + int tokenColumn_; + int tokenEndColumn_; + std::string currentLexeme_; + + int columnFor(const char* ptr) const; + void updateLocation(const char* begin, const char* end); + void setCurrentToken(int token, SemanticValue value, const char* begin, const char* end, int startLine, int startColumn); + std::string describeToken(int token, SemanticValue value, const char* begin, const char* end) const; + static const char* tokenName(int token); +}; diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index db1c7454..4c853fcf 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -1,5 +1,6 @@ -#include "ast/.hpp" -#include "parser.tab.h" +#include "grammar/lexer.hpp" +#include "useract.h" +#include #include static std::string toStr(const char* b, const char* e) { @@ -27,27 +28,174 @@ static std::string unescape(const char* b, const char* e) { return out; } -static void updateLocation(const char* begin, const char* end, int& line, const char*& line_start) { +static std::string findLine(const std::string& source, int lineNumber) { + int currentLine = 1; + size_t lineStart = 0; + + while (lineStart <= source.size()) { + size_t lineEnd = source.find('\n', lineStart); + if (lineEnd == std::string::npos) + lineEnd = source.size(); + + if (currentLine == lineNumber) + return source.substr(lineStart, lineEnd - lineStart); + + if (lineEnd == source.size()) + break; + + lineStart = lineEnd + 1; + ++currentLine; + } + + return std::string(); +} + +Lexer::Lexer(const std::string& sourcePath, const std::string& source) + : sourcePath_(sourcePath), + source_(source), + cursor_(source.c_str()), + marker_(source.c_str()), + limit_(source.c_str() + source.size()), + lineStart_(source.c_str()), + line_(1), + tokenLine_(1), + tokenColumn_(1), + tokenEndColumn_(1) { + type = TOK_EOF; + sval = NULL_SVAL; + loc = SL_UNKNOWN; +} + +LexerInterface::NextTokenFunc Lexer::getTokenFunc() const { + return &Lexer::nextToken; +} + +int Lexer::columnFor(const char* ptr) const { + return static_cast(ptr - lineStart_) + 1; +} + +void Lexer::updateLocation(const char* begin, const char* end) { for (const char* cursor = begin; cursor < end; ++cursor) { if (*cursor == '\n') { - ++line; - line_start = cursor + 1; + ++line_; + lineStart_ = cursor + 1; } } } -int yylex( - yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, - const char*& cursor, const char*& marker, const char* limit, const std::string& sourcePath, - const std::string& source, ast::nodes::Package*& ast, int& line, const char*& line_start) { +void Lexer::setCurrentToken(int token, SemanticValue value, const char* begin, const char* end, int startLine, int startColumn) { + updateLocation(begin, end); + type = token; + sval = value; + loc = SL_UNKNOWN; + tokenLine_ = startLine; + tokenColumn_ = startColumn; + tokenEndColumn_ = columnFor(end); + currentLexeme_ = describeToken(token, value, begin, end); +} + +std::string Lexer::describeToken(int token, SemanticValue value, const char* begin, const char* end) const { + if (token == TOK_STRING || token == TOK_IDENT || token == TOK_INT || token == TOK_FLOAT) { + const auto* text = reinterpret_cast(value); + return text != nullptr ? *text : std::string(); + } + + if (token == TOK_EOF) + return std::string(); + + return toStr(begin, end); +} + +const char* Lexer::tokenName(int token) { + switch (token) { + case TOK_EOF: return "end of file"; + case TOK_LPAREN: return "("; + case TOK_RPAREN: return ")"; + case TOK_LCURLY: return "{"; + case TOK_RCURLY: return "}"; + case TOK_COMMA: return ","; + case TOK_COLON: return ":"; + case TOK_EQUAL: return "="; + case TOK_DOLLAR: return "$"; + case TOK_THIN_ARROW: return "->"; + case TOK_THICK_ARROW: return "=>"; + case TOK_AT: return "@"; + case TOK_MUT: return "mut"; + case TOK_THIS: return "this"; + case TOK_STRING: return "string"; + case TOK_IDENT: return "identifier"; + case TOK_INT: return "int"; + case TOK_FLOAT: return "float"; + case TOK_PLUS: return "+"; + case TOK_MINUS: return "-"; + case TOK_STAR: return "*"; + case TOK_SLASH: return "/"; + case TOK_TILDE: return "~"; + case TOK_ERROR: return "invalid token"; + default: return "unknown token"; + } +} + +string Lexer::tokenDesc() const { + if (type == TOK_EOF) + return string("end of file"); + + if (type == TOK_STRING || type == TOK_IDENT || type == TOK_INT || type == TOK_FLOAT) + return string(currentLexeme_.c_str()); + + return string(tokenName(type)); +} + +string Lexer::tokenKindDesc(int kind) const { + return string(tokenName(kind)); +} + +void Lexer::reportParseError() const { + std::cerr << sourcePath_ << ":" << tokenLine_ << ":" << tokenColumn_ << ": error: unexpected " + << (type == TOK_EOF ? "end of file" : currentLexeme_) << "\n"; + + const std::string line = findLine(source_, tokenLine_); + if (line.empty()) + return; + + const std::string lineNumber = std::to_string(tokenLine_); + std::cerr << lineNumber << " | " << line << "\n"; + + std::string caretLine; + caretLine.reserve(lineNumber.size() + 3 + line.size()); + caretLine.append(lineNumber.size(), ' '); + caretLine += " | "; + for (int column = 1; column < tokenColumn_; ++column) + caretLine += static_cast(column - 1) < line.size() && line[static_cast(column - 1)] == '\t' ? '\t' : ' '; + + const int highlightWidth = std::max(1, tokenEndColumn_ - tokenColumn_); + caretLine.append(static_cast(highlightWidth), '^'); + std::cerr << caretLine << "\n"; +} + +void Lexer::nextToken(LexerInterface* base) { + auto* lexer = static_cast(base); for (;;) { - if (cursor >= limit) return 0; - const char* start = cursor; + if (lexer->cursor_ >= lexer->limit_) { + lexer->type = TOK_EOF; + lexer->sval = NULL_SVAL; + lexer->loc = SL_UNKNOWN; + lexer->tokenLine_ = lexer->line_; + lexer->tokenColumn_ = lexer->columnFor(lexer->cursor_); + lexer->tokenEndColumn_ = lexer->tokenColumn_; + lexer->currentLexeme_.clear(); + return; + } - yylloc->begin.line = line; - yylloc->begin.column = (int)(start - line_start) + 1; + const char* start = lexer->cursor_; + const int startLine = lexer->line_; + const int startColumn = lexer->columnFor(start); + int tok = TOK_ERROR; + SemanticValue sval = NULL_SVAL; - int tok = -1; + #define cursor lexer->cursor_ + #define marker lexer->marker_ + #define limit lexer->limit_ /*!re2c re2c:flags:utf-8 = 1; @@ -67,52 +215,57 @@ int yylex( float_lit = sw_digits "." digits | digits "." digits; [ \t\r\n]+ { - updateLocation(start, cursor, line, line_start); + lexer->updateLocation(start, cursor); continue; } - "=" { tok = yy::Parser::token::EQUAL; goto done; } - "(" { tok = yy::Parser::token::LPAREN; goto done; } - ")" { tok = yy::Parser::token::RPAREN; goto done; } - "{" { tok = yy::Parser::token::LCURLY; goto done; } - "}" { tok = yy::Parser::token::RCURLY; goto done; } - "," { tok = yy::Parser::token::COMMA; goto done; } - ":" { tok = yy::Parser::token::COLON; goto done; } - "~" { tok = yy::Parser::token::TILDE; goto done; } - - "+" { yylval->emplace("+"); tok = yy::Parser::token::PLUS; goto done; } - "-" { yylval->emplace("-"); tok = yy::Parser::token::MINUS; goto done; } - "*" { yylval->emplace("*"); tok = yy::Parser::token::STAR; goto done; } - "/" { yylval->emplace("/"); tok = yy::Parser::token::SLASH; goto done; } - - "$" { tok = yy::Parser::token::DOLLAR; goto done; } - "@" { tok = yy::Parser::token::AT; goto done; } - "->" { tok = yy::Parser::token::THIN_ARROW; goto done; } - "=>" { tok = yy::Parser::token::THICK_ARROW; goto done; } + "=" { tok = TOK_EQUAL; goto done; } + "(" { tok = TOK_LPAREN; goto done; } + ")" { tok = TOK_RPAREN; goto done; } + "{" { tok = TOK_LCURLY; goto done; } + "}" { tok = TOK_RCURLY; goto done; } + "," { tok = TOK_COMMA; goto done; } + ":" { tok = TOK_COLON; goto done; } + "~" { tok = TOK_TILDE; goto done; } + "+" { tok = TOK_PLUS; goto done; } + "-" { tok = TOK_MINUS; goto done; } + "*" { tok = TOK_STAR; goto done; } + "/" { tok = TOK_SLASH; goto done; } + + "$" { tok = TOK_DOLLAR; goto done; } + "@" { tok = TOK_AT; goto done; } + "->" { tok = TOK_THIN_ARROW; goto done; } + "=>" { tok = TOK_THICK_ARROW; goto done; } float_lit { - yylval->emplace(toStr(start, cursor)); - tok = yy::Parser::token::FLOAT; goto done; + sval = reinterpret_cast(new std::string(toStr(start, cursor))); + tok = TOK_FLOAT; goto done; } int_lit { - yylval->emplace(toStr(start, cursor)); - tok = yy::Parser::token::INT; goto done; + sval = reinterpret_cast(new std::string(toStr(start, cursor))); + tok = TOK_INT; goto done; } ["] str_char* ["] { - yylval->emplace(unescape(start + 1, cursor - 1)); - tok = yy::Parser::token::STRING; goto done; + sval = reinterpret_cast(new std::string(unescape(start + 1, cursor - 1))); + tok = TOK_STRING; goto done; } - "mut" { tok = yy::Parser::token::MUT; goto done; } - "this" { tok = yy::Parser::token::THIS; goto done; } + "mut" { tok = TOK_MUT; goto done; } + "this" { tok = TOK_THIS; goto done; } ident+ { - yylval->emplace(toStr(start, cursor)); - tok = yy::Parser::token::IDENT; goto done; + sval = reinterpret_cast(new std::string(toStr(start, cursor))); + tok = TOK_IDENT; goto done; + } + * { + tok = TOK_ERROR; + goto done; } - * { tok = yy::Parser::token::ERROR; goto done; } */ done: - yylloc->end.line = line; - yylloc->end.column = (int)(cursor - line_start) + 1; - return tok; + #undef cursor + #undef marker + #undef limit + + lexer->setCurrentToken(tok, sval, start, lexer->cursor_, startLine, startColumn); + return; } } diff --git a/src/grammar/parser.gr b/src/grammar/parser.gr new file mode 100644 index 00000000..20148fff --- /dev/null +++ b/src/grammar/parser.gr @@ -0,0 +1,539 @@ +verbatim { + #include "ast/.hpp" + #include + #include + #include + #include + #include + + namespace grammar_support { + + struct FunctionBodyValue { + std::variant value; + + explicit FunctionBodyValue(std::variant value) + : value(std::move(value)) {} + }; + + template + T take_value(T* ptr) { + T value = std::move(*ptr); + delete ptr; + return value; + } + + template + std::unique_ptr take_ptr(T* ptr) { + return std::unique_ptr(ptr); + } + + inline std::string take_string(std::string* ptr) { + std::string value = std::move(*ptr); + delete ptr; + return value; + } + + inline ast::nodes::ValueExpr* make_binary( + std::string op, + ast::nodes::ValueExpr* left, + ast::nodes::ValueExpr* right + ) { + return new ast::nodes::ValueExpr( + ast::nodes::OperatorCall( + std::move(op), + take_ptr(left), + take_ptr(right) + ) + ); + } + + inline ast::nodes::ValueExpr* make_flip(ast::nodes::ValueExpr* value) { + return new ast::nodes::ValueExpr(ast::nodes::OperatorFlipCall(take_ptr(value))); + } + + inline ast::nodes::ValueExpr* wrap_call(ast::nodes::FunctionCall* call) { + return new ast::nodes::ValueExpr(take_value(call)); + } + + inline ast::nodes::ValueExpr* wrap_parenthesized(ast::nodes::ParenthizedValue* value) { + return new ast::nodes::ValueExpr(take_value(value)); + } + + } // namespace grammar_support +} + +option defaultMergeAborts; + +context_class ZaneParser : public UserActions { +public: + // generated parser hooks are added by Elkhound +}; + +terminals { + 0 : TOK_EOF; + 1 : TOK_LPAREN "("; + 2 : TOK_RPAREN ")"; + 3 : TOK_LCURLY "{"; + 4 : TOK_RCURLY "}"; + 5 : TOK_COMMA ","; + 6 : TOK_COLON ":"; + 7 : TOK_EQUAL "="; + 8 : TOK_DOLLAR "$"; + 9 : TOK_THIN_ARROW "->"; + 10 : TOK_THICK_ARROW "=>"; + 11 : TOK_AT "@"; + 12 : TOK_MUT "mut"; + 13 : TOK_THIS "this"; + 14 : TOK_STRING; + 15 : TOK_IDENT; + 16 : TOK_INT; + 17 : TOK_FLOAT; + 18 : TOK_PLUS "+"; + 19 : TOK_MINUS "-"; + 20 : TOK_STAR "*"; + 21 : TOK_SLASH "/"; + 22 : TOK_TILDE "~"; + 23 : TOK_ERROR; + + token(std::string*) TOK_STRING { + fun dup(s) [return new std::string(*s);] + fun del(s) [delete s;] + } + token(std::string*) TOK_IDENT { + fun dup(s) [return new std::string(*s);] + fun del(s) [delete s;] + } + token(std::string*) TOK_INT { + fun dup(s) [return new std::string(*s);] + fun del(s) [delete s;] + } + token(std::string*) TOK_FLOAT { + fun dup(s) [return new std::string(*s);] + fun del(s) [delete s;] + } + + precedence { + left 20 "*" "/"; + left 10 "+" "-"; + right 30 "~"; + } +} + +nonterm(ast::nodes::Package*) package { + fun dup(p) [return p;] + fun del(p) [] + -> declarations:global_scope { + return new ast::nodes::Package(grammar_support::take_value(declarations)); + } +} + +nonterm(std::vector*) global_scope { + fun dup(p) [return p;] + fun del(p) [] + -> { + return new std::vector(); + } + -> declarations:global_scope declaration:declaration { + declarations->push_back(grammar_support::take_value(declaration)); + return declarations; + } +} + +nonterm(ast::nodes::Declaration*) declaration { + fun dup(p) [return p;] + fun del(p) [] + -> function:function_decl { + return new ast::nodes::Declaration(grammar_support::take_value(function)); + } + -> method:method_decl { + return new ast::nodes::Declaration(grammar_support::take_value(method)); + } +} + +nonterm(ast::nodes::VariableDecl*) variable_decl { + fun dup(p) [return p;] + fun del(p) [] + -> name:TOK_IDENT type:type_expr "=" value:value_expr { + return new ast::nodes::VariableDecl( + grammar_support::take_string(name), + grammar_support::take_value(type), + grammar_support::take_ptr(value) + ); + } +} + +nonterm(ast::nodes::FunctionDecl*) function_decl { + fun dup(p) [return p;] + fun del(p) [] + -> return_type:type_expr name:TOK_IDENT "(" params:parameters ")" body:function_body { + return new ast::nodes::FunctionDecl( + grammar_support::take_string(name), + grammar_support::take_value(params), + grammar_support::take_value(return_type), + grammar_support::take_value(body).value + ); + } +} + +nonterm(ast::nodes::MethodDecl*) method_decl { + fun dup(p) [return p;] + fun del(p) [] + -> return_type:type_expr name:TOK_IDENT "(" params:method_parameters ")" body:function_body { + return new ast::nodes::MethodDecl( + grammar_support::take_string(name), + grammar_support::take_value(params), + grammar_support::take_value(return_type), + grammar_support::take_value(body).value, + false + ); + } + -> return_type:type_expr name:TOK_IDENT "(" params:method_parameters ")" "mut" body:function_body { + return new ast::nodes::MethodDecl( + grammar_support::take_string(name), + grammar_support::take_value(params), + grammar_support::take_value(return_type), + grammar_support::take_value(body).value, + true + ); + } +} + +nonterm(std::vector*) parameters { + fun dup(p) [return p;] + fun del(p) [] + -> { + return new std::vector(); + } + -> list:parameter_list { + return list; + } +} + +nonterm(std::vector*) parameter_list { + fun dup(p) [return p;] + fun del(p) [] + -> parameter:parameter { + auto* list = new std::vector(); + list->push_back(grammar_support::take_value(parameter)); + return list; + } + -> list:parameter_list "," parameter:parameter { + list->push_back(grammar_support::take_value(parameter)); + return list; + } +} + +nonterm(std::vector*) method_parameters { + fun dup(p) [return p;] + fun del(p) [] + -> list:method_parameter_seq { + return list; + } +} + +nonterm(std::vector*) method_parameter_seq { + fun dup(p) [return p;] + fun del(p) [] + -> "this" type:type_expr { + auto* list = new std::vector(); + list->push_back(ast::nodes::Parameter(grammar_support::take_ptr(type), "this")); + return list; + } + -> list:method_parameter_seq "," parameter:parameter { + list->push_back(grammar_support::take_value(parameter)); + return list; + } +} + +nonterm(ast::nodes::Parameter*) parameter { + fun dup(p) [return p;] + fun del(p) [] + -> name:TOK_IDENT type:type_expr { + return new ast::nodes::Parameter( + grammar_support::take_ptr(type), + grammar_support::take_string(name) + ); + } +} + +nonterm(std::vector>*) type_list { + fun dup(p) [return p;] + fun del(p) [] + -> { + return new std::vector>(); + } + -> list:type_list_ne { + return list; + } +} + +nonterm(std::vector>*) type_list_ne { + fun dup(p) [return p;] + fun del(p) [] + -> expr:type_expr { + auto* list = new std::vector>(); + list->push_back(grammar_support::take_ptr(expr)); + return list; + } + -> list:type_list_ne "," expr:type_expr { + list->push_back(grammar_support::take_ptr(expr)); + return list; + } +} + +nonterm(ast::nodes::TypeExpression*) type_expr { + fun dup(p) [return p;] + fun del(p) [] + -> name:name_type { + return new ast::nodes::TypeExpression(grammar_support::take_value(name)); + } + -> function:function_type { + return new ast::nodes::TypeExpression(grammar_support::take_value(function)); + } + -> method:method_type { + return new ast::nodes::TypeExpression(grammar_support::take_value(method)); + } +} + +nonterm(ast::nodes::NameType*) name_type { + fun dup(p) [return p;] + fun del(p) [] + -> identifier:TOK_IDENT { + return new ast::nodes::NameType( + grammar_support::take_string(identifier), + std::vector>() + ); + } +} + +nonterm(ast::nodes::FunctionType*) function_type { + fun dup(p) [return p;] + fun del(p) [] + -> "(" params:type_list ")" "->" return_type:type_expr { + return new ast::nodes::FunctionType( + grammar_support::take_value(params), + grammar_support::take_ptr(return_type) + ); + } +} + +nonterm(ast::nodes::MethodType*) method_type { + fun dup(p) [return p;] + fun del(p) [] + -> "(" "this" params:type_list_ne ")" "->" return_type:type_expr { + return new ast::nodes::MethodType( + grammar_support::take_value(params), + grammar_support::take_ptr(return_type), + false + ); + } + -> "(" "this" params:type_list_ne ")" "mut" "->" return_type:type_expr { + return new ast::nodes::MethodType( + grammar_support::take_value(params), + grammar_support::take_ptr(return_type), + true + ); + } +} + +nonterm(ast::nodes::ArrowBody*) arrow_body { + fun dup(p) [return p;] + fun del(p) [] + -> "=>" value:value_expr { + return new ast::nodes::ArrowBody(grammar_support::take_ptr(value)); + } +} + +nonterm(grammar_support::FunctionBodyValue*) function_body { + fun dup(p) [return p;] + fun del(p) [] + -> body:arrow_body { + return new grammar_support::FunctionBodyValue(grammar_support::take_value(body)); + } + -> body:scope { + return new grammar_support::FunctionBodyValue(grammar_support::take_value(body)); + } +} + +nonterm(ast::nodes::Scope*) scope { + fun dup(p) [return p;] + fun del(p) [] + -> "{" statements:statements "}" { + return new ast::nodes::Scope(grammar_support::take_value(statements)); + } +} + +nonterm(std::vector>*) statements { + fun dup(p) [return p;] + fun del(p) [] + -> { + return new std::vector>(); + } + -> list:statements statement:statement { + list->push_back(grammar_support::take_ptr(statement)); + return list; + } +} + +nonterm(ast::nodes::Statement*) statement { + fun dup(p) [return p;] + fun del(p) [] + -> call:statement_function_call { + return new ast::nodes::Statement(grammar_support::take_value(call)); + } + -> declaration:variable_decl { + return new ast::nodes::Statement(grammar_support::take_value(declaration)); + } +} + +nonterm(ast::nodes::FunctionCall*) statement_function_call { + fun dup(p) [return p;] + fun del(p) [] + -> call:call_expr { + return call; + } +} + +nonterm(ast::nodes::ValueExpr*) value_expr { + fun dup(p) [return p;] + fun del(p) [] + -> expr:additive_expr { + return expr; + } +} + +nonterm(ast::nodes::ValueExpr*) additive_expr { + fun dup(p) [return p;] + fun del(p) [] + -> expr:multiplicative_expr { + return expr; + } + -> left:additive_expr "+" right:multiplicative_expr { + return grammar_support::make_binary("+", left, right); + } + -> left:additive_expr "-" right:multiplicative_expr { + return grammar_support::make_binary("-", left, right); + } +} + +nonterm(ast::nodes::ValueExpr*) multiplicative_expr { + fun dup(p) [return p;] + fun del(p) [] + -> expr:unary_expr { + return expr; + } + -> left:multiplicative_expr "*" right:unary_expr { + return grammar_support::make_binary("*", left, right); + } + -> left:multiplicative_expr "/" right:unary_expr { + return grammar_support::make_binary("/", left, right); + } +} + +nonterm(ast::nodes::ValueExpr*) unary_expr { + fun dup(p) [return p;] + fun del(p) [] + -> expr:postfix_expr { + return expr; + } + -> "~" expr:unary_expr precedence("~") { + return grammar_support::make_flip(expr); + } +} + +nonterm(ast::nodes::ValueExpr*) postfix_expr { + fun dup(p) [return p;] + fun del(p) [] + -> expr:primary_expr { + return expr; + } + -> call:call_expr { + return grammar_support::wrap_call(call); + } +} + +nonterm(ast::nodes::FunctionCall*) call_expr { + fun dup(p) [return p;] + fun del(p) [] + -> callee:primary_expr "(" args:arguments ")" { + return new ast::nodes::FunctionCall( + grammar_support::take_ptr(callee), + grammar_support::take_value(args) + ); + } + -> callee:call_expr "(" args:arguments ")" { + return new ast::nodes::FunctionCall( + std::make_unique(grammar_support::take_value(callee)), + grammar_support::take_value(args) + ); + } +} + +nonterm(ast::nodes::ValueExpr*) primary_expr { + fun dup(p) [return p;] + fun del(p) [] + -> identifier:TOK_IDENT { + return new ast::nodes::ValueExpr(ast::nodes::ValueSymbol(grammar_support::take_string(identifier))); + } + -> package:TOK_IDENT "$" identifier:TOK_IDENT { + return new ast::nodes::ValueExpr( + ast::nodes::PackageValueSymbol( + grammar_support::take_string(identifier), + grammar_support::take_string(package) + ) + ); + } + -> "@" package:TOK_IDENT "$" identifier:TOK_IDENT { + return new ast::nodes::ValueExpr( + ast::nodes::IntrinsicValueSymbol( + grammar_support::take_string(identifier), + grammar_support::take_string(package) + ) + ); + } + -> integer:TOK_INT { + return new ast::nodes::ValueExpr(ast::nodes::IntLiteral(grammar_support::take_string(integer))); + } + -> number:TOK_FLOAT { + return new ast::nodes::ValueExpr(ast::nodes::FloatLiteral(grammar_support::take_string(number))); + } + -> text:TOK_STRING { + return new ast::nodes::ValueExpr(ast::nodes::StringLiteral(grammar_support::take_string(text))); + } + -> value:parenthized_value { + return grammar_support::wrap_parenthesized(value); + } +} + +nonterm(ast::nodes::ParenthizedValue*) parenthized_value { + fun dup(p) [return p;] + fun del(p) [] + -> "(" value:value_expr ")" { + return new ast::nodes::ParenthizedValue(grammar_support::take_ptr(value)); + } +} + +nonterm(std::vector>*) arguments { + fun dup(p) [return p;] + fun del(p) [] + -> { + return new std::vector>(); + } + -> list:argument_list { + return list; + } +} + +nonterm(std::vector>*) argument_list { + fun dup(p) [return p;] + fun del(p) [] + -> value:value_expr { + auto* list = new std::vector>(); + list->push_back(grammar_support::take_ptr(value)); + return list; + } + -> list:argument_list "," value:value_expr { + list->push_back(grammar_support::take_ptr(value)); + return list; + } +} diff --git a/src/grammar/parser.y b/src/grammar/parser.y deleted file mode 100644 index 0d8903a7..00000000 --- a/src/grammar/parser.y +++ /dev/null @@ -1,447 +0,0 @@ -%skeleton "lalr1.cc" -%require "3.8" -%define api.parser.class {Parser} -%define api.value.type variant -%define parse.error detailed -%locations -%start package - -%code requires { - #include "ast/.hpp" - #include - #include - #include - #include - #include -} - -%code { - int yylex( - yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, - const char*& cursor, const char*& marker, const char* limit, - const std::string& sourcePath, const std::string& source, ast::nodes::Package*& ast, int& line, const char*& line_start); -} - -%param { const char*& cursor } -%param { const char*& marker } -%param { const char* limit } - -%param { const std::string& sourcePath } -%param { const std::string& source } -%param { ast::nodes::Package*& ast } -%param { int& line } -%param { const char*& line_start } - -// --- tokens --- -%token LPAREN RPAREN LCURLY RCURLY -%token COMMA COLON EQUAL -%token DOLLAR THIN_ARROW THICK_ARROW AT -%token MUT THIS -%token STRING IDENT INT FLOAT -%token ERROR - -// --- associativity --- -%left PLUS MINUS -%left STAR SLASH -%right TILDE - -// --- non-terminal types --- -%type package -%type > global_scope -%type declaration -%type variable_decl -%type function_decl -%type method_decl -%type > parameters method_parameters -%type >> type_list type_list_ne -%type parameter -%type type_expr -%type name_type -%type function_type -%type method_type -%type arrow_body -%type scope -%type > function_body -%type >> statements -%type statement -%type operator_call -%type operator_flip_call -%type function_call -%type statement_function_call -%type parenthized_value -%type value_expr -%type >> arguments - -%% - -package - : global_scope[glb] - { - $$ = ast::nodes::Package(std::move($glb)); - ast = new ast::nodes::Package(std::move($$)); - } - ; - -global_scope - : %empty - { $$ = std::vector(); } - | global_scope[glb] declaration[decl] - { - $glb.push_back(std::move($decl)); - $$ = std::move($glb); - } - ; - -declaration - : function_decl[fd] - { $$ = ast::nodes::Declaration(std::move($fd)); } - | method_decl[md] - { $$ = ast::nodes::Declaration(std::move($md)); } - ; - -variable_decl - : IDENT[name] type_expr[type] EQUAL value_expr[val] - { - $$ = ast::nodes::VariableDecl( - std::move($name), - std::move($type), - std::make_unique(std::move($val)) - ); - } - ; - -arrow_body - : THICK_ARROW value_expr[val] - { - $$ = ast::nodes::ArrowBody(std::make_unique(std::move($val))); - } - ; - -function_body - : arrow_body[arrow] - { - $$ = std::move($arrow); - } - | scope[scope] - { - $$ = std::move($scope); - } - ; - -function_decl - : type_expr[return_type] IDENT[name] LPAREN parameters[params] RPAREN function_body[body] - { - $$ = ast::nodes::FunctionDecl( - std::move($name), - std::move($params), - std::move($return_type), - std::move($body) - ); - } - ; - -method_decl - : type_expr[return_type] IDENT[name] LPAREN method_parameters[params] RPAREN function_body[body] - { - $$ = ast::nodes::MethodDecl( - std::move($name), - std::move($params), - std::move($return_type), - std::move($body), - false - ); - } - - | type_expr[return_type] IDENT[name] LPAREN method_parameters[params] RPAREN MUT function_body[body] - { - $$ = ast::nodes::MethodDecl( - std::move($name), - std::move($params), - std::move($return_type), - std::move($body), - true - ); - } - ; - -method_parameters - : %empty - { $$ = std::vector(); } - | THIS type_expr[type] - { - $$ = std::vector(); - $$.push_back( - ast::nodes::Parameter( - std::make_unique(std::move($type)), - "this" - ) - ); - } - | method_parameters[params] COMMA parameter[p] - { - $params.push_back(std::move($p)); - $$ = std::move($params); - } - ; - -parameters - : %empty - { $$ = std::vector(); } - | parameter[p] - { - $$ = std::vector(); - $$.push_back(std::move($p)); - } - | parameters[params] COMMA parameter[p] - { - $params.push_back(std::move($p)); - $$ = std::move($params); - } - ; - -parameter - : IDENT[name] type_expr[type] - { - $$ = ast::nodes::Parameter( - std::make_unique(std::move($type)), - std::move($name) - ); - } - ; - -type_list - : %empty - { $$ = std::vector>(); } - | type_expr[expr] - { - $$ = std::vector>(); - $$.push_back(std::make_unique(std::move($expr))); - } - | type_list[list] COMMA type_expr[expr] - { - $list.push_back(std::make_unique(std::move($expr))); - $$ = std::move($list); - } - ; - -type_list_ne - : type_expr[expr] - { - $$ = std::vector>(); - $$.push_back(std::make_unique(std::move($expr))); - } - | type_list[list] COMMA type_expr[expr] - { - $list.push_back(std::make_unique(std::move($expr))); - $$ = std::move($list); - } - ; - -function_type - : LPAREN type_list[params] RPAREN THIN_ARROW type_expr[ret_type] - { - $$ = ast::nodes::FunctionType( - std::move($params), - std::make_unique(std::move($ret_type)) - ); - } - ; - -method_type - : LPAREN THIS type_list_ne[params] RPAREN THIN_ARROW type_expr[ret_type] - { - $$ = ast::nodes::MethodType( - std::move($params), - std::make_unique(std::move($ret_type)), - false - ); - } - | LPAREN THIS type_list_ne[params] RPAREN MUT THIN_ARROW type_expr[ret_type] - { - $$ = ast::nodes::MethodType( - std::move($params), - std::make_unique(std::move($ret_type)), - true - ); - } - ; - -type_expr - : name_type[nt] - { $$ = ast::nodes::TypeExpression(std::move($nt)); } - | function_type[ft] - { $$ = ast::nodes::TypeExpression(std::move($ft)); } - | method_type[mt] - { $$ = ast::nodes::TypeExpression(std::move($mt)); } - ; - -name_type - : IDENT[id] - { $$ = ast::nodes::NameType(std::move($id), std::vector>()); } - ; - -scope - : LCURLY statements[stmts] RCURLY - { $$ = ast::nodes::Scope(std::move($stmts)); } - ; - -statements - : %empty - { $$ = std::vector>(); } - | statements[list] statement[stmt] - { - $list.push_back(std::make_unique(std::move($stmt))); - $$ = std::move($list); - } - ; - -statement - : statement_function_call[fc] - { $$ = ast::nodes::Statement(std::move($fc)); } - | variable_decl[var_decl] - { $$ = ast::nodes::Statement(std::move($var_decl)); } - ; - -statement_function_call - : IDENT[name] LPAREN arguments[args] RPAREN - { - $$ = ast::nodes::FunctionCall( - std::make_unique(ast::nodes::ValueExpr(ast::nodes::ValueSymbol(std::move($name)))), - std::move($args) - ); - } - | IDENT[pkg] DOLLAR IDENT[name] LPAREN arguments[args] RPAREN - { - $$ = ast::nodes::FunctionCall( - std::make_unique(ast::nodes::ValueExpr(ast::nodes::PackageValueSymbol(std::move($name), std::move($pkg)))), - std::move($args) - ); - } - | AT IDENT[pkg] DOLLAR IDENT[name] LPAREN arguments[args] RPAREN - { - $$ = ast::nodes::FunctionCall( - std::make_unique(ast::nodes::ValueExpr(ast::nodes::IntrinsicValueSymbol(std::move($name), std::move($pkg)))), - std::move($args) - ); - } - ; - -value_expr - : IDENT[id] - { $$ = ast::nodes::ValueExpr(ast::nodes::ValueSymbol(std::move($id))); } - | IDENT[pkg] DOLLAR IDENT[id] - { $$ = ast::nodes::ValueExpr(ast::nodes::PackageValueSymbol(std::move($id), std::move($pkg))); } - | AT IDENT[pkg] DOLLAR IDENT[id] - { $$ = ast::nodes::ValueExpr(ast::nodes::IntrinsicValueSymbol(std::move($id), std::move($pkg))); } - | INT[i] - { $$ = ast::nodes::ValueExpr(ast::nodes::IntLiteral(std::move($i))); } - | FLOAT[f] - { $$ = ast::nodes::ValueExpr(ast::nodes::FloatLiteral(std::move($f))); } - | STRING[s] - { $$ = ast::nodes::ValueExpr(ast::nodes::StringLiteral(std::move($s))); } - | function_call[fc] - { $$ = ast::nodes::ValueExpr(std::move($fc)); } - | operator_call[op] - { $$ = ast::nodes::ValueExpr(std::move($op)); } - | operator_flip_call[op_flip] - { $$ = ast::nodes::ValueExpr(std::move($op_flip)); } - | parenthized_value[pv] - { $$ = ast::nodes::ValueExpr(std::move($pv)); } - ; - -parenthized_value - : LPAREN value_expr[val] RPAREN - { $$ = ast::nodes::ParenthizedValue(std::make_unique(std::move($val))); } - ; - -function_call - : value_expr[callee] LPAREN arguments[args] RPAREN - { - $$ = ast::nodes::FunctionCall( - std::make_unique(std::move($callee)), - std::move($args) - ); - } - ; - -operator_flip_call - : TILDE value_expr[value] - { $$ = ast::nodes::OperatorFlipCall(std::make_unique(std::move($value))); } - ; - -operator_call - : value_expr[left] PLUS[op] value_expr[right] - { $$ = ast::nodes::OperatorCall(std::move($op), std::make_unique(std::move($left)), std::make_unique(std::move($right))); } - | value_expr[left] MINUS[op] value_expr[right] - { $$ = ast::nodes::OperatorCall(std::move($op), std::make_unique(std::move($left)), std::make_unique(std::move($right))); } - | value_expr[left] STAR[op] value_expr[right] - { $$ = ast::nodes::OperatorCall(std::move($op), std::make_unique(std::move($left)), std::make_unique(std::move($right))); } - | value_expr[left] SLASH[op] value_expr[right] - { $$ = ast::nodes::OperatorCall(std::move($op), std::make_unique(std::move($left)), std::make_unique(std::move($right))); } - ; - -arguments - : %empty - { $$ = std::vector>(); } - | value_expr[v] - { - $$ = std::vector>(); - $$.push_back(std::make_unique(std::move($v))); - } - | arguments[args] COMMA value_expr[v] - { - $args.push_back(std::make_unique(std::move($v))); - $$ = std::move($args); - } - ; - -%% - -static std::string findLine(const std::string& source, int lineNumber) { - int currentLine = 1; - size_t lineStart = 0; - - while (lineStart <= source.size()) { - size_t lineEnd = source.find('\n', lineStart); - if (lineEnd == std::string::npos) { - lineEnd = source.size(); - } - - if (currentLine == lineNumber) { - return source.substr(lineStart, lineEnd - lineStart); - } - - if (lineEnd == source.size()) { - break; - } - - lineStart = lineEnd + 1; - ++currentLine; - } - - return std::string(); -} - -void yy::Parser::error(const location_type& loc, const std::string& msg) { - std::cerr << sourcePath << ":" << loc.begin.line << ":" << loc.begin.column << ": error: " << msg << "\n"; - - const std::string line = findLine(source, loc.begin.line); - if (line.empty()) { - return; - } - - const std::string lineNumber = std::to_string(loc.begin.line); - std::cerr << lineNumber << " | " << line << "\n"; - - std::string caretLine; - caretLine.reserve(lineNumber.size() + 3 + line.size()); - caretLine.append(lineNumber.size(), ' '); - caretLine += " | "; - for (int column = 1; column < loc.begin.column; ++column) { - caretLine += static_cast(column - 1) < line.size() && line[static_cast(column - 1)] == '\t' ? '\t' : ' '; - } - - const int highlightWidth = std::max(1, loc.end.column - loc.begin.column); - caretLine.append(static_cast(highlightWidth), '^'); - std::cerr << caretLine << "\n"; -} diff --git a/src/main.cpp b/src/main.cpp index a7846a58..0505348c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,12 +1,10 @@ #include "ast/.hpp" -#include "parser.tab.h" +#include "glr.h" +#include "grammar/lexer.hpp" +#include "zane_parser.h" +#include #include #include -#include - -int yylex(yy::Parser::semantic_type* yylval, yy::Parser::location_type* yylloc, - const char*& cursor, const char*& marker, const char* limit, - const std::string& sourcePath, const std::string& source, ast::nodes::Package*& ast, int& line, const char*& line_start); std::string readFile(const std::string& path) { std::ifstream file(path); @@ -19,21 +17,26 @@ std::string readFile(const std::string& path) { int main() { const std::string inputPath = "test-parser/main.zn"; std::string input = readFile(inputPath); + Lexer lexer(inputPath, input); + Lexer::nextToken(&lexer); - const char* cursor = input.c_str(); - const char* marker = cursor; - const char* limit = cursor + input.size(); - const char* line_start = cursor; - int line = 1; - ast::nodes::Package* ast = nullptr; + ZaneParser parser; + GLR glr(&parser, parser.makeTables()); + glr.noisyFailedParse = false; + + SemanticValue result = NULL_SVAL; + const bool success = glr.glrParse(lexer, result); + if (!success) { + lexer.reportParseError(); + return 1; + } - yy::Parser parser(cursor, marker, limit, inputPath, input, ast, line, line_start); - int res = parser.parse(); + auto* ast = reinterpret_cast(result); if (ast != nullptr) { std::cout << (ast::evaluators::ToGraph {}(*ast)).render(); delete ast; } - return res; + return 0; } diff --git a/test-parser/main.zn b/test-parser/main.zn index d8c917e8..a71bb9c7 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -6,4 +6,6 @@ Void main(this Int, a Bool) { func (this Int) -> Void = 3.0 } -Int getNum() => 3 +Int getNum() { + print() +} diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json index 65c85e67..01e44599 100644 --- a/vcpkg-configuration.json +++ b/vcpkg-configuration.json @@ -10,5 +10,8 @@ "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", "name": "microsoft" } + ], + "overlay-ports": [ + "vcpkg-ports" ] } diff --git a/vcpkg-ports/elkhound-runtime/CMakeLists.txt b/vcpkg-ports/elkhound-runtime/CMakeLists.txt new file mode 100644 index 00000000..e1afcb14 --- /dev/null +++ b/vcpkg-ports/elkhound-runtime/CMakeLists.txt @@ -0,0 +1,88 @@ +cmake_minimum_required(VERSION 3.20) + +project(elkhound_runtime LANGUAGES C CXX) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +include(CMakePackageConfigHelpers) + +set(ELKHOUND_RUNTIME_SOURCES + src/elkhound/cyctimer.cc + src/elkhound/emitcode.cc + src/elkhound/glr.cc + src/elkhound/parsetables.cc + src/elkhound/ptreeact.cc + src/elkhound/ptreenode.cc + src/elkhound/useract.cc + src/smbase/autofile.cc + src/smbase/bflatten.cc + src/smbase/bit2d.cc + src/smbase/bitarray.cc + src/smbase/breaker.cpp + src/smbase/crc.cpp + src/smbase/cycles.c + src/smbase/datablok.cpp + src/smbase/exc.cpp + src/smbase/flatten.cc + src/smbase/gprintf.c + src/smbase/growbuf.cc + src/smbase/hashline.cc + src/smbase/hashtbl.cc + src/smbase/malloc_stub.c + src/smbase/mysig.cc + src/smbase/nonport.cpp + src/smbase/point.cc + src/smbase/srcloc.cc + src/smbase/str.cpp + src/smbase/strdict.cc + src/smbase/strhash.cc + src/smbase/stringset.cc + src/smbase/strtokp.cpp + src/smbase/strutil.cc + src/smbase/svdict.cc + src/smbase/syserr.cpp + src/smbase/trace.cc + src/smbase/trdelete.cc + src/smbase/vdtllist.cc + src/smbase/voidlist.cc + src/smbase/vptrmap.cc +) + +file(GLOB ELKHOUND_RUNTIME_HEADERS CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/elkhound/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/smbase/*.h" +) + +add_library(elkhound_runtime STATIC ${ELKHOUND_RUNTIME_SOURCES}) +add_library(elkhound_runtime::elkhound_runtime ALIAS elkhound_runtime) + +target_compile_definitions(elkhound_runtime PRIVATE __UNIX__) +target_include_directories(elkhound_runtime + PUBLIC + $ + $ + $ +) + +install(TARGETS elkhound_runtime EXPORT elkhound_runtimeTargets ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin) +install(FILES ${ELKHOUND_RUNTIME_HEADERS} DESTINATION include/elkhound_runtime) + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/elkhound_runtimeConfigVersion.cmake" + VERSION 1.0.0 + COMPATIBILITY SameMajorVersion +) + +configure_package_config_file( + "${CMAKE_CURRENT_SOURCE_DIR}/elkhound_runtimeConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/elkhound_runtimeConfig.cmake" + INSTALL_DESTINATION share/elkhound_runtime +) + +install(EXPORT elkhound_runtimeTargets NAMESPACE elkhound_runtime:: DESTINATION share/elkhound_runtime) +install(FILES + "${CMAKE_CURRENT_BINARY_DIR}/elkhound_runtimeConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/elkhound_runtimeConfigVersion.cmake" + DESTINATION share/elkhound_runtime +) diff --git a/vcpkg-ports/elkhound-runtime/elkhound_runtimeConfig.cmake.in b/vcpkg-ports/elkhound-runtime/elkhound_runtimeConfig.cmake.in new file mode 100644 index 00000000..eeb14081 --- /dev/null +++ b/vcpkg-ports/elkhound-runtime/elkhound_runtimeConfig.cmake.in @@ -0,0 +1,3 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/elkhound_runtimeTargets.cmake") diff --git a/vcpkg-ports/elkhound-runtime/portfile.cmake b/vcpkg-ports/elkhound-runtime/portfile.cmake new file mode 100644 index 00000000..10cafafd --- /dev/null +++ b/vcpkg-ports/elkhound-runtime/portfile.cmake @@ -0,0 +1,20 @@ +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO WeiDUorg/elkhound + REF b8f5589de119c89b36b1fc21d2f51c4a942ee3a8 + SHA512 f284e6750adda2a9795503cc2dff21cabba89e65d3c2e0e638f5393b09f84d16f8ef005c9ca937f93b50456a6f197b8bfaec8ce40863d59c77108d34bb74c54c + HEAD_REF master +) + +file(COPY "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt" DESTINATION "${SOURCE_PATH}") +file(COPY "${CMAKE_CURRENT_LIST_DIR}/elkhound_runtimeConfig.cmake.in" DESTINATION "${SOURCE_PATH}") + +vcpkg_configure_cmake( + SOURCE_PATH "${SOURCE_PATH}" +) + +vcpkg_install_cmake() +vcpkg_fixup_cmake_targets(CONFIG_PATH share/elkhound_runtime) + +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") +file(INSTALL "${SOURCE_PATH}/license.txt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) diff --git a/vcpkg-ports/elkhound-runtime/vcpkg.json b/vcpkg-ports/elkhound-runtime/vcpkg.json new file mode 100644 index 00000000..0cc45f9d --- /dev/null +++ b/vcpkg-ports/elkhound-runtime/vcpkg.json @@ -0,0 +1,7 @@ +{ + "name": "elkhound-runtime", + "version-string": "2026-05-28", + "description": "Elkhound parser runtime library bundled with smbase", + "homepage": "https://github.com/WeiDUorg/elkhound", + "license": "BSD-3-Clause" +} diff --git a/vcpkg.json b/vcpkg.json index be32b307..66ae5cda 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,6 +1,7 @@ { "dependencies": [ "nlohmann-json", - "cereal" + "cereal", + "elkhound-runtime" ] } From 1b052355a8ce36bbdc9a837580091a74ecb8fbe5 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 28 May 2026 23:36:34 +0200 Subject: [PATCH 052/154] use maintained elkhound --- devbox.json | 2 +- devbox.lock | 48 --------------------- nix/elkhound/flake.lock | 27 ++++++++++++ vcpkg-ports/elkhound-runtime/portfile.cmake | 2 + 4 files changed, 30 insertions(+), 49 deletions(-) create mode 100644 nix/elkhound/flake.lock diff --git a/devbox.json b/devbox.json index 8b6f145b..79e575a0 100644 --- a/devbox.json +++ b/devbox.json @@ -10,7 +10,7 @@ "ninja@latest", "zig@latest", "clang-tools@latest", - "elkhound@latest", + "path:nix/elkhound#default", "re2c@latest" ], "shell": { diff --git a/devbox.lock b/devbox.lock index 1e31972e..26e56d1b 100644 --- a/devbox.lock +++ b/devbox.lock @@ -153,54 +153,6 @@ } } }, - "elkhound@latest": { - "last_modified": "2026-04-23T13:07:47Z", - "resolved": "github:NixOS/nixpkgs/01fbdeef22b76df85ea168fbfe1bfd9e63681b30#elkhound", - "source": "devbox-search", - "version": "0-unstable-2020-04-13", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1i4ny8flqb1pgd1ly7f3c13a6mh9i6bx-elkhound-0-unstable-2020-04-13", - "default": true - } - ], - "store_path": "/nix/store/1i4ny8flqb1pgd1ly7f3c13a6mh9i6bx-elkhound-0-unstable-2020-04-13" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/jzl4xkd3l33ryiqrsbzcjmlwwr8v3w5g-elkhound-0-unstable-2020-04-13", - "default": true - } - ], - "store_path": "/nix/store/jzl4xkd3l33ryiqrsbzcjmlwwr8v3w5g-elkhound-0-unstable-2020-04-13" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/9n87n5khz2kzr3gkj2z6ynwgak0zskw5-elkhound-0-unstable-2020-04-13", - "default": true - } - ], - "store_path": "/nix/store/9n87n5khz2kzr3gkj2z6ynwgak0zskw5-elkhound-0-unstable-2020-04-13" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/macnab366i1q2zps273r05dh1pbs34y2-elkhound-0-unstable-2020-04-13", - "default": true - } - ], - "store_path": "/nix/store/macnab366i1q2zps273r05dh1pbs34y2-elkhound-0-unstable-2020-04-13" - } - } - }, "github:NixOS/nixpkgs/nixpkgs-unstable": { "last_modified": "2026-05-27T10:28:13Z", "resolved": "github:NixOS/nixpkgs/4100e830e085863741bc69b156ec4ccd53ab5be0?lastModified=1779877693&narHash=sha256-NOF9NAREhxr50bbBfVcVOq%2BArCMSoe8dP79Pk2uyARk%3D" diff --git a/nix/elkhound/flake.lock b/nix/elkhound/flake.lock new file mode 100644 index 00000000..62ede088 --- /dev/null +++ b/nix/elkhound/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1776949667, + "narHash": "sha256-GMSVw35Q+294GlrTUKlx087E31z7KurReQ1YHSKp5iw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "01fbdeef22b76df85ea168fbfe1bfd9e63681b30", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "01fbdeef22b76df85ea168fbfe1bfd9e63681b30", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/vcpkg-ports/elkhound-runtime/portfile.cmake b/vcpkg-ports/elkhound-runtime/portfile.cmake index 10cafafd..f779385e 100644 --- a/vcpkg-ports/elkhound-runtime/portfile.cmake +++ b/vcpkg-ports/elkhound-runtime/portfile.cmake @@ -1,3 +1,5 @@ +# Source: WeiDUorg/elkhound (https://github.com/WeiDUorg/elkhound) +# The REF below must match the rev in nix/elkhound/flake.nix. vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO WeiDUorg/elkhound From 747bc5949636bb74234cf1ff571f1399ea5643d0 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 28 May 2026 23:36:34 +0200 Subject: [PATCH 053/154] update --- nix/elkhound/flake.nix | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 nix/elkhound/flake.nix diff --git a/nix/elkhound/flake.nix b/nix/elkhound/flake.nix new file mode 100644 index 00000000..6bad0a9b --- /dev/null +++ b/nix/elkhound/flake.nix @@ -0,0 +1,35 @@ +{ + description = "elkhound parser generator - WeiDUorg/elkhound at pinned commit"; + + # Pinned to the same nixpkgs commit devbox uses, so no second download is needed. + # To update: bump the rev, then run `nix flake update` and update devbox.json. + inputs.nixpkgs.url = "github:NixOS/nixpkgs/01fbdeef22b76df85ea168fbfe1bfd9e63681b30"; + + outputs = { self, nixpkgs }: + let + # The exact same commit that vcpkg-ports/elkhound-runtime/portfile.cmake pins. + # Both must be kept in sync when upgrading. + src = { + owner = "WeiDUorg"; + repo = "elkhound"; + rev = "b8f5589de119c89b36b1fc21d2f51c4a942ee3a8"; + hash = "sha256-8kktKhGY71zsNDAPKxUPBhy39N7m+P4tWmpbWxK7HhI="; + }; + + supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; + + forAllSystems = nixpkgs.lib.genAttrs supportedSystems; + in + { + packages = forAllSystems (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + default = pkgs.elkhound.overrideAttrs (_old: { + src = pkgs.fetchFromGitHub src; + }); + } + ); + }; +} From ed029a581a2b77699e6e59cc14bc3303086166f8 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 28 May 2026 23:54:29 +0200 Subject: [PATCH 054/154] update --- justfile | 9 +- src/grammar/parser.cc | 1841 +++++++++++++++++++++++++++++++++++++++++ src/grammar/parser.gr | 162 ++-- src/grammar/parser.h | 245 ++++++ 4 files changed, 2175 insertions(+), 82 deletions(-) create mode 100644 src/grammar/parser.cc create mode 100644 src/grammar/parser.h diff --git a/justfile b/justfile index 251ef8d2..8cb4dcf1 100644 --- a/justfile +++ b/justfile @@ -10,4 +10,11 @@ release: test-parser: meson compile -C build - ./build/zane + ./build/zane test-parser/main.zn + +glr-stats: + meson compile -C build + ELKHOUND_DEBUG=1 ./build/zane test-parser/main.zn 2>/dev/null + +grammar-conflicts: + elkhound -v -tr conflict,prec src/grammar/parser.gr diff --git a/src/grammar/parser.cc b/src/grammar/parser.cc new file mode 100644 index 00000000..1db4fa0f --- /dev/null +++ b/src/grammar/parser.cc @@ -0,0 +1,1841 @@ +// src/grammar/parser.cc +// *** DO NOT EDIT BY HAND *** +// automatically generated by gramanl, from src/grammar/parser.gr + +// GLR source location information is enabled + +#include "parser.h" // ZaneParser +#include "parsetables.h" // ParseTables +#include "srcloc.h" // SourceLoc + +#include // assert +#include // std::cout +#include // abort + +static char const *termNames[] = { + "TOK_EOF", // 0 + "TOK_LPAREN", // 1 + "TOK_RPAREN", // 2 + "TOK_LCURLY", // 3 + "TOK_RCURLY", // 4 + "TOK_COMMA", // 5 + "TOK_COLON", // 6 + "TOK_EQUAL", // 7 + "TOK_DOLLAR", // 8 + "TOK_THIN_ARROW", // 9 + "TOK_THICK_ARROW", // 10 + "TOK_AT", // 11 + "TOK_MUT", // 12 + "TOK_THIS", // 13 + "TOK_STRING", // 14 + "TOK_IDENT", // 15 + "TOK_INT", // 16 + "TOK_FLOAT", // 17 + "TOK_PLUS", // 18 + "TOK_MINUS", // 19 + "TOK_STAR", // 20 + "TOK_SLASH", // 21 + "TOK_TILDE", // 22 + "TOK_ERROR", // 23 +}; + +string ZaneParser::terminalDescription(int termId, SemanticValue sval) +{ + return stringc << termNames[termId] + << "(" << (sval % 100000) << ")"; +} + + +static char const *nontermNames[] = { + "empty", // 0 + "__EarlyStartSymbol", // 1 + "package", // 2 + "global_scope", // 3 + "declaration", // 4 + "variable_decl", // 5 + "function_decl", // 6 + "method_decl", // 7 + "parameters", // 8 + "parameter_list", // 9 + "method_parameters", // 10 + "method_parameter_seq", // 11 + "parameter", // 12 + "type_list", // 13 + "type_list_ne", // 14 + "type_expr", // 15 + "name_type", // 16 + "function_type", // 17 + "method_type", // 18 + "arrow_body", // 19 + "function_body", // 20 + "scope", // 21 + "statements", // 22 + "statement", // 23 + "statement_function_call", // 24 + "value_expr", // 25 + "additive_expr", // 26 + "multiplicative_expr", // 27 + "unary_expr", // 28 + "postfix_expr", // 29 + "call_expr", // 30 + "primary_expr", // 31 + "parenthized_value", // 32 + "arguments", // 33 + "argument_list", // 34 +}; + +string ZaneParser::nonterminalDescription(int nontermId, SemanticValue sval) +{ + return stringc << nontermNames[nontermId] + << "(" << (sval % 100000) << ")"; +} + + +char const *ZaneParser::terminalName(int termId) +{ + return termNames[termId]; +} + +char const *ZaneParser::nonterminalName(int nontermId) +{ + return nontermNames[nontermId]; +} + +// ------------------- actions ------------------ +// [0] __EarlyStartSymbol[ast::nodes::Package*] -> top:package TOK_EOF +inline ast::nodes::Package* ZaneParser::action0___EarlyStartSymbol(SourceLoc loc, ast::nodes::Package* top) +#line 1 "" +{ return top; } +#line 110 "src/grammar/parser.cc" + +// [1] package[ast::nodes::Package*] -> declarations:global_scope +inline ast::nodes::Package* ZaneParser::action1_package(SourceLoc loc, std::vector* declarations) +#line 125 "src/grammar/parser.gr" +{ + return new ast::nodes::Package(grammar_support::take_value(declarations)); + } +#line 118 "src/grammar/parser.cc" + +// [2] global_scope[std::vector*] -> empty +inline std::vector* ZaneParser::action2_global_scope(SourceLoc loc) +#line 133 "src/grammar/parser.gr" +{ + return new std::vector(); + } +#line 126 "src/grammar/parser.cc" + +// [3] global_scope[std::vector*] -> declarations:global_scope declaration:declaration +inline std::vector* ZaneParser::action3_global_scope(SourceLoc loc, std::vector* declarations, ast::nodes::Declaration* declaration) +#line 136 "src/grammar/parser.gr" +{ + declarations->push_back(grammar_support::take_value(declaration)); + return declarations; + } +#line 135 "src/grammar/parser.cc" + +// [4] declaration[ast::nodes::Declaration*] -> function:function_decl +inline ast::nodes::Declaration* ZaneParser::action4_declaration(SourceLoc loc, ast::nodes::FunctionDecl* function) +#line 145 "src/grammar/parser.gr" +{ + return new ast::nodes::Declaration(grammar_support::take_value(function)); + } +#line 143 "src/grammar/parser.cc" + +// [5] declaration[ast::nodes::Declaration*] -> method:method_decl +inline ast::nodes::Declaration* ZaneParser::action5_declaration(SourceLoc loc, ast::nodes::MethodDecl* method) +#line 148 "src/grammar/parser.gr" +{ + return new ast::nodes::Declaration(grammar_support::take_value(method)); + } +#line 151 "src/grammar/parser.cc" + +// [6] variable_decl[ast::nodes::VariableDecl*] -> name:TOK_IDENT type:type_expr = value:value_expr +inline ast::nodes::VariableDecl* ZaneParser::action6_variable_decl(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type, ast::nodes::ValueExpr* value) +#line 156 "src/grammar/parser.gr" +{ + return new ast::nodes::VariableDecl( + grammar_support::take_string(name), + grammar_support::take_value(type), + grammar_support::take_ptr(value) + ); + } +#line 163 "src/grammar/parser.cc" + +// [7] function_decl[ast::nodes::FunctionDecl*] -> return_type:type_expr name:TOK_IDENT ( params:parameters ) body:function_body +inline ast::nodes::FunctionDecl* ZaneParser::action7_function_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body) +#line 168 "src/grammar/parser.gr" +{ + return new ast::nodes::FunctionDecl( + grammar_support::take_string(name), + grammar_support::take_value(params), + grammar_support::take_value(return_type), + grammar_support::take_value(body).value + ); + } +#line 176 "src/grammar/parser.cc" + +// [8] method_decl[ast::nodes::MethodDecl*] -> return_type:type_expr name:TOK_IDENT ( params:method_parameters ) body:function_body +inline ast::nodes::MethodDecl* ZaneParser::action8_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body) +#line 181 "src/grammar/parser.gr" +{ + return new ast::nodes::MethodDecl( + grammar_support::take_string(name), + grammar_support::take_value(params), + grammar_support::take_value(return_type), + grammar_support::take_value(body).value, + false + ); + } +#line 190 "src/grammar/parser.cc" + +// [9] method_decl[ast::nodes::MethodDecl*] -> return_type:type_expr name:TOK_IDENT ( params:method_parameters ) mut body:function_body +inline ast::nodes::MethodDecl* ZaneParser::action9_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body) +#line 190 "src/grammar/parser.gr" +{ + return new ast::nodes::MethodDecl( + grammar_support::take_string(name), + grammar_support::take_value(params), + grammar_support::take_value(return_type), + grammar_support::take_value(body).value, + true + ); + } +#line 204 "src/grammar/parser.cc" + +// [10] parameters[std::vector*] -> empty +inline std::vector* ZaneParser::action10_parameters(SourceLoc loc) +#line 204 "src/grammar/parser.gr" +{ + return new std::vector(); + } +#line 212 "src/grammar/parser.cc" + +// [11] parameters[std::vector*] -> list:parameter_list +inline std::vector* ZaneParser::action11_parameters(SourceLoc loc, std::vector* list) +#line 207 "src/grammar/parser.gr" +{ + return list; + } +#line 220 "src/grammar/parser.cc" + +// [12] parameter_list[std::vector*] -> parameter:parameter +inline std::vector* ZaneParser::action12_parameter_list(SourceLoc loc, ast::nodes::Parameter* parameter) +#line 215 "src/grammar/parser.gr" +{ + auto* list = new std::vector(); + list->push_back(grammar_support::take_value(parameter)); + return list; + } +#line 230 "src/grammar/parser.cc" + +// [13] parameter_list[std::vector*] -> list:parameter_list , parameter:parameter +inline std::vector* ZaneParser::action13_parameter_list(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter) +#line 220 "src/grammar/parser.gr" +{ + list->push_back(grammar_support::take_value(parameter)); + return list; + } +#line 239 "src/grammar/parser.cc" + +// [14] method_parameters[std::vector*] -> list:method_parameter_seq +inline std::vector* ZaneParser::action14_method_parameters(SourceLoc loc, std::vector* list) +#line 229 "src/grammar/parser.gr" +{ + return list; + } +#line 247 "src/grammar/parser.cc" + +// [15] method_parameter_seq[std::vector*] -> this type:type_expr +inline std::vector* ZaneParser::action15_method_parameter_seq(SourceLoc loc, ast::nodes::TypeExpression* type) +#line 237 "src/grammar/parser.gr" +{ + auto* list = new std::vector(); + list->push_back(ast::nodes::Parameter(grammar_support::take_ptr(type), "this")); + return list; + } +#line 257 "src/grammar/parser.cc" + +// [16] method_parameter_seq[std::vector*] -> list:method_parameter_seq , parameter:parameter +inline std::vector* ZaneParser::action16_method_parameter_seq(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter) +#line 242 "src/grammar/parser.gr" +{ + list->push_back(grammar_support::take_value(parameter)); + return list; + } +#line 266 "src/grammar/parser.cc" + +// [17] parameter[ast::nodes::Parameter*] -> name:TOK_IDENT type:type_expr +inline ast::nodes::Parameter* ZaneParser::action17_parameter(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type) +#line 251 "src/grammar/parser.gr" +{ + return new ast::nodes::Parameter( + grammar_support::take_ptr(type), + grammar_support::take_string(name) + ); + } +#line 277 "src/grammar/parser.cc" + +// [18] type_list[std::vector>*] -> empty +inline std::vector>* ZaneParser::action18_type_list(SourceLoc loc) +#line 262 "src/grammar/parser.gr" +{ + return new std::vector>(); + } +#line 285 "src/grammar/parser.cc" + +// [19] type_list[std::vector>*] -> list:type_list_ne +inline std::vector>* ZaneParser::action19_type_list(SourceLoc loc, std::vector>* list) +#line 265 "src/grammar/parser.gr" +{ + return list; + } +#line 293 "src/grammar/parser.cc" + +// [20] type_list_ne[std::vector>*] -> expr:type_expr +inline std::vector>* ZaneParser::action20_type_list_ne(SourceLoc loc, ast::nodes::TypeExpression* expr) +#line 273 "src/grammar/parser.gr" +{ + auto* list = new std::vector>(); + list->push_back(grammar_support::take_ptr(expr)); + return list; + } +#line 303 "src/grammar/parser.cc" + +// [21] type_list_ne[std::vector>*] -> list:type_list_ne , expr:type_expr +inline std::vector>* ZaneParser::action21_type_list_ne(SourceLoc loc, std::vector>* list, ast::nodes::TypeExpression* expr) +#line 278 "src/grammar/parser.gr" +{ + list->push_back(grammar_support::take_ptr(expr)); + return list; + } +#line 312 "src/grammar/parser.cc" + +// [22] type_expr[ast::nodes::TypeExpression*] -> name:name_type +inline ast::nodes::TypeExpression* ZaneParser::action22_type_expr(SourceLoc loc, ast::nodes::NameType* name) +#line 287 "src/grammar/parser.gr" +{ + return new ast::nodes::TypeExpression(grammar_support::take_value(name)); + } +#line 320 "src/grammar/parser.cc" + +// [23] type_expr[ast::nodes::TypeExpression*] -> function:function_type +inline ast::nodes::TypeExpression* ZaneParser::action23_type_expr(SourceLoc loc, ast::nodes::FunctionType* function) +#line 290 "src/grammar/parser.gr" +{ + return new ast::nodes::TypeExpression(grammar_support::take_value(function)); + } +#line 328 "src/grammar/parser.cc" + +// [24] type_expr[ast::nodes::TypeExpression*] -> method:method_type +inline ast::nodes::TypeExpression* ZaneParser::action24_type_expr(SourceLoc loc, ast::nodes::MethodType* method) +#line 293 "src/grammar/parser.gr" +{ + return new ast::nodes::TypeExpression(grammar_support::take_value(method)); + } +#line 336 "src/grammar/parser.cc" + +// [25] name_type[ast::nodes::NameType*] -> identifier:TOK_IDENT +inline ast::nodes::NameType* ZaneParser::action25_name_type(SourceLoc loc, std::string* identifier) +#line 301 "src/grammar/parser.gr" +{ + return new ast::nodes::NameType( + grammar_support::take_string(identifier), + std::vector>() + ); + } +#line 347 "src/grammar/parser.cc" + +// [26] function_type[ast::nodes::FunctionType*] -> ( params:type_list ) -> return_type:type_expr +inline ast::nodes::FunctionType* ZaneParser::action26_function_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) +#line 312 "src/grammar/parser.gr" +{ + return new ast::nodes::FunctionType( + grammar_support::take_value(params), + grammar_support::take_ptr(return_type) + ); + } +#line 358 "src/grammar/parser.cc" + +// [27] method_type[ast::nodes::MethodType*] -> ( this params:type_list_ne ) -> return_type:type_expr +inline ast::nodes::MethodType* ZaneParser::action27_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) +#line 323 "src/grammar/parser.gr" +{ + return new ast::nodes::MethodType( + grammar_support::take_value(params), + grammar_support::take_ptr(return_type), + false + ); + } +#line 370 "src/grammar/parser.cc" + +// [28] method_type[ast::nodes::MethodType*] -> ( this params:type_list_ne ) mut -> return_type:type_expr +inline ast::nodes::MethodType* ZaneParser::action28_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) +#line 330 "src/grammar/parser.gr" +{ + return new ast::nodes::MethodType( + grammar_support::take_value(params), + grammar_support::take_ptr(return_type), + true + ); + } +#line 382 "src/grammar/parser.cc" + +// [29] arrow_body[ast::nodes::ArrowBody*] -> => value:value_expr +inline ast::nodes::ArrowBody* ZaneParser::action29_arrow_body(SourceLoc loc, ast::nodes::ValueExpr* value) +#line 342 "src/grammar/parser.gr" +{ + return new ast::nodes::ArrowBody(grammar_support::take_ptr(value)); + } +#line 390 "src/grammar/parser.cc" + +// [30] function_body[grammar_support::FunctionBodyValue*] -> body:arrow_body +inline grammar_support::FunctionBodyValue* ZaneParser::action30_function_body(SourceLoc loc, ast::nodes::ArrowBody* body) +#line 350 "src/grammar/parser.gr" +{ + return new grammar_support::FunctionBodyValue(grammar_support::take_value(body)); + } +#line 398 "src/grammar/parser.cc" + +// [31] function_body[grammar_support::FunctionBodyValue*] -> body:scope +inline grammar_support::FunctionBodyValue* ZaneParser::action31_function_body(SourceLoc loc, ast::nodes::Scope* body) +#line 353 "src/grammar/parser.gr" +{ + return new grammar_support::FunctionBodyValue(grammar_support::take_value(body)); + } +#line 406 "src/grammar/parser.cc" + +// [32] scope[ast::nodes::Scope*] -> { statements:statements } +inline ast::nodes::Scope* ZaneParser::action32_scope(SourceLoc loc, std::vector>* statements) +#line 361 "src/grammar/parser.gr" +{ + return new ast::nodes::Scope(grammar_support::take_value(statements)); + } +#line 414 "src/grammar/parser.cc" + +// [33] statements[std::vector>*] -> empty +inline std::vector>* ZaneParser::action33_statements(SourceLoc loc) +#line 369 "src/grammar/parser.gr" +{ + return new std::vector>(); + } +#line 422 "src/grammar/parser.cc" + +// [34] statements[std::vector>*] -> list:statements statement:statement +inline std::vector>* ZaneParser::action34_statements(SourceLoc loc, std::vector>* list, ast::nodes::Statement* statement) +#line 372 "src/grammar/parser.gr" +{ + list->push_back(grammar_support::take_ptr(statement)); + return list; + } +#line 431 "src/grammar/parser.cc" + +// [35] statement[ast::nodes::Statement*] -> call:statement_function_call +inline ast::nodes::Statement* ZaneParser::action35_statement(SourceLoc loc, ast::nodes::FunctionCall* call) +#line 381 "src/grammar/parser.gr" +{ + return new ast::nodes::Statement(grammar_support::take_value(call)); + } +#line 439 "src/grammar/parser.cc" + +// [36] statement[ast::nodes::Statement*] -> declaration:variable_decl +inline ast::nodes::Statement* ZaneParser::action36_statement(SourceLoc loc, ast::nodes::VariableDecl* declaration) +#line 384 "src/grammar/parser.gr" +{ + return new ast::nodes::Statement(grammar_support::take_value(declaration)); + } +#line 447 "src/grammar/parser.cc" + +// [37] statement_function_call[ast::nodes::FunctionCall*] -> call:call_expr +inline ast::nodes::FunctionCall* ZaneParser::action37_statement_function_call(SourceLoc loc, ast::nodes::FunctionCall* call) +#line 392 "src/grammar/parser.gr" +{ + return call; + } +#line 455 "src/grammar/parser.cc" + +// [38] value_expr[ast::nodes::ValueExpr*] -> expr:additive_expr +inline ast::nodes::ValueExpr* ZaneParser::action38_value_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) +#line 400 "src/grammar/parser.gr" +{ + return expr; + } +#line 463 "src/grammar/parser.cc" + +// [39] additive_expr[ast::nodes::ValueExpr*] -> expr:multiplicative_expr +inline ast::nodes::ValueExpr* ZaneParser::action39_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) +#line 408 "src/grammar/parser.gr" +{ + return expr; + } +#line 471 "src/grammar/parser.cc" + +// [40] additive_expr[ast::nodes::ValueExpr*] -> left:additive_expr + right:multiplicative_expr %prec(10) +inline ast::nodes::ValueExpr* ZaneParser::action40_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) +#line 411 "src/grammar/parser.gr" +{ + return grammar_support::make_binary("+", left, right); + } +#line 479 "src/grammar/parser.cc" + +// [41] additive_expr[ast::nodes::ValueExpr*] -> left:additive_expr - right:multiplicative_expr %prec(10) +inline ast::nodes::ValueExpr* ZaneParser::action41_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) +#line 414 "src/grammar/parser.gr" +{ + return grammar_support::make_binary("-", left, right); + } +#line 487 "src/grammar/parser.cc" + +// [42] multiplicative_expr[ast::nodes::ValueExpr*] -> expr:unary_expr +inline ast::nodes::ValueExpr* ZaneParser::action42_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) +#line 422 "src/grammar/parser.gr" +{ + return expr; + } +#line 495 "src/grammar/parser.cc" + +// [43] multiplicative_expr[ast::nodes::ValueExpr*] -> left:multiplicative_expr * right:unary_expr %prec(20) +inline ast::nodes::ValueExpr* ZaneParser::action43_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) +#line 425 "src/grammar/parser.gr" +{ + return grammar_support::make_binary("*", left, right); + } +#line 503 "src/grammar/parser.cc" + +// [44] multiplicative_expr[ast::nodes::ValueExpr*] -> left:multiplicative_expr / right:unary_expr %prec(20) +inline ast::nodes::ValueExpr* ZaneParser::action44_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) +#line 428 "src/grammar/parser.gr" +{ + return grammar_support::make_binary("/", left, right); + } +#line 511 "src/grammar/parser.cc" + +// [45] unary_expr[ast::nodes::ValueExpr*] -> expr:postfix_expr +inline ast::nodes::ValueExpr* ZaneParser::action45_unary_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) +#line 436 "src/grammar/parser.gr" +{ + return expr; + } +#line 519 "src/grammar/parser.cc" + +// [46] unary_expr[ast::nodes::ValueExpr*] -> ~ expr:unary_expr %prec(30) +inline ast::nodes::ValueExpr* ZaneParser::action46_unary_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) +#line 439 "src/grammar/parser.gr" +{ + return grammar_support::make_flip(expr); + } +#line 527 "src/grammar/parser.cc" + +// [47] postfix_expr[ast::nodes::ValueExpr*] -> expr:primary_expr +inline ast::nodes::ValueExpr* ZaneParser::action47_postfix_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) +#line 447 "src/grammar/parser.gr" +{ + return expr; + } +#line 535 "src/grammar/parser.cc" + +// [48] postfix_expr[ast::nodes::ValueExpr*] -> call:call_expr +inline ast::nodes::ValueExpr* ZaneParser::action48_postfix_expr(SourceLoc loc, ast::nodes::FunctionCall* call) +#line 450 "src/grammar/parser.gr" +{ + return grammar_support::wrap_call(call); + } +#line 543 "src/grammar/parser.cc" + +// [49] call_expr[ast::nodes::FunctionCall*] -> callee:primary_expr ( args:arguments ) +inline ast::nodes::FunctionCall* ZaneParser::action49_call_expr(SourceLoc loc, ast::nodes::ValueExpr* callee, std::vector>* args) +#line 458 "src/grammar/parser.gr" +{ + return new ast::nodes::FunctionCall( + grammar_support::take_ptr(callee), + grammar_support::take_value(args) + ); + } +#line 554 "src/grammar/parser.cc" + +// [50] call_expr[ast::nodes::FunctionCall*] -> callee:call_expr ( args:arguments ) +inline ast::nodes::FunctionCall* ZaneParser::action50_call_expr(SourceLoc loc, ast::nodes::FunctionCall* callee, std::vector>* args) +#line 464 "src/grammar/parser.gr" +{ + return new ast::nodes::FunctionCall( + std::make_unique(grammar_support::take_value(callee)), + grammar_support::take_value(args) + ); + } +#line 565 "src/grammar/parser.cc" + +// [51] primary_expr[ast::nodes::ValueExpr*] -> identifier:TOK_IDENT +inline ast::nodes::ValueExpr* ZaneParser::action51_primary_expr(SourceLoc loc, std::string* identifier) +#line 475 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr(ast::nodes::ValueSymbol(grammar_support::take_string(identifier))); + } +#line 573 "src/grammar/parser.cc" + +// [52] primary_expr[ast::nodes::ValueExpr*] -> package:TOK_IDENT $ identifier:TOK_IDENT +inline ast::nodes::ValueExpr* ZaneParser::action52_primary_expr(SourceLoc loc, std::string* package, std::string* identifier) +#line 478 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr( + ast::nodes::PackageValueSymbol( + grammar_support::take_string(identifier), + grammar_support::take_string(package) + ) + ); + } +#line 586 "src/grammar/parser.cc" + +// [53] primary_expr[ast::nodes::ValueExpr*] -> @ package:TOK_IDENT $ identifier:TOK_IDENT +inline ast::nodes::ValueExpr* ZaneParser::action53_primary_expr(SourceLoc loc, std::string* package, std::string* identifier) +#line 486 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr( + ast::nodes::IntrinsicValueSymbol( + grammar_support::take_string(identifier), + grammar_support::take_string(package) + ) + ); + } +#line 599 "src/grammar/parser.cc" + +// [54] primary_expr[ast::nodes::ValueExpr*] -> integer:TOK_INT +inline ast::nodes::ValueExpr* ZaneParser::action54_primary_expr(SourceLoc loc, std::string* integer) +#line 494 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr(ast::nodes::IntLiteral(grammar_support::take_string(integer))); + } +#line 607 "src/grammar/parser.cc" + +// [55] primary_expr[ast::nodes::ValueExpr*] -> number:TOK_FLOAT +inline ast::nodes::ValueExpr* ZaneParser::action55_primary_expr(SourceLoc loc, std::string* number) +#line 497 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr(ast::nodes::FloatLiteral(grammar_support::take_string(number))); + } +#line 615 "src/grammar/parser.cc" + +// [56] primary_expr[ast::nodes::ValueExpr*] -> text:TOK_STRING +inline ast::nodes::ValueExpr* ZaneParser::action56_primary_expr(SourceLoc loc, std::string* text) +#line 500 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr(ast::nodes::StringLiteral(grammar_support::take_string(text))); + } +#line 623 "src/grammar/parser.cc" + +// [57] primary_expr[ast::nodes::ValueExpr*] -> value:parenthized_value +inline ast::nodes::ValueExpr* ZaneParser::action57_primary_expr(SourceLoc loc, ast::nodes::ParenthizedValue* value) +#line 503 "src/grammar/parser.gr" +{ + return grammar_support::wrap_parenthesized(value); + } +#line 631 "src/grammar/parser.cc" + +// [58] parenthized_value[ast::nodes::ParenthizedValue*] -> ( value:value_expr ) +inline ast::nodes::ParenthizedValue* ZaneParser::action58_parenthized_value(SourceLoc loc, ast::nodes::ValueExpr* value) +#line 511 "src/grammar/parser.gr" +{ + return new ast::nodes::ParenthizedValue(grammar_support::take_ptr(value)); + } +#line 639 "src/grammar/parser.cc" + +// [59] arguments[std::vector>*] -> empty +inline std::vector>* ZaneParser::action59_arguments(SourceLoc loc) +#line 519 "src/grammar/parser.gr" +{ + return new std::vector>(); + } +#line 647 "src/grammar/parser.cc" + +// [60] arguments[std::vector>*] -> list:argument_list +inline std::vector>* ZaneParser::action60_arguments(SourceLoc loc, std::vector>* list) +#line 522 "src/grammar/parser.gr" +{ + return list; + } +#line 655 "src/grammar/parser.cc" + +// [61] argument_list[std::vector>*] -> value:value_expr +inline std::vector>* ZaneParser::action61_argument_list(SourceLoc loc, ast::nodes::ValueExpr* value) +#line 530 "src/grammar/parser.gr" +{ + auto* list = new std::vector>(); + list->push_back(grammar_support::take_ptr(value)); + return list; + } +#line 665 "src/grammar/parser.cc" + +// [62] argument_list[std::vector>*] -> list:argument_list , value:value_expr +inline std::vector>* ZaneParser::action62_argument_list(SourceLoc loc, std::vector>* list, ast::nodes::ValueExpr* value) +#line 535 "src/grammar/parser.gr" +{ + list->push_back(grammar_support::take_ptr(value)); + return list; + } +#line 674 "src/grammar/parser.cc" + + +/*static*/ SemanticValue ZaneParser::doReductionAction( + ZaneParser *ths, + int productionId, SemanticValue const *semanticValues, + SourceLoc loc) +{ + switch (productionId) { + case 0: + return (SemanticValue)(ths->action0___EarlyStartSymbol(loc, (ast::nodes::Package*)(semanticValues[0]))); + case 1: + return (SemanticValue)(ths->action1_package(loc, (std::vector*)(semanticValues[0]))); + case 2: + return (SemanticValue)(ths->action2_global_scope(loc)); + case 3: + return (SemanticValue)(ths->action3_global_scope(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Declaration*)(semanticValues[1]))); + case 4: + return (SemanticValue)(ths->action4_declaration(loc, (ast::nodes::FunctionDecl*)(semanticValues[0]))); + case 5: + return (SemanticValue)(ths->action5_declaration(loc, (ast::nodes::MethodDecl*)(semanticValues[0]))); + case 6: + return (SemanticValue)(ths->action6_variable_decl(loc, (std::string*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[1]), (ast::nodes::ValueExpr*)(semanticValues[3]))); + case 7: + return (SemanticValue)(ths->action7_function_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammar_support::FunctionBodyValue*)(semanticValues[5]))); + case 8: + return (SemanticValue)(ths->action8_method_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammar_support::FunctionBodyValue*)(semanticValues[5]))); + case 9: + return (SemanticValue)(ths->action9_method_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammar_support::FunctionBodyValue*)(semanticValues[6]))); + case 10: + return (SemanticValue)(ths->action10_parameters(loc)); + case 11: + return (SemanticValue)(ths->action11_parameters(loc, (std::vector*)(semanticValues[0]))); + case 12: + return (SemanticValue)(ths->action12_parameter_list(loc, (ast::nodes::Parameter*)(semanticValues[0]))); + case 13: + return (SemanticValue)(ths->action13_parameter_list(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Parameter*)(semanticValues[2]))); + case 14: + return (SemanticValue)(ths->action14_method_parameters(loc, (std::vector*)(semanticValues[0]))); + case 15: + return (SemanticValue)(ths->action15_method_parameter_seq(loc, (ast::nodes::TypeExpression*)(semanticValues[1]))); + case 16: + return (SemanticValue)(ths->action16_method_parameter_seq(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Parameter*)(semanticValues[2]))); + case 17: + return (SemanticValue)(ths->action17_parameter(loc, (std::string*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[1]))); + case 18: + return (SemanticValue)(ths->action18_type_list(loc)); + case 19: + return (SemanticValue)(ths->action19_type_list(loc, (std::vector>*)(semanticValues[0]))); + case 20: + return (SemanticValue)(ths->action20_type_list_ne(loc, (ast::nodes::TypeExpression*)(semanticValues[0]))); + case 21: + return (SemanticValue)(ths->action21_type_list_ne(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[2]))); + case 22: + return (SemanticValue)(ths->action22_type_expr(loc, (ast::nodes::NameType*)(semanticValues[0]))); + case 23: + return (SemanticValue)(ths->action23_type_expr(loc, (ast::nodes::FunctionType*)(semanticValues[0]))); + case 24: + return (SemanticValue)(ths->action24_type_expr(loc, (ast::nodes::MethodType*)(semanticValues[0]))); + case 25: + return (SemanticValue)(ths->action25_name_type(loc, (std::string*)(semanticValues[0]))); + case 26: + return (SemanticValue)(ths->action26_function_type(loc, (std::vector>*)(semanticValues[1]), (ast::nodes::TypeExpression*)(semanticValues[4]))); + case 27: + return (SemanticValue)(ths->action27_method_type(loc, (std::vector>*)(semanticValues[2]), (ast::nodes::TypeExpression*)(semanticValues[5]))); + case 28: + return (SemanticValue)(ths->action28_method_type(loc, (std::vector>*)(semanticValues[2]), (ast::nodes::TypeExpression*)(semanticValues[6]))); + case 29: + return (SemanticValue)(ths->action29_arrow_body(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); + case 30: + return (SemanticValue)(ths->action30_function_body(loc, (ast::nodes::ArrowBody*)(semanticValues[0]))); + case 31: + return (SemanticValue)(ths->action31_function_body(loc, (ast::nodes::Scope*)(semanticValues[0]))); + case 32: + return (SemanticValue)(ths->action32_scope(loc, (std::vector>*)(semanticValues[1]))); + case 33: + return (SemanticValue)(ths->action33_statements(loc)); + case 34: + return (SemanticValue)(ths->action34_statements(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::Statement*)(semanticValues[1]))); + case 35: + return (SemanticValue)(ths->action35_statement(loc, (ast::nodes::FunctionCall*)(semanticValues[0]))); + case 36: + return (SemanticValue)(ths->action36_statement(loc, (ast::nodes::VariableDecl*)(semanticValues[0]))); + case 37: + return (SemanticValue)(ths->action37_statement_function_call(loc, (ast::nodes::FunctionCall*)(semanticValues[0]))); + case 38: + return (SemanticValue)(ths->action38_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); + case 39: + return (SemanticValue)(ths->action39_additive_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); + case 40: + return (SemanticValue)(ths->action40_additive_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); + case 41: + return (SemanticValue)(ths->action41_additive_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); + case 42: + return (SemanticValue)(ths->action42_multiplicative_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); + case 43: + return (SemanticValue)(ths->action43_multiplicative_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); + case 44: + return (SemanticValue)(ths->action44_multiplicative_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); + case 45: + return (SemanticValue)(ths->action45_unary_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); + case 46: + return (SemanticValue)(ths->action46_unary_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); + case 47: + return (SemanticValue)(ths->action47_postfix_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); + case 48: + return (SemanticValue)(ths->action48_postfix_expr(loc, (ast::nodes::FunctionCall*)(semanticValues[0]))); + case 49: + return (SemanticValue)(ths->action49_call_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (std::vector>*)(semanticValues[2]))); + case 50: + return (SemanticValue)(ths->action50_call_expr(loc, (ast::nodes::FunctionCall*)(semanticValues[0]), (std::vector>*)(semanticValues[2]))); + case 51: + return (SemanticValue)(ths->action51_primary_expr(loc, (std::string*)(semanticValues[0]))); + case 52: + return (SemanticValue)(ths->action52_primary_expr(loc, (std::string*)(semanticValues[0]), (std::string*)(semanticValues[2]))); + case 53: + return (SemanticValue)(ths->action53_primary_expr(loc, (std::string*)(semanticValues[1]), (std::string*)(semanticValues[3]))); + case 54: + return (SemanticValue)(ths->action54_primary_expr(loc, (std::string*)(semanticValues[0]))); + case 55: + return (SemanticValue)(ths->action55_primary_expr(loc, (std::string*)(semanticValues[0]))); + case 56: + return (SemanticValue)(ths->action56_primary_expr(loc, (std::string*)(semanticValues[0]))); + case 57: + return (SemanticValue)(ths->action57_primary_expr(loc, (ast::nodes::ParenthizedValue*)(semanticValues[0]))); + case 58: + return (SemanticValue)(ths->action58_parenthized_value(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); + case 59: + return (SemanticValue)(ths->action59_arguments(loc)); + case 60: + return (SemanticValue)(ths->action60_arguments(loc, (std::vector>*)(semanticValues[0]))); + case 61: + return (SemanticValue)(ths->action61_argument_list(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); + case 62: + return (SemanticValue)(ths->action62_argument_list(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); + default: + assert(!"invalid production code"); + return (SemanticValue)0; // silence warning + } +} + +UserActions::ReductionActionFunc ZaneParser::getReductionAction() +{ + return (ReductionActionFunc)&ZaneParser::doReductionAction; +} + + +// ---------------- dup/del/merge/keep nonterminals --------------- + +inline ast::nodes::Package* ZaneParser::dup_package(ast::nodes::Package* p) +#line 123 "src/grammar/parser.gr" +{return p; } +#line 826 "src/grammar/parser.cc" + +inline void ZaneParser::del_package(ast::nodes::Package* p) +#line 124 "src/grammar/parser.gr" +{ } +#line 831 "src/grammar/parser.cc" + +inline std::vector* ZaneParser::dup_global_scope(std::vector* p) +#line 131 "src/grammar/parser.gr" +{return p; } +#line 836 "src/grammar/parser.cc" + +inline void ZaneParser::del_global_scope(std::vector* p) +#line 132 "src/grammar/parser.gr" +{ } +#line 841 "src/grammar/parser.cc" + +inline ast::nodes::Declaration* ZaneParser::dup_declaration(ast::nodes::Declaration* p) +#line 143 "src/grammar/parser.gr" +{return p; } +#line 846 "src/grammar/parser.cc" + +inline void ZaneParser::del_declaration(ast::nodes::Declaration* p) +#line 144 "src/grammar/parser.gr" +{ } +#line 851 "src/grammar/parser.cc" + +inline ast::nodes::VariableDecl* ZaneParser::dup_variable_decl(ast::nodes::VariableDecl* p) +#line 154 "src/grammar/parser.gr" +{return p; } +#line 856 "src/grammar/parser.cc" + +inline void ZaneParser::del_variable_decl(ast::nodes::VariableDecl* p) +#line 155 "src/grammar/parser.gr" +{ } +#line 861 "src/grammar/parser.cc" + +inline ast::nodes::FunctionDecl* ZaneParser::dup_function_decl(ast::nodes::FunctionDecl* p) +#line 166 "src/grammar/parser.gr" +{return p; } +#line 866 "src/grammar/parser.cc" + +inline void ZaneParser::del_function_decl(ast::nodes::FunctionDecl* p) +#line 167 "src/grammar/parser.gr" +{ } +#line 871 "src/grammar/parser.cc" + +inline ast::nodes::MethodDecl* ZaneParser::dup_method_decl(ast::nodes::MethodDecl* p) +#line 179 "src/grammar/parser.gr" +{return p; } +#line 876 "src/grammar/parser.cc" + +inline void ZaneParser::del_method_decl(ast::nodes::MethodDecl* p) +#line 180 "src/grammar/parser.gr" +{ } +#line 881 "src/grammar/parser.cc" + +inline std::vector* ZaneParser::dup_parameters(std::vector* p) +#line 202 "src/grammar/parser.gr" +{return p; } +#line 886 "src/grammar/parser.cc" + +inline void ZaneParser::del_parameters(std::vector* p) +#line 203 "src/grammar/parser.gr" +{ } +#line 891 "src/grammar/parser.cc" + +inline std::vector* ZaneParser::dup_parameter_list(std::vector* p) +#line 213 "src/grammar/parser.gr" +{return p; } +#line 896 "src/grammar/parser.cc" + +inline void ZaneParser::del_parameter_list(std::vector* p) +#line 214 "src/grammar/parser.gr" +{ } +#line 901 "src/grammar/parser.cc" + +inline std::vector* ZaneParser::dup_method_parameters(std::vector* p) +#line 227 "src/grammar/parser.gr" +{return p; } +#line 906 "src/grammar/parser.cc" + +inline void ZaneParser::del_method_parameters(std::vector* p) +#line 228 "src/grammar/parser.gr" +{ } +#line 911 "src/grammar/parser.cc" + +inline std::vector* ZaneParser::dup_method_parameter_seq(std::vector* p) +#line 235 "src/grammar/parser.gr" +{return p; } +#line 916 "src/grammar/parser.cc" + +inline void ZaneParser::del_method_parameter_seq(std::vector* p) +#line 236 "src/grammar/parser.gr" +{ } +#line 921 "src/grammar/parser.cc" + +inline ast::nodes::Parameter* ZaneParser::dup_parameter(ast::nodes::Parameter* p) +#line 249 "src/grammar/parser.gr" +{return p; } +#line 926 "src/grammar/parser.cc" + +inline void ZaneParser::del_parameter(ast::nodes::Parameter* p) +#line 250 "src/grammar/parser.gr" +{ } +#line 931 "src/grammar/parser.cc" + +inline std::vector>* ZaneParser::dup_type_list(std::vector>* p) +#line 260 "src/grammar/parser.gr" +{return p; } +#line 936 "src/grammar/parser.cc" + +inline void ZaneParser::del_type_list(std::vector>* p) +#line 261 "src/grammar/parser.gr" +{ } +#line 941 "src/grammar/parser.cc" + +inline std::vector>* ZaneParser::dup_type_list_ne(std::vector>* p) +#line 271 "src/grammar/parser.gr" +{return p; } +#line 946 "src/grammar/parser.cc" + +inline void ZaneParser::del_type_list_ne(std::vector>* p) +#line 272 "src/grammar/parser.gr" +{ } +#line 951 "src/grammar/parser.cc" + +inline ast::nodes::TypeExpression* ZaneParser::dup_type_expr(ast::nodes::TypeExpression* p) +#line 285 "src/grammar/parser.gr" +{return p; } +#line 956 "src/grammar/parser.cc" + +inline void ZaneParser::del_type_expr(ast::nodes::TypeExpression* p) +#line 286 "src/grammar/parser.gr" +{ } +#line 961 "src/grammar/parser.cc" + +inline ast::nodes::NameType* ZaneParser::dup_name_type(ast::nodes::NameType* p) +#line 299 "src/grammar/parser.gr" +{return p; } +#line 966 "src/grammar/parser.cc" + +inline void ZaneParser::del_name_type(ast::nodes::NameType* p) +#line 300 "src/grammar/parser.gr" +{ } +#line 971 "src/grammar/parser.cc" + +inline ast::nodes::FunctionType* ZaneParser::dup_function_type(ast::nodes::FunctionType* p) +#line 310 "src/grammar/parser.gr" +{return p; } +#line 976 "src/grammar/parser.cc" + +inline void ZaneParser::del_function_type(ast::nodes::FunctionType* p) +#line 311 "src/grammar/parser.gr" +{ } +#line 981 "src/grammar/parser.cc" + +inline ast::nodes::MethodType* ZaneParser::dup_method_type(ast::nodes::MethodType* p) +#line 321 "src/grammar/parser.gr" +{return p; } +#line 986 "src/grammar/parser.cc" + +inline void ZaneParser::del_method_type(ast::nodes::MethodType* p) +#line 322 "src/grammar/parser.gr" +{ } +#line 991 "src/grammar/parser.cc" + +inline ast::nodes::ArrowBody* ZaneParser::dup_arrow_body(ast::nodes::ArrowBody* p) +#line 340 "src/grammar/parser.gr" +{return p; } +#line 996 "src/grammar/parser.cc" + +inline void ZaneParser::del_arrow_body(ast::nodes::ArrowBody* p) +#line 341 "src/grammar/parser.gr" +{ } +#line 1001 "src/grammar/parser.cc" + +inline grammar_support::FunctionBodyValue* ZaneParser::dup_function_body(grammar_support::FunctionBodyValue* p) +#line 348 "src/grammar/parser.gr" +{return p; } +#line 1006 "src/grammar/parser.cc" + +inline void ZaneParser::del_function_body(grammar_support::FunctionBodyValue* p) +#line 349 "src/grammar/parser.gr" +{ } +#line 1011 "src/grammar/parser.cc" + +inline ast::nodes::Scope* ZaneParser::dup_scope(ast::nodes::Scope* p) +#line 359 "src/grammar/parser.gr" +{return p; } +#line 1016 "src/grammar/parser.cc" + +inline void ZaneParser::del_scope(ast::nodes::Scope* p) +#line 360 "src/grammar/parser.gr" +{ } +#line 1021 "src/grammar/parser.cc" + +inline std::vector>* ZaneParser::dup_statements(std::vector>* p) +#line 367 "src/grammar/parser.gr" +{return p; } +#line 1026 "src/grammar/parser.cc" + +inline void ZaneParser::del_statements(std::vector>* p) +#line 368 "src/grammar/parser.gr" +{ } +#line 1031 "src/grammar/parser.cc" + +inline ast::nodes::Statement* ZaneParser::dup_statement(ast::nodes::Statement* p) +#line 379 "src/grammar/parser.gr" +{return p; } +#line 1036 "src/grammar/parser.cc" + +inline void ZaneParser::del_statement(ast::nodes::Statement* p) +#line 380 "src/grammar/parser.gr" +{ } +#line 1041 "src/grammar/parser.cc" + +inline ast::nodes::FunctionCall* ZaneParser::dup_statement_function_call(ast::nodes::FunctionCall* p) +#line 390 "src/grammar/parser.gr" +{return p; } +#line 1046 "src/grammar/parser.cc" + +inline void ZaneParser::del_statement_function_call(ast::nodes::FunctionCall* p) +#line 391 "src/grammar/parser.gr" +{ } +#line 1051 "src/grammar/parser.cc" + +inline ast::nodes::ValueExpr* ZaneParser::dup_value_expr(ast::nodes::ValueExpr* p) +#line 398 "src/grammar/parser.gr" +{return p; } +#line 1056 "src/grammar/parser.cc" + +inline void ZaneParser::del_value_expr(ast::nodes::ValueExpr* p) +#line 399 "src/grammar/parser.gr" +{ } +#line 1061 "src/grammar/parser.cc" + +inline ast::nodes::ValueExpr* ZaneParser::dup_additive_expr(ast::nodes::ValueExpr* p) +#line 406 "src/grammar/parser.gr" +{return p; } +#line 1066 "src/grammar/parser.cc" + +inline void ZaneParser::del_additive_expr(ast::nodes::ValueExpr* p) +#line 407 "src/grammar/parser.gr" +{ } +#line 1071 "src/grammar/parser.cc" + +inline ast::nodes::ValueExpr* ZaneParser::dup_multiplicative_expr(ast::nodes::ValueExpr* p) +#line 420 "src/grammar/parser.gr" +{return p; } +#line 1076 "src/grammar/parser.cc" + +inline void ZaneParser::del_multiplicative_expr(ast::nodes::ValueExpr* p) +#line 421 "src/grammar/parser.gr" +{ } +#line 1081 "src/grammar/parser.cc" + +inline ast::nodes::ValueExpr* ZaneParser::dup_unary_expr(ast::nodes::ValueExpr* p) +#line 434 "src/grammar/parser.gr" +{return p; } +#line 1086 "src/grammar/parser.cc" + +inline void ZaneParser::del_unary_expr(ast::nodes::ValueExpr* p) +#line 435 "src/grammar/parser.gr" +{ } +#line 1091 "src/grammar/parser.cc" + +inline ast::nodes::ValueExpr* ZaneParser::dup_postfix_expr(ast::nodes::ValueExpr* p) +#line 445 "src/grammar/parser.gr" +{return p; } +#line 1096 "src/grammar/parser.cc" + +inline void ZaneParser::del_postfix_expr(ast::nodes::ValueExpr* p) +#line 446 "src/grammar/parser.gr" +{ } +#line 1101 "src/grammar/parser.cc" + +inline ast::nodes::FunctionCall* ZaneParser::dup_call_expr(ast::nodes::FunctionCall* p) +#line 456 "src/grammar/parser.gr" +{return p; } +#line 1106 "src/grammar/parser.cc" + +inline void ZaneParser::del_call_expr(ast::nodes::FunctionCall* p) +#line 457 "src/grammar/parser.gr" +{ } +#line 1111 "src/grammar/parser.cc" + +inline ast::nodes::ValueExpr* ZaneParser::dup_primary_expr(ast::nodes::ValueExpr* p) +#line 473 "src/grammar/parser.gr" +{return p; } +#line 1116 "src/grammar/parser.cc" + +inline void ZaneParser::del_primary_expr(ast::nodes::ValueExpr* p) +#line 474 "src/grammar/parser.gr" +{ } +#line 1121 "src/grammar/parser.cc" + +inline ast::nodes::ParenthizedValue* ZaneParser::dup_parenthized_value(ast::nodes::ParenthizedValue* p) +#line 509 "src/grammar/parser.gr" +{return p; } +#line 1126 "src/grammar/parser.cc" + +inline void ZaneParser::del_parenthized_value(ast::nodes::ParenthizedValue* p) +#line 510 "src/grammar/parser.gr" +{ } +#line 1131 "src/grammar/parser.cc" + +inline std::vector>* ZaneParser::dup_arguments(std::vector>* p) +#line 517 "src/grammar/parser.gr" +{return p; } +#line 1136 "src/grammar/parser.cc" + +inline void ZaneParser::del_arguments(std::vector>* p) +#line 518 "src/grammar/parser.gr" +{ } +#line 1141 "src/grammar/parser.cc" + +inline std::vector>* ZaneParser::dup_argument_list(std::vector>* p) +#line 528 "src/grammar/parser.gr" +{return p; } +#line 1146 "src/grammar/parser.cc" + +inline void ZaneParser::del_argument_list(std::vector>* p) +#line 529 "src/grammar/parser.gr" +{ } +#line 1151 "src/grammar/parser.cc" + +SemanticValue ZaneParser::duplicateNontermValue(int nontermId, SemanticValue sval) +{ + switch (nontermId) { + case 2: + return (SemanticValue)dup_package((ast::nodes::Package*)sval); + case 3: + return (SemanticValue)dup_global_scope((std::vector*)sval); + case 4: + return (SemanticValue)dup_declaration((ast::nodes::Declaration*)sval); + case 5: + return (SemanticValue)dup_variable_decl((ast::nodes::VariableDecl*)sval); + case 6: + return (SemanticValue)dup_function_decl((ast::nodes::FunctionDecl*)sval); + case 7: + return (SemanticValue)dup_method_decl((ast::nodes::MethodDecl*)sval); + case 8: + return (SemanticValue)dup_parameters((std::vector*)sval); + case 9: + return (SemanticValue)dup_parameter_list((std::vector*)sval); + case 10: + return (SemanticValue)dup_method_parameters((std::vector*)sval); + case 11: + return (SemanticValue)dup_method_parameter_seq((std::vector*)sval); + case 12: + return (SemanticValue)dup_parameter((ast::nodes::Parameter*)sval); + case 13: + return (SemanticValue)dup_type_list((std::vector>*)sval); + case 14: + return (SemanticValue)dup_type_list_ne((std::vector>*)sval); + case 15: + return (SemanticValue)dup_type_expr((ast::nodes::TypeExpression*)sval); + case 16: + return (SemanticValue)dup_name_type((ast::nodes::NameType*)sval); + case 17: + return (SemanticValue)dup_function_type((ast::nodes::FunctionType*)sval); + case 18: + return (SemanticValue)dup_method_type((ast::nodes::MethodType*)sval); + case 19: + return (SemanticValue)dup_arrow_body((ast::nodes::ArrowBody*)sval); + case 20: + return (SemanticValue)dup_function_body((grammar_support::FunctionBodyValue*)sval); + case 21: + return (SemanticValue)dup_scope((ast::nodes::Scope*)sval); + case 22: + return (SemanticValue)dup_statements((std::vector>*)sval); + case 23: + return (SemanticValue)dup_statement((ast::nodes::Statement*)sval); + case 24: + return (SemanticValue)dup_statement_function_call((ast::nodes::FunctionCall*)sval); + case 25: + return (SemanticValue)dup_value_expr((ast::nodes::ValueExpr*)sval); + case 26: + return (SemanticValue)dup_additive_expr((ast::nodes::ValueExpr*)sval); + case 27: + return (SemanticValue)dup_multiplicative_expr((ast::nodes::ValueExpr*)sval); + case 28: + return (SemanticValue)dup_unary_expr((ast::nodes::ValueExpr*)sval); + case 29: + return (SemanticValue)dup_postfix_expr((ast::nodes::ValueExpr*)sval); + case 30: + return (SemanticValue)dup_call_expr((ast::nodes::FunctionCall*)sval); + case 31: + return (SemanticValue)dup_primary_expr((ast::nodes::ValueExpr*)sval); + case 32: + return (SemanticValue)dup_parenthized_value((ast::nodes::ParenthizedValue*)sval); + case 33: + return (SemanticValue)dup_arguments((std::vector>*)sval); + case 34: + return (SemanticValue)dup_argument_list((std::vector>*)sval); + default: + return (SemanticValue)0; + } +} + +void ZaneParser::deallocateNontermValue(int nontermId, SemanticValue sval) +{ + switch (nontermId) { + case 2: + del_package((ast::nodes::Package*)sval); + return; + case 3: + del_global_scope((std::vector*)sval); + return; + case 4: + del_declaration((ast::nodes::Declaration*)sval); + return; + case 5: + del_variable_decl((ast::nodes::VariableDecl*)sval); + return; + case 6: + del_function_decl((ast::nodes::FunctionDecl*)sval); + return; + case 7: + del_method_decl((ast::nodes::MethodDecl*)sval); + return; + case 8: + del_parameters((std::vector*)sval); + return; + case 9: + del_parameter_list((std::vector*)sval); + return; + case 10: + del_method_parameters((std::vector*)sval); + return; + case 11: + del_method_parameter_seq((std::vector*)sval); + return; + case 12: + del_parameter((ast::nodes::Parameter*)sval); + return; + case 13: + del_type_list((std::vector>*)sval); + return; + case 14: + del_type_list_ne((std::vector>*)sval); + return; + case 15: + del_type_expr((ast::nodes::TypeExpression*)sval); + return; + case 16: + del_name_type((ast::nodes::NameType*)sval); + return; + case 17: + del_function_type((ast::nodes::FunctionType*)sval); + return; + case 18: + del_method_type((ast::nodes::MethodType*)sval); + return; + case 19: + del_arrow_body((ast::nodes::ArrowBody*)sval); + return; + case 20: + del_function_body((grammar_support::FunctionBodyValue*)sval); + return; + case 21: + del_scope((ast::nodes::Scope*)sval); + return; + case 22: + del_statements((std::vector>*)sval); + return; + case 23: + del_statement((ast::nodes::Statement*)sval); + return; + case 24: + del_statement_function_call((ast::nodes::FunctionCall*)sval); + return; + case 25: + del_value_expr((ast::nodes::ValueExpr*)sval); + return; + case 26: + del_additive_expr((ast::nodes::ValueExpr*)sval); + return; + case 27: + del_multiplicative_expr((ast::nodes::ValueExpr*)sval); + return; + case 28: + del_unary_expr((ast::nodes::ValueExpr*)sval); + return; + case 29: + del_postfix_expr((ast::nodes::ValueExpr*)sval); + return; + case 30: + del_call_expr((ast::nodes::FunctionCall*)sval); + return; + case 31: + del_primary_expr((ast::nodes::ValueExpr*)sval); + return; + case 32: + del_parenthized_value((ast::nodes::ParenthizedValue*)sval); + return; + case 33: + del_arguments((std::vector>*)sval); + return; + case 34: + del_argument_list((std::vector>*)sval); + return; + default: + std::cout << "WARNING: there is no action to deallocate nonterm " + << nontermNames[nontermId] << std::endl; + } +} + +SemanticValue ZaneParser::mergeAlternativeParses(int nontermId, SemanticValue left, + SemanticValue right, SourceLoc loc) +{ + switch (nontermId) { + default: + std::cout << toString(loc) + << ": error: there is no action to merge nonterm " + << nontermNames[nontermId] << std::endl; + abort(); + } +} + +bool ZaneParser::keepNontermValue(int nontermId, SemanticValue sval) +{ + switch (nontermId) { + default: + return true; + } +} + + +// ---------------- dup/del/classify terminals --------------- +inline std::string* ZaneParser::dup_TOK_STRING(std::string* s) +#line 99 "src/grammar/parser.gr" +{return new std::string(*s); } +#line 1360 "src/grammar/parser.cc" + +inline void ZaneParser::del_TOK_STRING(std::string* s) +#line 100 "src/grammar/parser.gr" +{delete s; } +#line 1365 "src/grammar/parser.cc" + +inline std::string* ZaneParser::dup_TOK_IDENT(std::string* s) +#line 103 "src/grammar/parser.gr" +{return new std::string(*s); } +#line 1370 "src/grammar/parser.cc" + +inline void ZaneParser::del_TOK_IDENT(std::string* s) +#line 104 "src/grammar/parser.gr" +{delete s; } +#line 1375 "src/grammar/parser.cc" + +inline std::string* ZaneParser::dup_TOK_INT(std::string* s) +#line 107 "src/grammar/parser.gr" +{return new std::string(*s); } +#line 1380 "src/grammar/parser.cc" + +inline void ZaneParser::del_TOK_INT(std::string* s) +#line 108 "src/grammar/parser.gr" +{delete s; } +#line 1385 "src/grammar/parser.cc" + +inline std::string* ZaneParser::dup_TOK_FLOAT(std::string* s) +#line 111 "src/grammar/parser.gr" +{return new std::string(*s); } +#line 1390 "src/grammar/parser.cc" + +inline void ZaneParser::del_TOK_FLOAT(std::string* s) +#line 112 "src/grammar/parser.gr" +{delete s; } +#line 1395 "src/grammar/parser.cc" + +SemanticValue ZaneParser::duplicateTerminalValue(int termId, SemanticValue sval) +{ + switch (termId) { + case 0: + return sval; + case 1: + return sval; + case 2: + return sval; + case 3: + return sval; + case 4: + return sval; + case 5: + return sval; + case 6: + return sval; + case 7: + return sval; + case 8: + return sval; + case 9: + return sval; + case 10: + return sval; + case 11: + return sval; + case 12: + return sval; + case 13: + return sval; + case 14: + return (SemanticValue)dup_TOK_STRING((std::string*)sval); + case 15: + return (SemanticValue)dup_TOK_IDENT((std::string*)sval); + case 16: + return (SemanticValue)dup_TOK_INT((std::string*)sval); + case 17: + return (SemanticValue)dup_TOK_FLOAT((std::string*)sval); + case 18: + return sval; + case 19: + return sval; + case 20: + return sval; + case 21: + return sval; + case 22: + return sval; + case 23: + return sval; + default: + return (SemanticValue)0; + } +} + +void ZaneParser::deallocateTerminalValue(int termId, SemanticValue sval) +{ + switch (termId) { + case 0: + break; + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 5: + break; + case 6: + break; + case 7: + break; + case 8: + break; + case 9: + break; + case 10: + break; + case 11: + break; + case 12: + break; + case 13: + break; + case 14: + del_TOK_STRING((std::string*)sval); + return; + case 15: + del_TOK_IDENT((std::string*)sval); + return; + case 16: + del_TOK_INT((std::string*)sval); + return; + case 17: + del_TOK_FLOAT((std::string*)sval); + return; + case 18: + break; + case 19: + break; + case 20: + break; + case 21: + break; + case 22: + break; + case 23: + break; + default: + int arrayMin = 0; + int arrayMax = 24; + xassert(termId >= arrayMin && termId < arrayMax); + std::cout << "WARNING: there is no action to deallocate terminal " + << termNames[termId] << std::endl; + } +} + +/*static*/ int ZaneParser::reclassifyToken(ZaneParser *ths, int oldTokenType, SemanticValue sval) +{ + switch (oldTokenType) { + default: + return oldTokenType; + } +} + +UserActions::ReclassifyFunc ZaneParser::getReclassifier() +{ + return (ReclassifyFunc)&ZaneParser::reclassifyToken; +} + + +// this makes a ParseTables from some literal data; +// the code is written by ParseTables::emitConstructionCode() +// in /build/source/src/elkhound/parsetables.cc +class ZaneParser_ParseTables : public ParseTables { +public: + ZaneParser_ParseTables(); +}; + +ZaneParser_ParseTables::ZaneParser_ParseTables() + : ParseTables(false /*owning*/) +{ + numTerms = 24; + numNonterms = 35; + numStates = 106; + numProds = 63; + actionCols = 24; + actionRows = 106; + gotoCols = 35; + gotoRows = 106; + ambigTableSize = 12; + startState = (StateId)0; + finalProductionIndex = 0; + bigProductionListSize = 0; + errorBitsRowSize = 4; + uniqueErrorRows = 0; + + // storage size: 5088 bytes + // rows: 106 cols: 24 + static ActionEntry const actionTable_static[2544] = { + /* 0*/ -3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, + /* 1*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 2*/ 0, 3, -19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, + /* 3*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, + /* 4*/ 0, 4, -60, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, + /* 5*/ 0, 4, -60, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, + /* 6*/ 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, + /* 7*/ 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 27, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 8*/ 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 9*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 11*/ -51, -51, -51, 0, -51, -51, 0, 0, 0, 0, 0, -51, 0, 0, -51, -51, -51, -51, -51, -51, -51, -51, 0, 0, + /* 12*/ -50, -50, -50, 0, -50, -50, 0, 0, 0, 0, 0, -50, 0, 0, -50, -50, -50, -50, -50, -50, -50, -50, 0, 0, + /* 13*/ -59, -59, -59, 0, -59, -59, 0, 0, 0, 0, 0, -59, 0, 0, -59, -59, -59, -59, -59, -59, -59, -59, 0, 0, + /* 14*/ 0, -34, 0, 0, -34, 0, 0, 0, 0, 0, 0, -34, 0, 0, -34, -34, -34, -34, 0, 0, 0, 0, 0, 0, + /* 15*/ -33, -33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -33, 0, 0, 0, 0, 0, 0, 0, 0, + /* 16*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, + /* 17*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, + /* 18*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, + /* 19*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, + /* 20*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, + /* 21*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, + /* 22*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, + /* 23*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, + /* 24*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, + /* 25*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, + /* 26*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, + /* 27*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, + /* 28*/ 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 29*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 30*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, + /* 31*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, + /* 32*/ -57, -57, -57, 0, -57, -57, 0, 0, 0, 0, 0, -57, 0, 0, -57, -57, -57, -57, -57, -57, -57, -57, 0, 0, + /* 33*/ 0, 107, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, + /* 34*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, + /* 35*/ 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 36*/ 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 37*/ -52, -52, -52, 0, -52, -52, 0, 0, 23, 0, 0, -52, 0, 0, -52, -52, -52, -52, -52, -52, -52, -52, 0, 0, + /* 38*/ 0, 0, -26, 0, 0, -26, 0, -26, 0, 0, 0, 0, 0, 0, 0, -26, 0, 0, 0, 0, 0, 0, 0, 0, + /* 39*/ -54, -54, -54, 0, -54, -54, 0, 0, 0, 0, 0, -54, 0, 0, -54, -54, -54, -54, -54, -54, -54, -54, 0, 0, + /* 40*/ -53, -53, -53, 0, -53, -53, 0, 0, 0, 0, 0, -53, 0, 0, -53, -53, -53, -53, -53, -53, -53, -53, 0, 0, + /* 41*/ -55, -55, -55, 0, -55, -55, 0, 0, 0, 0, 0, -55, 0, 0, -55, -55, -55, -55, -55, -55, -55, -55, 0, 0, + /* 42*/ -56, -56, -56, 0, -56, -56, 0, 0, 0, 0, 0, -56, 0, 0, -56, -56, -56, -56, -56, -56, -56, -56, 0, 0, + /* 43*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, + /* 44*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, + /* 45*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, + /* 46*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, + /* 47*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, + /* 48*/ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 49*/ -2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, + /* 50*/ -4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, + /* 51*/ 0, -37, 0, 0, -37, 0, 0, 0, 0, 0, 0, -37, 0, 0, -37, -37, -37, -37, 0, 0, 0, 0, 0, 0, + /* 52*/ -5, -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, 0, 0, + /* 53*/ -6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, + /* 54*/ 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 55*/ 0, 0, -12, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 56*/ 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 57*/ 0, 0, -15, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 58*/ 0, 0, -14, 0, 0, -14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 59*/ 0, 0, -13, 0, 0, -13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 60*/ 0, 0, -17, 0, 0, -17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 61*/ 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 62*/ 0, 0, 10, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 63*/ 0, 0, -20, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 64*/ 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 65*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, + /* 66*/ 0, 0, -16, 0, 0, -16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 67*/ 0, 0, -18, 0, 0, -18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 68*/ 0, 0, -22, 0, 0, -22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 69*/ 0, 0, -21, 0, 0, -21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 70*/ 0, 0, -27, 0, 0, -27, 0, -27, 0, 0, 0, 0, 0, 0, 0, -27, 0, 0, 0, 0, 0, 0, 0, 0, + /* 71*/ 0, 0, -28, 0, 0, -28, 0, -28, 0, 0, 0, 0, 0, 0, 0, -28, 0, 0, 0, 0, 0, 0, 0, 0, + /* 72*/ 0, 0, -29, 0, 0, -29, 0, -29, 0, 0, 0, 0, 0, 0, 0, -29, 0, 0, 0, 0, 0, 0, 0, 0, + /* 73*/ 0, 0, -23, 0, 0, -23, 0, -23, 0, 0, 0, 0, 0, 0, 0, -23, 0, 0, 0, 0, 0, 0, 0, 0, + /* 74*/ 0, 0, -24, 0, 0, -24, 0, -24, 0, 0, 0, 0, 0, 0, 0, -24, 0, 0, 0, 0, 0, 0, 0, 0, + /* 75*/ 0, 0, -25, 0, 0, -25, 0, -25, 0, 0, 0, 0, 0, 0, 0, -25, 0, 0, 0, 0, 0, 0, 0, 0, + /* 76*/ -31, -31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -31, 0, 0, 0, 0, 0, 0, 0, 0, + /* 77*/ -8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, 0, 0, 0, 0, 0, 0, 0, + /* 78*/ -9, -9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 0, 0, 0, + /* 79*/ -10, -10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, 0, 0, 0, 0, 0, 0, 0, 0, + /* 80*/ -32, -32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -32, 0, 0, 0, 0, 0, 0, 0, 0, + /* 81*/ 0, 4, 0, 0, 16, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 34, 42, 43, 0, 0, 0, 0, 0, 0, + /* 82*/ 0, -35, 0, 0, -35, 0, 0, 0, 0, 0, 0, -35, 0, 0, -35, -35, -35, -35, 0, 0, 0, 0, 0, 0, + /* 83*/ 0, -36, 0, 0, -36, 0, 0, 0, 0, 0, 0, -36, 0, 0, -36, -36, -36, -36, 0, 0, 0, 0, 0, 0, + /* 84*/ 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 85*/ 0, 0, -62, 0, 0, -62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 86*/ 0, 0, -63, 0, 0, -63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* 87*/ 0, -7, 0, 0, -7, 0, 0, 0, 0, 0, 0, -7, 0, 0, -7, -7, -7, -7, 0, 0, 0, 0, 0, 0, + /* 88*/ -30, -30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -30, 0, 0, 0, 0, 0, 0, 0, 0, + /* 89*/ -39, -39, -39, 0, -39, -39, 0, 0, 0, 0, 0, -39, 0, 0, -39, -39, -39, -39, 44, 45, 0, 0, 0, 0, + /* 90*/ -41, -41, -41, 0, -41, -41, 0, 0, 0, 0, 0, -41, 0, 0, -41, -41, -41, -41, -41, -41, 46, 47, 0, 0, + /* 91*/ -42, -42, -42, 0, -42, -42, 0, 0, 0, 0, 0, -42, 0, 0, -42, -42, -42, -42, -42, -42, 46, 47, 0, 0, + /* 92*/ -40, -40, -40, 0, -40, -40, 0, 0, 0, 0, 0, -40, 0, 0, -40, -40, -40, -40, -40, -40, 46, 47, 0, 0, + /* 93*/ -44, -44, -44, 0, -44, -44, 0, 0, 0, 0, 0, -44, 0, 0, -44, -44, -44, -44, -44, -44, -44, -44, 0, 0, + /* 94*/ -45, -45, -45, 0, -45, -45, 0, 0, 0, 0, 0, -45, 0, 0, -45, -45, -45, -45, -45, -45, -45, -45, 0, 0, + /* 95*/ -43, -43, -43, 0, -43, -43, 0, 0, 0, 0, 0, -43, 0, 0, -43, -43, -43, -43, -43, -43, -43, -43, 0, 0, + /* 96*/ -47, -47, -47, 0, -47, -47, 0, 0, 0, 0, 0, -47, 0, 0, -47, -47, -47, -47, -47, -47, -47, -47, 0, 0, + /* 97*/ -46, -46, -46, 0, -46, -46, 0, 0, 0, 0, 0, -46, 0, 0, -46, -46, -46, -46, -46, -46, -46, -46, 0, 0, + /* 98*/ 0, 110, 0, 0, -38, 0, 0, 0, 0, 0, 0, -38, 0, 0, -38, -38, -38, -38, 0, 0, 0, 0, 0, 0, + /* 99*/ -49, 113, -49, 0, -49, -49, 0, 0, 0, 0, 0, -49, 0, 0, -49, -49, -49, -49, -49, -49, -49, -49, 0, 0, + /*100*/ 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /*101*/ -48, 116, -48, 0, -48, -48, 0, 0, 0, 0, 0, -48, 0, 0, -48, -48, -48, -48, -48, -48, -48, -48, 0, 0, + /*102*/ -58, -58, -58, 0, -58, -58, 0, 0, 0, 0, 0, -58, 0, 0, -58, -58, -58, -58, -58, -58, -58, -58, 0, 0, + /*103*/ 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /*104*/ 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /*105*/ 0, 0, -61, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + actionTable = const_cast(actionTable_static); + + // storage size: 7420 bytes + // rows: 106 cols: 35 + static GotoEntry const gotoTable_static[3710] = { + /* 0*/ 65535, 65535, 48, 49, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 1*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 2*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 61, 63, 69, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 3*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 84, 89, 92, 95, 97, 99, 101, 102, 65535, 65535, + /* 4*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 85, 89, 92, 95, 97, 99, 101, 102, 103, 105, + /* 5*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 85, 89, 92, 95, 97, 99, 101, 102, 104, 105, + /* 6*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 54, 55, 56, 57, 59, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 7*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 76, 78, 80, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 8*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 76, 77, 80, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 9*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 10*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 11*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 12*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 13*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 14*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 81, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 15*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 16*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 68, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 17*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 86, 89, 92, 95, 97, 99, 101, 102, 65535, 65535, + /* 18*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 60, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 19*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 58, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 20*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 87, 89, 92, 95, 97, 99, 101, 102, 65535, 65535, + /* 21*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 22*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 23*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 72, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 24*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 71, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 25*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 70, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 26*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 88, 89, 92, 95, 97, 99, 101, 102, 65535, 65535, + /* 27*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 28*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 76, 79, 80, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 29*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 30*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 62, 69, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 31*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 66, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 32*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 33*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 64, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 34*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 67, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 35*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 36*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 37*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 38*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 39*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 40*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 41*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 42*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 43*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 90, 95, 97, 99, 101, 102, 65535, 65535, + /* 44*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 91, 95, 97, 99, 101, 102, 65535, 65535, + /* 45*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 93, 97, 99, 101, 102, 65535, 65535, + /* 46*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 94, 97, 99, 101, 102, 65535, 65535, + /* 47*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 96, 97, 99, 101, 102, 65535, 65535, + /* 48*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 49*/ 65535, 65535, 65535, 65535, 50, 65535, 52, 53, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 50*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 51*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 52*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 53*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 54*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 55*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 56*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 57*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 58*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 59*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 60*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 61*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 62*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 63*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 64*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 65*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 66*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 67*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 68*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 69*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 70*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 71*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 72*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 73*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 74*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 75*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 76*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 77*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 78*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 79*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 80*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 81*/ 65535, 65535, 65535, 65535, 65535, 51, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 82, 83, 65535, 65535, 65535, 65535, 65535, 98, 100, 102, 65535, 65535, + /* 82*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 83*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 84*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 85*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 86*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 87*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 88*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 89*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 90*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 91*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 92*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 93*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 94*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 95*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 96*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 97*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 98*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /* 99*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /*100*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /*101*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /*102*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /*103*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /*104*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /*105*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + }; + gotoTable = const_cast(gotoTable_static); + + // storage size: 252 bytes + static ParseTables::ProdInfo const prodInfo_static[63] = { + /*0*/ {2,1}, {1,2}, {0,3}, {2,3}, {1,4}, {1,4}, {4,5}, {6,6}, {6,7}, {7,7}, {0,8}, {1,8}, {1,9}, {3,9}, {1,10}, {2,11}, + /*1*/ {3,11}, {2,12}, {0,13}, {1,13}, {1,14}, {3,14}, {1,15}, {1,15}, {1,15}, {1,16}, {5,17}, {6,18}, {7,18}, {2,19}, {1,20}, {1,20}, + /*2*/ {3,21}, {0,22}, {2,22}, {1,23}, {1,23}, {1,24}, {1,25}, {1,26}, {3,26}, {3,26}, {1,27}, {3,27}, {3,27}, {1,28}, {2,28}, {1,29}, + /*3*/ {1,29}, {4,30}, {4,30}, {1,31}, {3,31}, {4,31}, {1,31}, {1,31}, {1,31}, {1,31}, {3,32}, {0,33}, {1,33}, {1,34}, {3,34}, + }; + prodInfo = const_cast(prodInfo_static); + + // storage size: 212 bytes + static SymbolId const stateSymbol_static[106] = { + /*0*/ 0, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 5, + /*1*/ 6, 6, 6, 6, 8, 9, 9, 10, 10, 10, 11, 12, 13, 13, 14, 14, + /*2*/ 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 18, 19, 20, 21, 22, 23, + /*3*/ -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -13, -13, -14, -15, -15, + /*4*/ -16, -16, -16, -16, -16, -16, -16, -16, -16, -17, -18, -19, -20, -21, -21, -21, + /*5*/ -22, -23, -24, -25, -26, -26, -26, -26, -26, -27, -28, -28, -28, -29, -29, -29, + /*6*/ -29, -30, -31, -31, -32, -32, -33, -34, -34, -35, + }; + stateSymbol = const_cast(stateSymbol_static); + + static ActionEntry const ambigTable_static[12] = { + /*0*/ 2, 3, -52, 2, 5, -38, 2, 5, -49, 2, 6, -48, + }; + ambigTable = const_cast(ambigTable_static); + + // storage size: 70 bytes + static NtIndex const nontermOrder_static[35] = { + /*0*/ 28, 27, 34, 33, 26, 24, 23, 22, 32, 21, 20, 19, 18, 31, 17, 16, + /*1*/ 15, 14, 13, 11, 12, 10, 30, 25, 9, 7, 6, 5, 4, 3, 2, 1, + /*2*/ 0, 29, 8, + }; + nontermOrder = const_cast(nontermOrder_static); + + ErrorBitsEntry *errorBits_static = NULL; + errorBits = const_cast(errorBits_static); + + errorBitsPointers = NULL; + + TermIndex *actionIndexMap_static = NULL; + actionIndexMap = const_cast(actionIndexMap_static); + + actionRowPointers = NULL; + + NtIndex *gotoIndexMap_static = NULL; + gotoIndexMap = const_cast(gotoIndexMap_static); + + gotoRowPointers = NULL; + + firstWithTerminal = NULL; + firstWithNonterminal = NULL; + bigProductionList = NULL; + productionsForState = NULL; + ambigStateTable = NULL; +} + + +ParseTables *ZaneParser::makeTables() +{ + return new ZaneParser_ParseTables; +} + diff --git a/src/grammar/parser.gr b/src/grammar/parser.gr index 20148fff..741ae2fe 100644 --- a/src/grammar/parser.gr +++ b/src/grammar/parser.gr @@ -6,7 +6,7 @@ verbatim { #include #include - namespace grammar_support { + namespace grammarSupport { struct FunctionBodyValue { std::variant value; @@ -16,24 +16,24 @@ verbatim { }; template - T take_value(T* ptr) { + T takeValue(T* ptr) { T value = std::move(*ptr); delete ptr; return value; } template - std::unique_ptr take_ptr(T* ptr) { + std::unique_ptr takePtr(T* ptr) { return std::unique_ptr(ptr); } - inline std::string take_string(std::string* ptr) { + inline std::string takeString(std::string* ptr) { std::string value = std::move(*ptr); delete ptr; return value; } - inline ast::nodes::ValueExpr* make_binary( + inline ast::nodes::ValueExpr* makeBinary( std::string op, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right @@ -41,25 +41,25 @@ verbatim { return new ast::nodes::ValueExpr( ast::nodes::OperatorCall( std::move(op), - take_ptr(left), - take_ptr(right) + takePtr(left), + takePtr(right) ) ); } - inline ast::nodes::ValueExpr* make_flip(ast::nodes::ValueExpr* value) { - return new ast::nodes::ValueExpr(ast::nodes::OperatorFlipCall(take_ptr(value))); + inline ast::nodes::ValueExpr* makeFlip(ast::nodes::ValueExpr* value) { + return new ast::nodes::ValueExpr(ast::nodes::OperatorFlipCall(takePtr(value))); } - inline ast::nodes::ValueExpr* wrap_call(ast::nodes::FunctionCall* call) { - return new ast::nodes::ValueExpr(take_value(call)); + inline ast::nodes::ValueExpr* wrapCall(ast::nodes::FunctionCall* call) { + return new ast::nodes::ValueExpr(takeValue(call)); } - inline ast::nodes::ValueExpr* wrap_parenthesized(ast::nodes::ParenthizedValue* value) { - return new ast::nodes::ValueExpr(take_value(value)); + inline ast::nodes::ValueExpr* wrapParenthesized(ast::nodes::ParenthizedValue* value) { + return new ast::nodes::ValueExpr(takeValue(value)); } - } // namespace grammar_support + } // namespace grammarSupport } option defaultMergeAborts; @@ -123,7 +123,7 @@ nonterm(ast::nodes::Package*) package { fun dup(p) [return p;] fun del(p) [] -> declarations:global_scope { - return new ast::nodes::Package(grammar_support::take_value(declarations)); + return new ast::nodes::Package(grammarSupport::takeValue(declarations)); } } @@ -134,7 +134,7 @@ nonterm(std::vector*) global_scope { return new std::vector(); } -> declarations:global_scope declaration:declaration { - declarations->push_back(grammar_support::take_value(declaration)); + declarations->push_back(grammarSupport::takeValue(declaration)); return declarations; } } @@ -143,10 +143,10 @@ nonterm(ast::nodes::Declaration*) declaration { fun dup(p) [return p;] fun del(p) [] -> function:function_decl { - return new ast::nodes::Declaration(grammar_support::take_value(function)); + return new ast::nodes::Declaration(grammarSupport::takeValue(function)); } -> method:method_decl { - return new ast::nodes::Declaration(grammar_support::take_value(method)); + return new ast::nodes::Declaration(grammarSupport::takeValue(method)); } } @@ -155,9 +155,9 @@ nonterm(ast::nodes::VariableDecl*) variable_decl { fun del(p) [] -> name:TOK_IDENT type:type_expr "=" value:value_expr { return new ast::nodes::VariableDecl( - grammar_support::take_string(name), - grammar_support::take_value(type), - grammar_support::take_ptr(value) + grammarSupport::takeString(name), + grammarSupport::takeValue(type), + grammarSupport::takePtr(value) ); } } @@ -167,10 +167,10 @@ nonterm(ast::nodes::FunctionDecl*) function_decl { fun del(p) [] -> return_type:type_expr name:TOK_IDENT "(" params:parameters ")" body:function_body { return new ast::nodes::FunctionDecl( - grammar_support::take_string(name), - grammar_support::take_value(params), - grammar_support::take_value(return_type), - grammar_support::take_value(body).value + grammarSupport::takeString(name), + grammarSupport::takeValue(params), + grammarSupport::takeValue(return_type), + grammarSupport::takeValue(body).value ); } } @@ -180,19 +180,19 @@ nonterm(ast::nodes::MethodDecl*) method_decl { fun del(p) [] -> return_type:type_expr name:TOK_IDENT "(" params:method_parameters ")" body:function_body { return new ast::nodes::MethodDecl( - grammar_support::take_string(name), - grammar_support::take_value(params), - grammar_support::take_value(return_type), - grammar_support::take_value(body).value, + grammarSupport::takeString(name), + grammarSupport::takeValue(params), + grammarSupport::takeValue(return_type), + grammarSupport::takeValue(body).value, false ); } -> return_type:type_expr name:TOK_IDENT "(" params:method_parameters ")" "mut" body:function_body { return new ast::nodes::MethodDecl( - grammar_support::take_string(name), - grammar_support::take_value(params), - grammar_support::take_value(return_type), - grammar_support::take_value(body).value, + grammarSupport::takeString(name), + grammarSupport::takeValue(params), + grammarSupport::takeValue(return_type), + grammarSupport::takeValue(body).value, true ); } @@ -214,11 +214,11 @@ nonterm(std::vector*) parameter_list { fun del(p) [] -> parameter:parameter { auto* list = new std::vector(); - list->push_back(grammar_support::take_value(parameter)); + list->push_back(grammarSupport::takeValue(parameter)); return list; } -> list:parameter_list "," parameter:parameter { - list->push_back(grammar_support::take_value(parameter)); + list->push_back(grammarSupport::takeValue(parameter)); return list; } } @@ -236,11 +236,11 @@ nonterm(std::vector*) method_parameter_seq { fun del(p) [] -> "this" type:type_expr { auto* list = new std::vector(); - list->push_back(ast::nodes::Parameter(grammar_support::take_ptr(type), "this")); + list->push_back(ast::nodes::Parameter(grammarSupport::takePtr(type), "this")); return list; } -> list:method_parameter_seq "," parameter:parameter { - list->push_back(grammar_support::take_value(parameter)); + list->push_back(grammarSupport::takeValue(parameter)); return list; } } @@ -250,8 +250,8 @@ nonterm(ast::nodes::Parameter*) parameter { fun del(p) [] -> name:TOK_IDENT type:type_expr { return new ast::nodes::Parameter( - grammar_support::take_ptr(type), - grammar_support::take_string(name) + grammarSupport::takePtr(type), + grammarSupport::takeString(name) ); } } @@ -272,11 +272,11 @@ nonterm(std::vector>*) type_list_ne fun del(p) [] -> expr:type_expr { auto* list = new std::vector>(); - list->push_back(grammar_support::take_ptr(expr)); + list->push_back(grammarSupport::takePtr(expr)); return list; } -> list:type_list_ne "," expr:type_expr { - list->push_back(grammar_support::take_ptr(expr)); + list->push_back(grammarSupport::takePtr(expr)); return list; } } @@ -285,13 +285,13 @@ nonterm(ast::nodes::TypeExpression*) type_expr { fun dup(p) [return p;] fun del(p) [] -> name:name_type { - return new ast::nodes::TypeExpression(grammar_support::take_value(name)); + return new ast::nodes::TypeExpression(grammarSupport::takeValue(name)); } -> function:function_type { - return new ast::nodes::TypeExpression(grammar_support::take_value(function)); + return new ast::nodes::TypeExpression(grammarSupport::takeValue(function)); } -> method:method_type { - return new ast::nodes::TypeExpression(grammar_support::take_value(method)); + return new ast::nodes::TypeExpression(grammarSupport::takeValue(method)); } } @@ -300,7 +300,7 @@ nonterm(ast::nodes::NameType*) name_type { fun del(p) [] -> identifier:TOK_IDENT { return new ast::nodes::NameType( - grammar_support::take_string(identifier), + grammarSupport::takeString(identifier), std::vector>() ); } @@ -311,8 +311,8 @@ nonterm(ast::nodes::FunctionType*) function_type { fun del(p) [] -> "(" params:type_list ")" "->" return_type:type_expr { return new ast::nodes::FunctionType( - grammar_support::take_value(params), - grammar_support::take_ptr(return_type) + grammarSupport::takeValue(params), + grammarSupport::takePtr(return_type) ); } } @@ -322,15 +322,15 @@ nonterm(ast::nodes::MethodType*) method_type { fun del(p) [] -> "(" "this" params:type_list_ne ")" "->" return_type:type_expr { return new ast::nodes::MethodType( - grammar_support::take_value(params), - grammar_support::take_ptr(return_type), + grammarSupport::takeValue(params), + grammarSupport::takePtr(return_type), false ); } -> "(" "this" params:type_list_ne ")" "mut" "->" return_type:type_expr { return new ast::nodes::MethodType( - grammar_support::take_value(params), - grammar_support::take_ptr(return_type), + grammarSupport::takeValue(params), + grammarSupport::takePtr(return_type), true ); } @@ -340,18 +340,18 @@ nonterm(ast::nodes::ArrowBody*) arrow_body { fun dup(p) [return p;] fun del(p) [] -> "=>" value:value_expr { - return new ast::nodes::ArrowBody(grammar_support::take_ptr(value)); + return new ast::nodes::ArrowBody(grammarSupport::takePtr(value)); } } -nonterm(grammar_support::FunctionBodyValue*) function_body { +nonterm(grammarSupport::FunctionBodyValue*) function_body { fun dup(p) [return p;] fun del(p) [] -> body:arrow_body { - return new grammar_support::FunctionBodyValue(grammar_support::take_value(body)); + return new grammarSupport::FunctionBodyValue(grammarSupport::takeValue(body)); } -> body:scope { - return new grammar_support::FunctionBodyValue(grammar_support::take_value(body)); + return new grammarSupport::FunctionBodyValue(grammarSupport::takeValue(body)); } } @@ -359,7 +359,7 @@ nonterm(ast::nodes::Scope*) scope { fun dup(p) [return p;] fun del(p) [] -> "{" statements:statements "}" { - return new ast::nodes::Scope(grammar_support::take_value(statements)); + return new ast::nodes::Scope(grammarSupport::takeValue(statements)); } } @@ -370,7 +370,7 @@ nonterm(std::vector>*) statements { return new std::vector>(); } -> list:statements statement:statement { - list->push_back(grammar_support::take_ptr(statement)); + list->push_back(grammarSupport::takePtr(statement)); return list; } } @@ -379,10 +379,10 @@ nonterm(ast::nodes::Statement*) statement { fun dup(p) [return p;] fun del(p) [] -> call:statement_function_call { - return new ast::nodes::Statement(grammar_support::take_value(call)); + return new ast::nodes::Statement(grammarSupport::takeValue(call)); } -> declaration:variable_decl { - return new ast::nodes::Statement(grammar_support::take_value(declaration)); + return new ast::nodes::Statement(grammarSupport::takeValue(declaration)); } } @@ -409,10 +409,10 @@ nonterm(ast::nodes::ValueExpr*) additive_expr { return expr; } -> left:additive_expr "+" right:multiplicative_expr { - return grammar_support::make_binary("+", left, right); + return grammarSupport::makeBinary("+", left, right); } -> left:additive_expr "-" right:multiplicative_expr { - return grammar_support::make_binary("-", left, right); + return grammarSupport::makeBinary("-", left, right); } } @@ -423,10 +423,10 @@ nonterm(ast::nodes::ValueExpr*) multiplicative_expr { return expr; } -> left:multiplicative_expr "*" right:unary_expr { - return grammar_support::make_binary("*", left, right); + return grammarSupport::makeBinary("*", left, right); } -> left:multiplicative_expr "/" right:unary_expr { - return grammar_support::make_binary("/", left, right); + return grammarSupport::makeBinary("/", left, right); } } @@ -437,7 +437,7 @@ nonterm(ast::nodes::ValueExpr*) unary_expr { return expr; } -> "~" expr:unary_expr precedence("~") { - return grammar_support::make_flip(expr); + return grammarSupport::makeFlip(expr); } } @@ -448,7 +448,7 @@ nonterm(ast::nodes::ValueExpr*) postfix_expr { return expr; } -> call:call_expr { - return grammar_support::wrap_call(call); + return grammarSupport::wrapCall(call); } } @@ -457,14 +457,14 @@ nonterm(ast::nodes::FunctionCall*) call_expr { fun del(p) [] -> callee:primary_expr "(" args:arguments ")" { return new ast::nodes::FunctionCall( - grammar_support::take_ptr(callee), - grammar_support::take_value(args) + grammarSupport::takePtr(callee), + grammarSupport::takeValue(args) ); } -> callee:call_expr "(" args:arguments ")" { return new ast::nodes::FunctionCall( - std::make_unique(grammar_support::take_value(callee)), - grammar_support::take_value(args) + std::make_unique(grammarSupport::takeValue(callee)), + grammarSupport::takeValue(args) ); } } @@ -473,35 +473,35 @@ nonterm(ast::nodes::ValueExpr*) primary_expr { fun dup(p) [return p;] fun del(p) [] -> identifier:TOK_IDENT { - return new ast::nodes::ValueExpr(ast::nodes::ValueSymbol(grammar_support::take_string(identifier))); + return new ast::nodes::ValueExpr(ast::nodes::ValueSymbol(grammarSupport::takeString(identifier))); } -> package:TOK_IDENT "$" identifier:TOK_IDENT { return new ast::nodes::ValueExpr( ast::nodes::PackageValueSymbol( - grammar_support::take_string(identifier), - grammar_support::take_string(package) + grammarSupport::takeString(identifier), + grammarSupport::takeString(package) ) ); } -> "@" package:TOK_IDENT "$" identifier:TOK_IDENT { return new ast::nodes::ValueExpr( ast::nodes::IntrinsicValueSymbol( - grammar_support::take_string(identifier), - grammar_support::take_string(package) + grammarSupport::takeString(identifier), + grammarSupport::takeString(package) ) ); } -> integer:TOK_INT { - return new ast::nodes::ValueExpr(ast::nodes::IntLiteral(grammar_support::take_string(integer))); + return new ast::nodes::ValueExpr(ast::nodes::IntLiteral(grammarSupport::takeString(integer))); } -> number:TOK_FLOAT { - return new ast::nodes::ValueExpr(ast::nodes::FloatLiteral(grammar_support::take_string(number))); + return new ast::nodes::ValueExpr(ast::nodes::FloatLiteral(grammarSupport::takeString(number))); } -> text:TOK_STRING { - return new ast::nodes::ValueExpr(ast::nodes::StringLiteral(grammar_support::take_string(text))); + return new ast::nodes::ValueExpr(ast::nodes::StringLiteral(grammarSupport::takeString(text))); } -> value:parenthized_value { - return grammar_support::wrap_parenthesized(value); + return grammarSupport::wrapParenthesized(value); } } @@ -509,7 +509,7 @@ nonterm(ast::nodes::ParenthizedValue*) parenthized_value { fun dup(p) [return p;] fun del(p) [] -> "(" value:value_expr ")" { - return new ast::nodes::ParenthizedValue(grammar_support::take_ptr(value)); + return new ast::nodes::ParenthizedValue(grammarSupport::takePtr(value)); } } @@ -529,11 +529,11 @@ nonterm(std::vector>*) argument_list { fun del(p) [] -> value:value_expr { auto* list = new std::vector>(); - list->push_back(grammar_support::take_ptr(value)); + list->push_back(grammarSupport::takePtr(value)); return list; } -> list:argument_list "," value:value_expr { - list->push_back(grammar_support::take_ptr(value)); + list->push_back(grammarSupport::takePtr(value)); return list; } } diff --git a/src/grammar/parser.h b/src/grammar/parser.h new file mode 100644 index 00000000..bf75732c --- /dev/null +++ b/src/grammar/parser.h @@ -0,0 +1,245 @@ +// src/grammar/parser.h +// *** DO NOT EDIT BY HAND *** +// automatically generated by elkhound, from src/grammar/parser.gr + +#ifndef SRC_GRAMMAR_PARSER_H +#define SRC_GRAMMAR_PARSER_H + +#include "useract.h" // UserActions + + +#line 1 "src/grammar/parser.gr" + + #include "ast/.hpp" + #include + #include + #include + #include + #include + + namespace grammar_support { + + struct FunctionBodyValue { + std::variant value; + + explicit FunctionBodyValue(std::variant value) + : value(std::move(value)) {} + }; + + template + T take_value(T* ptr) { + T value = std::move(*ptr); + delete ptr; + return value; + } + + template + std::unique_ptr take_ptr(T* ptr) { + return std::unique_ptr(ptr); + } + + inline std::string take_string(std::string* ptr) { + std::string value = std::move(*ptr); + delete ptr; + return value; + } + + inline ast::nodes::ValueExpr* make_binary( + std::string op, + ast::nodes::ValueExpr* left, + ast::nodes::ValueExpr* right + ) { + return new ast::nodes::ValueExpr( + ast::nodes::OperatorCall( + std::move(op), + take_ptr(left), + take_ptr(right) + ) + ); + } + + inline ast::nodes::ValueExpr* make_flip(ast::nodes::ValueExpr* value) { + return new ast::nodes::ValueExpr(ast::nodes::OperatorFlipCall(take_ptr(value))); + } + + inline ast::nodes::ValueExpr* wrap_call(ast::nodes::FunctionCall* call) { + return new ast::nodes::ValueExpr(take_value(call)); + } + + inline ast::nodes::ValueExpr* wrap_parenthesized(ast::nodes::ParenthizedValue* value) { + return new ast::nodes::ValueExpr(take_value(value)); + } + + } // namespace grammar_support + +#line 76 "src/grammar/parser.h" + + +// parser context class +class +#line 67 "src/grammar/parser.gr" + ZaneParser : public UserActions { +public: + // generated parser hooks are added by Elkhound + +#line 86 "src/grammar/parser.h" + + +private: + USER_ACTION_FUNCTIONS // see useract.h + + // declare the actual action function + static SemanticValue doReductionAction( + ZaneParser *ths, + int productionId, SemanticValue const *semanticValues, + SourceLoc loc); + + // declare the classifier function + static int reclassifyToken( + ZaneParser *ths, + int oldTokenType, SemanticValue sval); + + ast::nodes::Package* action0___EarlyStartSymbol(SourceLoc loc, ast::nodes::Package* top); + ast::nodes::Package* action1_package(SourceLoc loc, std::vector* declarations); + std::vector* action2_global_scope(SourceLoc loc); + std::vector* action3_global_scope(SourceLoc loc, std::vector* declarations, ast::nodes::Declaration* declaration); + ast::nodes::Declaration* action4_declaration(SourceLoc loc, ast::nodes::FunctionDecl* function); + ast::nodes::Declaration* action5_declaration(SourceLoc loc, ast::nodes::MethodDecl* method); + ast::nodes::VariableDecl* action6_variable_decl(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type, ast::nodes::ValueExpr* value); + ast::nodes::FunctionDecl* action7_function_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body); + ast::nodes::MethodDecl* action8_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body); + ast::nodes::MethodDecl* action9_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body); + std::vector* action10_parameters(SourceLoc loc); + std::vector* action11_parameters(SourceLoc loc, std::vector* list); + std::vector* action12_parameter_list(SourceLoc loc, ast::nodes::Parameter* parameter); + std::vector* action13_parameter_list(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter); + std::vector* action14_method_parameters(SourceLoc loc, std::vector* list); + std::vector* action15_method_parameter_seq(SourceLoc loc, ast::nodes::TypeExpression* type); + std::vector* action16_method_parameter_seq(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter); + ast::nodes::Parameter* action17_parameter(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type); + std::vector>* action18_type_list(SourceLoc loc); + std::vector>* action19_type_list(SourceLoc loc, std::vector>* list); + std::vector>* action20_type_list_ne(SourceLoc loc, ast::nodes::TypeExpression* expr); + std::vector>* action21_type_list_ne(SourceLoc loc, std::vector>* list, ast::nodes::TypeExpression* expr); + ast::nodes::TypeExpression* action22_type_expr(SourceLoc loc, ast::nodes::NameType* name); + ast::nodes::TypeExpression* action23_type_expr(SourceLoc loc, ast::nodes::FunctionType* function); + ast::nodes::TypeExpression* action24_type_expr(SourceLoc loc, ast::nodes::MethodType* method); + ast::nodes::NameType* action25_name_type(SourceLoc loc, std::string* identifier); + ast::nodes::FunctionType* action26_function_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); + ast::nodes::MethodType* action27_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); + ast::nodes::MethodType* action28_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); + ast::nodes::ArrowBody* action29_arrow_body(SourceLoc loc, ast::nodes::ValueExpr* value); + grammar_support::FunctionBodyValue* action30_function_body(SourceLoc loc, ast::nodes::ArrowBody* body); + grammar_support::FunctionBodyValue* action31_function_body(SourceLoc loc, ast::nodes::Scope* body); + ast::nodes::Scope* action32_scope(SourceLoc loc, std::vector>* statements); + std::vector>* action33_statements(SourceLoc loc); + std::vector>* action34_statements(SourceLoc loc, std::vector>* list, ast::nodes::Statement* statement); + ast::nodes::Statement* action35_statement(SourceLoc loc, ast::nodes::FunctionCall* call); + ast::nodes::Statement* action36_statement(SourceLoc loc, ast::nodes::VariableDecl* declaration); + ast::nodes::FunctionCall* action37_statement_function_call(SourceLoc loc, ast::nodes::FunctionCall* call); + ast::nodes::ValueExpr* action38_value_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); + ast::nodes::ValueExpr* action39_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); + ast::nodes::ValueExpr* action40_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); + ast::nodes::ValueExpr* action41_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); + ast::nodes::ValueExpr* action42_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); + ast::nodes::ValueExpr* action43_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); + ast::nodes::ValueExpr* action44_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); + ast::nodes::ValueExpr* action45_unary_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); + ast::nodes::ValueExpr* action46_unary_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); + ast::nodes::ValueExpr* action47_postfix_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); + ast::nodes::ValueExpr* action48_postfix_expr(SourceLoc loc, ast::nodes::FunctionCall* call); + ast::nodes::FunctionCall* action49_call_expr(SourceLoc loc, ast::nodes::ValueExpr* callee, std::vector>* args); + ast::nodes::FunctionCall* action50_call_expr(SourceLoc loc, ast::nodes::FunctionCall* callee, std::vector>* args); + ast::nodes::ValueExpr* action51_primary_expr(SourceLoc loc, std::string* identifier); + ast::nodes::ValueExpr* action52_primary_expr(SourceLoc loc, std::string* package, std::string* identifier); + ast::nodes::ValueExpr* action53_primary_expr(SourceLoc loc, std::string* package, std::string* identifier); + ast::nodes::ValueExpr* action54_primary_expr(SourceLoc loc, std::string* integer); + ast::nodes::ValueExpr* action55_primary_expr(SourceLoc loc, std::string* number); + ast::nodes::ValueExpr* action56_primary_expr(SourceLoc loc, std::string* text); + ast::nodes::ValueExpr* action57_primary_expr(SourceLoc loc, ast::nodes::ParenthizedValue* value); + ast::nodes::ParenthizedValue* action58_parenthized_value(SourceLoc loc, ast::nodes::ValueExpr* value); + std::vector>* action59_arguments(SourceLoc loc); + std::vector>* action60_arguments(SourceLoc loc, std::vector>* list); + std::vector>* action61_argument_list(SourceLoc loc, ast::nodes::ValueExpr* value); + std::vector>* action62_argument_list(SourceLoc loc, std::vector>* list, ast::nodes::ValueExpr* value); + inline ast::nodes::Package* dup_package(ast::nodes::Package* p) ; + inline void del_package(ast::nodes::Package* p) ; + inline std::vector* dup_global_scope(std::vector* p) ; + inline void del_global_scope(std::vector* p) ; + inline ast::nodes::Declaration* dup_declaration(ast::nodes::Declaration* p) ; + inline void del_declaration(ast::nodes::Declaration* p) ; + inline ast::nodes::VariableDecl* dup_variable_decl(ast::nodes::VariableDecl* p) ; + inline void del_variable_decl(ast::nodes::VariableDecl* p) ; + inline ast::nodes::FunctionDecl* dup_function_decl(ast::nodes::FunctionDecl* p) ; + inline void del_function_decl(ast::nodes::FunctionDecl* p) ; + inline ast::nodes::MethodDecl* dup_method_decl(ast::nodes::MethodDecl* p) ; + inline void del_method_decl(ast::nodes::MethodDecl* p) ; + inline std::vector* dup_parameters(std::vector* p) ; + inline void del_parameters(std::vector* p) ; + inline std::vector* dup_parameter_list(std::vector* p) ; + inline void del_parameter_list(std::vector* p) ; + inline std::vector* dup_method_parameters(std::vector* p) ; + inline void del_method_parameters(std::vector* p) ; + inline std::vector* dup_method_parameter_seq(std::vector* p) ; + inline void del_method_parameter_seq(std::vector* p) ; + inline ast::nodes::Parameter* dup_parameter(ast::nodes::Parameter* p) ; + inline void del_parameter(ast::nodes::Parameter* p) ; + inline std::vector>* dup_type_list(std::vector>* p) ; + inline void del_type_list(std::vector>* p) ; + inline std::vector>* dup_type_list_ne(std::vector>* p) ; + inline void del_type_list_ne(std::vector>* p) ; + inline ast::nodes::TypeExpression* dup_type_expr(ast::nodes::TypeExpression* p) ; + inline void del_type_expr(ast::nodes::TypeExpression* p) ; + inline ast::nodes::NameType* dup_name_type(ast::nodes::NameType* p) ; + inline void del_name_type(ast::nodes::NameType* p) ; + inline ast::nodes::FunctionType* dup_function_type(ast::nodes::FunctionType* p) ; + inline void del_function_type(ast::nodes::FunctionType* p) ; + inline ast::nodes::MethodType* dup_method_type(ast::nodes::MethodType* p) ; + inline void del_method_type(ast::nodes::MethodType* p) ; + inline ast::nodes::ArrowBody* dup_arrow_body(ast::nodes::ArrowBody* p) ; + inline void del_arrow_body(ast::nodes::ArrowBody* p) ; + inline grammar_support::FunctionBodyValue* dup_function_body(grammar_support::FunctionBodyValue* p) ; + inline void del_function_body(grammar_support::FunctionBodyValue* p) ; + inline ast::nodes::Scope* dup_scope(ast::nodes::Scope* p) ; + inline void del_scope(ast::nodes::Scope* p) ; + inline std::vector>* dup_statements(std::vector>* p) ; + inline void del_statements(std::vector>* p) ; + inline ast::nodes::Statement* dup_statement(ast::nodes::Statement* p) ; + inline void del_statement(ast::nodes::Statement* p) ; + inline ast::nodes::FunctionCall* dup_statement_function_call(ast::nodes::FunctionCall* p) ; + inline void del_statement_function_call(ast::nodes::FunctionCall* p) ; + inline ast::nodes::ValueExpr* dup_value_expr(ast::nodes::ValueExpr* p) ; + inline void del_value_expr(ast::nodes::ValueExpr* p) ; + inline ast::nodes::ValueExpr* dup_additive_expr(ast::nodes::ValueExpr* p) ; + inline void del_additive_expr(ast::nodes::ValueExpr* p) ; + inline ast::nodes::ValueExpr* dup_multiplicative_expr(ast::nodes::ValueExpr* p) ; + inline void del_multiplicative_expr(ast::nodes::ValueExpr* p) ; + inline ast::nodes::ValueExpr* dup_unary_expr(ast::nodes::ValueExpr* p) ; + inline void del_unary_expr(ast::nodes::ValueExpr* p) ; + inline ast::nodes::ValueExpr* dup_postfix_expr(ast::nodes::ValueExpr* p) ; + inline void del_postfix_expr(ast::nodes::ValueExpr* p) ; + inline ast::nodes::FunctionCall* dup_call_expr(ast::nodes::FunctionCall* p) ; + inline void del_call_expr(ast::nodes::FunctionCall* p) ; + inline ast::nodes::ValueExpr* dup_primary_expr(ast::nodes::ValueExpr* p) ; + inline void del_primary_expr(ast::nodes::ValueExpr* p) ; + inline ast::nodes::ParenthizedValue* dup_parenthized_value(ast::nodes::ParenthizedValue* p) ; + inline void del_parenthized_value(ast::nodes::ParenthizedValue* p) ; + inline std::vector>* dup_arguments(std::vector>* p) ; + inline void del_arguments(std::vector>* p) ; + inline std::vector>* dup_argument_list(std::vector>* p) ; + inline void del_argument_list(std::vector>* p) ; + inline std::string* dup_TOK_STRING(std::string* s) ; + inline void del_TOK_STRING(std::string* s) ; + inline std::string* dup_TOK_IDENT(std::string* s) ; + inline void del_TOK_IDENT(std::string* s) ; + inline std::string* dup_TOK_INT(std::string* s) ; + inline void del_TOK_INT(std::string* s) ; + inline std::string* dup_TOK_FLOAT(std::string* s) ; + inline void del_TOK_FLOAT(std::string* s) ; + +// the function which makes the parse tables +public: + virtual ParseTables *makeTables(); +}; + +#endif // SRC_GRAMMAR_PARSER_H From 822621498c102a48400cbda1146d2cfda57ee6db Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 00:03:35 +0200 Subject: [PATCH 055/154] update --- src/grammar/parser.gr | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/grammar/parser.gr b/src/grammar/parser.gr index 741ae2fe..c16bc8ba 100644 --- a/src/grammar/parser.gr +++ b/src/grammar/parser.gr @@ -8,12 +8,7 @@ verbatim { namespace grammarSupport { - struct FunctionBodyValue { - std::variant value; - - explicit FunctionBodyValue(std::variant value) - : value(std::move(value)) {} - }; + using FunctionBody = std::variant; template T takeValue(T* ptr) { @@ -170,7 +165,7 @@ nonterm(ast::nodes::FunctionDecl*) function_decl { grammarSupport::takeString(name), grammarSupport::takeValue(params), grammarSupport::takeValue(return_type), - grammarSupport::takeValue(body).value + grammarSupport::takeValue(body) ); } } @@ -183,7 +178,7 @@ nonterm(ast::nodes::MethodDecl*) method_decl { grammarSupport::takeString(name), grammarSupport::takeValue(params), grammarSupport::takeValue(return_type), - grammarSupport::takeValue(body).value, + grammarSupport::takeValue(body), false ); } @@ -192,7 +187,7 @@ nonterm(ast::nodes::MethodDecl*) method_decl { grammarSupport::takeString(name), grammarSupport::takeValue(params), grammarSupport::takeValue(return_type), - grammarSupport::takeValue(body).value, + grammarSupport::takeValue(body), true ); } @@ -344,14 +339,14 @@ nonterm(ast::nodes::ArrowBody*) arrow_body { } } -nonterm(grammarSupport::FunctionBodyValue*) function_body { +nonterm(grammarSupport::FunctionBody*) function_body { fun dup(p) [return p;] fun del(p) [] -> body:arrow_body { - return new grammarSupport::FunctionBodyValue(grammarSupport::takeValue(body)); + return new grammarSupport::FunctionBody(grammarSupport::takeValue(body)); } -> body:scope { - return new grammarSupport::FunctionBodyValue(grammarSupport::takeValue(body)); + return new grammarSupport::FunctionBody(grammarSupport::takeValue(body)); } } From 6b82dc3c53e6d37d0a83e1a98063919e8822f711 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 00:06:03 +0200 Subject: [PATCH 056/154] update --- justfile | 4 +- src/grammar/parser.cc | 1841 ----------------------------------------- src/grammar/parser.h | 245 ------ 3 files changed, 2 insertions(+), 2088 deletions(-) delete mode 100644 src/grammar/parser.cc delete mode 100644 src/grammar/parser.h diff --git a/justfile b/justfile index 8cb4dcf1..9d9943c9 100644 --- a/justfile +++ b/justfile @@ -10,11 +10,11 @@ release: test-parser: meson compile -C build - ./build/zane test-parser/main.zn + ./build/zane glr-stats: meson compile -C build - ELKHOUND_DEBUG=1 ./build/zane test-parser/main.zn 2>/dev/null + ELKHOUND_DEBUG=1 ./build/zane 2>/dev/null grammar-conflicts: elkhound -v -tr conflict,prec src/grammar/parser.gr diff --git a/src/grammar/parser.cc b/src/grammar/parser.cc deleted file mode 100644 index 1db4fa0f..00000000 --- a/src/grammar/parser.cc +++ /dev/null @@ -1,1841 +0,0 @@ -// src/grammar/parser.cc -// *** DO NOT EDIT BY HAND *** -// automatically generated by gramanl, from src/grammar/parser.gr - -// GLR source location information is enabled - -#include "parser.h" // ZaneParser -#include "parsetables.h" // ParseTables -#include "srcloc.h" // SourceLoc - -#include // assert -#include // std::cout -#include // abort - -static char const *termNames[] = { - "TOK_EOF", // 0 - "TOK_LPAREN", // 1 - "TOK_RPAREN", // 2 - "TOK_LCURLY", // 3 - "TOK_RCURLY", // 4 - "TOK_COMMA", // 5 - "TOK_COLON", // 6 - "TOK_EQUAL", // 7 - "TOK_DOLLAR", // 8 - "TOK_THIN_ARROW", // 9 - "TOK_THICK_ARROW", // 10 - "TOK_AT", // 11 - "TOK_MUT", // 12 - "TOK_THIS", // 13 - "TOK_STRING", // 14 - "TOK_IDENT", // 15 - "TOK_INT", // 16 - "TOK_FLOAT", // 17 - "TOK_PLUS", // 18 - "TOK_MINUS", // 19 - "TOK_STAR", // 20 - "TOK_SLASH", // 21 - "TOK_TILDE", // 22 - "TOK_ERROR", // 23 -}; - -string ZaneParser::terminalDescription(int termId, SemanticValue sval) -{ - return stringc << termNames[termId] - << "(" << (sval % 100000) << ")"; -} - - -static char const *nontermNames[] = { - "empty", // 0 - "__EarlyStartSymbol", // 1 - "package", // 2 - "global_scope", // 3 - "declaration", // 4 - "variable_decl", // 5 - "function_decl", // 6 - "method_decl", // 7 - "parameters", // 8 - "parameter_list", // 9 - "method_parameters", // 10 - "method_parameter_seq", // 11 - "parameter", // 12 - "type_list", // 13 - "type_list_ne", // 14 - "type_expr", // 15 - "name_type", // 16 - "function_type", // 17 - "method_type", // 18 - "arrow_body", // 19 - "function_body", // 20 - "scope", // 21 - "statements", // 22 - "statement", // 23 - "statement_function_call", // 24 - "value_expr", // 25 - "additive_expr", // 26 - "multiplicative_expr", // 27 - "unary_expr", // 28 - "postfix_expr", // 29 - "call_expr", // 30 - "primary_expr", // 31 - "parenthized_value", // 32 - "arguments", // 33 - "argument_list", // 34 -}; - -string ZaneParser::nonterminalDescription(int nontermId, SemanticValue sval) -{ - return stringc << nontermNames[nontermId] - << "(" << (sval % 100000) << ")"; -} - - -char const *ZaneParser::terminalName(int termId) -{ - return termNames[termId]; -} - -char const *ZaneParser::nonterminalName(int nontermId) -{ - return nontermNames[nontermId]; -} - -// ------------------- actions ------------------ -// [0] __EarlyStartSymbol[ast::nodes::Package*] -> top:package TOK_EOF -inline ast::nodes::Package* ZaneParser::action0___EarlyStartSymbol(SourceLoc loc, ast::nodes::Package* top) -#line 1 "" -{ return top; } -#line 110 "src/grammar/parser.cc" - -// [1] package[ast::nodes::Package*] -> declarations:global_scope -inline ast::nodes::Package* ZaneParser::action1_package(SourceLoc loc, std::vector* declarations) -#line 125 "src/grammar/parser.gr" -{ - return new ast::nodes::Package(grammar_support::take_value(declarations)); - } -#line 118 "src/grammar/parser.cc" - -// [2] global_scope[std::vector*] -> empty -inline std::vector* ZaneParser::action2_global_scope(SourceLoc loc) -#line 133 "src/grammar/parser.gr" -{ - return new std::vector(); - } -#line 126 "src/grammar/parser.cc" - -// [3] global_scope[std::vector*] -> declarations:global_scope declaration:declaration -inline std::vector* ZaneParser::action3_global_scope(SourceLoc loc, std::vector* declarations, ast::nodes::Declaration* declaration) -#line 136 "src/grammar/parser.gr" -{ - declarations->push_back(grammar_support::take_value(declaration)); - return declarations; - } -#line 135 "src/grammar/parser.cc" - -// [4] declaration[ast::nodes::Declaration*] -> function:function_decl -inline ast::nodes::Declaration* ZaneParser::action4_declaration(SourceLoc loc, ast::nodes::FunctionDecl* function) -#line 145 "src/grammar/parser.gr" -{ - return new ast::nodes::Declaration(grammar_support::take_value(function)); - } -#line 143 "src/grammar/parser.cc" - -// [5] declaration[ast::nodes::Declaration*] -> method:method_decl -inline ast::nodes::Declaration* ZaneParser::action5_declaration(SourceLoc loc, ast::nodes::MethodDecl* method) -#line 148 "src/grammar/parser.gr" -{ - return new ast::nodes::Declaration(grammar_support::take_value(method)); - } -#line 151 "src/grammar/parser.cc" - -// [6] variable_decl[ast::nodes::VariableDecl*] -> name:TOK_IDENT type:type_expr = value:value_expr -inline ast::nodes::VariableDecl* ZaneParser::action6_variable_decl(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type, ast::nodes::ValueExpr* value) -#line 156 "src/grammar/parser.gr" -{ - return new ast::nodes::VariableDecl( - grammar_support::take_string(name), - grammar_support::take_value(type), - grammar_support::take_ptr(value) - ); - } -#line 163 "src/grammar/parser.cc" - -// [7] function_decl[ast::nodes::FunctionDecl*] -> return_type:type_expr name:TOK_IDENT ( params:parameters ) body:function_body -inline ast::nodes::FunctionDecl* ZaneParser::action7_function_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body) -#line 168 "src/grammar/parser.gr" -{ - return new ast::nodes::FunctionDecl( - grammar_support::take_string(name), - grammar_support::take_value(params), - grammar_support::take_value(return_type), - grammar_support::take_value(body).value - ); - } -#line 176 "src/grammar/parser.cc" - -// [8] method_decl[ast::nodes::MethodDecl*] -> return_type:type_expr name:TOK_IDENT ( params:method_parameters ) body:function_body -inline ast::nodes::MethodDecl* ZaneParser::action8_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body) -#line 181 "src/grammar/parser.gr" -{ - return new ast::nodes::MethodDecl( - grammar_support::take_string(name), - grammar_support::take_value(params), - grammar_support::take_value(return_type), - grammar_support::take_value(body).value, - false - ); - } -#line 190 "src/grammar/parser.cc" - -// [9] method_decl[ast::nodes::MethodDecl*] -> return_type:type_expr name:TOK_IDENT ( params:method_parameters ) mut body:function_body -inline ast::nodes::MethodDecl* ZaneParser::action9_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body) -#line 190 "src/grammar/parser.gr" -{ - return new ast::nodes::MethodDecl( - grammar_support::take_string(name), - grammar_support::take_value(params), - grammar_support::take_value(return_type), - grammar_support::take_value(body).value, - true - ); - } -#line 204 "src/grammar/parser.cc" - -// [10] parameters[std::vector*] -> empty -inline std::vector* ZaneParser::action10_parameters(SourceLoc loc) -#line 204 "src/grammar/parser.gr" -{ - return new std::vector(); - } -#line 212 "src/grammar/parser.cc" - -// [11] parameters[std::vector*] -> list:parameter_list -inline std::vector* ZaneParser::action11_parameters(SourceLoc loc, std::vector* list) -#line 207 "src/grammar/parser.gr" -{ - return list; - } -#line 220 "src/grammar/parser.cc" - -// [12] parameter_list[std::vector*] -> parameter:parameter -inline std::vector* ZaneParser::action12_parameter_list(SourceLoc loc, ast::nodes::Parameter* parameter) -#line 215 "src/grammar/parser.gr" -{ - auto* list = new std::vector(); - list->push_back(grammar_support::take_value(parameter)); - return list; - } -#line 230 "src/grammar/parser.cc" - -// [13] parameter_list[std::vector*] -> list:parameter_list , parameter:parameter -inline std::vector* ZaneParser::action13_parameter_list(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter) -#line 220 "src/grammar/parser.gr" -{ - list->push_back(grammar_support::take_value(parameter)); - return list; - } -#line 239 "src/grammar/parser.cc" - -// [14] method_parameters[std::vector*] -> list:method_parameter_seq -inline std::vector* ZaneParser::action14_method_parameters(SourceLoc loc, std::vector* list) -#line 229 "src/grammar/parser.gr" -{ - return list; - } -#line 247 "src/grammar/parser.cc" - -// [15] method_parameter_seq[std::vector*] -> this type:type_expr -inline std::vector* ZaneParser::action15_method_parameter_seq(SourceLoc loc, ast::nodes::TypeExpression* type) -#line 237 "src/grammar/parser.gr" -{ - auto* list = new std::vector(); - list->push_back(ast::nodes::Parameter(grammar_support::take_ptr(type), "this")); - return list; - } -#line 257 "src/grammar/parser.cc" - -// [16] method_parameter_seq[std::vector*] -> list:method_parameter_seq , parameter:parameter -inline std::vector* ZaneParser::action16_method_parameter_seq(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter) -#line 242 "src/grammar/parser.gr" -{ - list->push_back(grammar_support::take_value(parameter)); - return list; - } -#line 266 "src/grammar/parser.cc" - -// [17] parameter[ast::nodes::Parameter*] -> name:TOK_IDENT type:type_expr -inline ast::nodes::Parameter* ZaneParser::action17_parameter(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type) -#line 251 "src/grammar/parser.gr" -{ - return new ast::nodes::Parameter( - grammar_support::take_ptr(type), - grammar_support::take_string(name) - ); - } -#line 277 "src/grammar/parser.cc" - -// [18] type_list[std::vector>*] -> empty -inline std::vector>* ZaneParser::action18_type_list(SourceLoc loc) -#line 262 "src/grammar/parser.gr" -{ - return new std::vector>(); - } -#line 285 "src/grammar/parser.cc" - -// [19] type_list[std::vector>*] -> list:type_list_ne -inline std::vector>* ZaneParser::action19_type_list(SourceLoc loc, std::vector>* list) -#line 265 "src/grammar/parser.gr" -{ - return list; - } -#line 293 "src/grammar/parser.cc" - -// [20] type_list_ne[std::vector>*] -> expr:type_expr -inline std::vector>* ZaneParser::action20_type_list_ne(SourceLoc loc, ast::nodes::TypeExpression* expr) -#line 273 "src/grammar/parser.gr" -{ - auto* list = new std::vector>(); - list->push_back(grammar_support::take_ptr(expr)); - return list; - } -#line 303 "src/grammar/parser.cc" - -// [21] type_list_ne[std::vector>*] -> list:type_list_ne , expr:type_expr -inline std::vector>* ZaneParser::action21_type_list_ne(SourceLoc loc, std::vector>* list, ast::nodes::TypeExpression* expr) -#line 278 "src/grammar/parser.gr" -{ - list->push_back(grammar_support::take_ptr(expr)); - return list; - } -#line 312 "src/grammar/parser.cc" - -// [22] type_expr[ast::nodes::TypeExpression*] -> name:name_type -inline ast::nodes::TypeExpression* ZaneParser::action22_type_expr(SourceLoc loc, ast::nodes::NameType* name) -#line 287 "src/grammar/parser.gr" -{ - return new ast::nodes::TypeExpression(grammar_support::take_value(name)); - } -#line 320 "src/grammar/parser.cc" - -// [23] type_expr[ast::nodes::TypeExpression*] -> function:function_type -inline ast::nodes::TypeExpression* ZaneParser::action23_type_expr(SourceLoc loc, ast::nodes::FunctionType* function) -#line 290 "src/grammar/parser.gr" -{ - return new ast::nodes::TypeExpression(grammar_support::take_value(function)); - } -#line 328 "src/grammar/parser.cc" - -// [24] type_expr[ast::nodes::TypeExpression*] -> method:method_type -inline ast::nodes::TypeExpression* ZaneParser::action24_type_expr(SourceLoc loc, ast::nodes::MethodType* method) -#line 293 "src/grammar/parser.gr" -{ - return new ast::nodes::TypeExpression(grammar_support::take_value(method)); - } -#line 336 "src/grammar/parser.cc" - -// [25] name_type[ast::nodes::NameType*] -> identifier:TOK_IDENT -inline ast::nodes::NameType* ZaneParser::action25_name_type(SourceLoc loc, std::string* identifier) -#line 301 "src/grammar/parser.gr" -{ - return new ast::nodes::NameType( - grammar_support::take_string(identifier), - std::vector>() - ); - } -#line 347 "src/grammar/parser.cc" - -// [26] function_type[ast::nodes::FunctionType*] -> ( params:type_list ) -> return_type:type_expr -inline ast::nodes::FunctionType* ZaneParser::action26_function_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) -#line 312 "src/grammar/parser.gr" -{ - return new ast::nodes::FunctionType( - grammar_support::take_value(params), - grammar_support::take_ptr(return_type) - ); - } -#line 358 "src/grammar/parser.cc" - -// [27] method_type[ast::nodes::MethodType*] -> ( this params:type_list_ne ) -> return_type:type_expr -inline ast::nodes::MethodType* ZaneParser::action27_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) -#line 323 "src/grammar/parser.gr" -{ - return new ast::nodes::MethodType( - grammar_support::take_value(params), - grammar_support::take_ptr(return_type), - false - ); - } -#line 370 "src/grammar/parser.cc" - -// [28] method_type[ast::nodes::MethodType*] -> ( this params:type_list_ne ) mut -> return_type:type_expr -inline ast::nodes::MethodType* ZaneParser::action28_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) -#line 330 "src/grammar/parser.gr" -{ - return new ast::nodes::MethodType( - grammar_support::take_value(params), - grammar_support::take_ptr(return_type), - true - ); - } -#line 382 "src/grammar/parser.cc" - -// [29] arrow_body[ast::nodes::ArrowBody*] -> => value:value_expr -inline ast::nodes::ArrowBody* ZaneParser::action29_arrow_body(SourceLoc loc, ast::nodes::ValueExpr* value) -#line 342 "src/grammar/parser.gr" -{ - return new ast::nodes::ArrowBody(grammar_support::take_ptr(value)); - } -#line 390 "src/grammar/parser.cc" - -// [30] function_body[grammar_support::FunctionBodyValue*] -> body:arrow_body -inline grammar_support::FunctionBodyValue* ZaneParser::action30_function_body(SourceLoc loc, ast::nodes::ArrowBody* body) -#line 350 "src/grammar/parser.gr" -{ - return new grammar_support::FunctionBodyValue(grammar_support::take_value(body)); - } -#line 398 "src/grammar/parser.cc" - -// [31] function_body[grammar_support::FunctionBodyValue*] -> body:scope -inline grammar_support::FunctionBodyValue* ZaneParser::action31_function_body(SourceLoc loc, ast::nodes::Scope* body) -#line 353 "src/grammar/parser.gr" -{ - return new grammar_support::FunctionBodyValue(grammar_support::take_value(body)); - } -#line 406 "src/grammar/parser.cc" - -// [32] scope[ast::nodes::Scope*] -> { statements:statements } -inline ast::nodes::Scope* ZaneParser::action32_scope(SourceLoc loc, std::vector>* statements) -#line 361 "src/grammar/parser.gr" -{ - return new ast::nodes::Scope(grammar_support::take_value(statements)); - } -#line 414 "src/grammar/parser.cc" - -// [33] statements[std::vector>*] -> empty -inline std::vector>* ZaneParser::action33_statements(SourceLoc loc) -#line 369 "src/grammar/parser.gr" -{ - return new std::vector>(); - } -#line 422 "src/grammar/parser.cc" - -// [34] statements[std::vector>*] -> list:statements statement:statement -inline std::vector>* ZaneParser::action34_statements(SourceLoc loc, std::vector>* list, ast::nodes::Statement* statement) -#line 372 "src/grammar/parser.gr" -{ - list->push_back(grammar_support::take_ptr(statement)); - return list; - } -#line 431 "src/grammar/parser.cc" - -// [35] statement[ast::nodes::Statement*] -> call:statement_function_call -inline ast::nodes::Statement* ZaneParser::action35_statement(SourceLoc loc, ast::nodes::FunctionCall* call) -#line 381 "src/grammar/parser.gr" -{ - return new ast::nodes::Statement(grammar_support::take_value(call)); - } -#line 439 "src/grammar/parser.cc" - -// [36] statement[ast::nodes::Statement*] -> declaration:variable_decl -inline ast::nodes::Statement* ZaneParser::action36_statement(SourceLoc loc, ast::nodes::VariableDecl* declaration) -#line 384 "src/grammar/parser.gr" -{ - return new ast::nodes::Statement(grammar_support::take_value(declaration)); - } -#line 447 "src/grammar/parser.cc" - -// [37] statement_function_call[ast::nodes::FunctionCall*] -> call:call_expr -inline ast::nodes::FunctionCall* ZaneParser::action37_statement_function_call(SourceLoc loc, ast::nodes::FunctionCall* call) -#line 392 "src/grammar/parser.gr" -{ - return call; - } -#line 455 "src/grammar/parser.cc" - -// [38] value_expr[ast::nodes::ValueExpr*] -> expr:additive_expr -inline ast::nodes::ValueExpr* ZaneParser::action38_value_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) -#line 400 "src/grammar/parser.gr" -{ - return expr; - } -#line 463 "src/grammar/parser.cc" - -// [39] additive_expr[ast::nodes::ValueExpr*] -> expr:multiplicative_expr -inline ast::nodes::ValueExpr* ZaneParser::action39_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) -#line 408 "src/grammar/parser.gr" -{ - return expr; - } -#line 471 "src/grammar/parser.cc" - -// [40] additive_expr[ast::nodes::ValueExpr*] -> left:additive_expr + right:multiplicative_expr %prec(10) -inline ast::nodes::ValueExpr* ZaneParser::action40_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) -#line 411 "src/grammar/parser.gr" -{ - return grammar_support::make_binary("+", left, right); - } -#line 479 "src/grammar/parser.cc" - -// [41] additive_expr[ast::nodes::ValueExpr*] -> left:additive_expr - right:multiplicative_expr %prec(10) -inline ast::nodes::ValueExpr* ZaneParser::action41_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) -#line 414 "src/grammar/parser.gr" -{ - return grammar_support::make_binary("-", left, right); - } -#line 487 "src/grammar/parser.cc" - -// [42] multiplicative_expr[ast::nodes::ValueExpr*] -> expr:unary_expr -inline ast::nodes::ValueExpr* ZaneParser::action42_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) -#line 422 "src/grammar/parser.gr" -{ - return expr; - } -#line 495 "src/grammar/parser.cc" - -// [43] multiplicative_expr[ast::nodes::ValueExpr*] -> left:multiplicative_expr * right:unary_expr %prec(20) -inline ast::nodes::ValueExpr* ZaneParser::action43_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) -#line 425 "src/grammar/parser.gr" -{ - return grammar_support::make_binary("*", left, right); - } -#line 503 "src/grammar/parser.cc" - -// [44] multiplicative_expr[ast::nodes::ValueExpr*] -> left:multiplicative_expr / right:unary_expr %prec(20) -inline ast::nodes::ValueExpr* ZaneParser::action44_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) -#line 428 "src/grammar/parser.gr" -{ - return grammar_support::make_binary("/", left, right); - } -#line 511 "src/grammar/parser.cc" - -// [45] unary_expr[ast::nodes::ValueExpr*] -> expr:postfix_expr -inline ast::nodes::ValueExpr* ZaneParser::action45_unary_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) -#line 436 "src/grammar/parser.gr" -{ - return expr; - } -#line 519 "src/grammar/parser.cc" - -// [46] unary_expr[ast::nodes::ValueExpr*] -> ~ expr:unary_expr %prec(30) -inline ast::nodes::ValueExpr* ZaneParser::action46_unary_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) -#line 439 "src/grammar/parser.gr" -{ - return grammar_support::make_flip(expr); - } -#line 527 "src/grammar/parser.cc" - -// [47] postfix_expr[ast::nodes::ValueExpr*] -> expr:primary_expr -inline ast::nodes::ValueExpr* ZaneParser::action47_postfix_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) -#line 447 "src/grammar/parser.gr" -{ - return expr; - } -#line 535 "src/grammar/parser.cc" - -// [48] postfix_expr[ast::nodes::ValueExpr*] -> call:call_expr -inline ast::nodes::ValueExpr* ZaneParser::action48_postfix_expr(SourceLoc loc, ast::nodes::FunctionCall* call) -#line 450 "src/grammar/parser.gr" -{ - return grammar_support::wrap_call(call); - } -#line 543 "src/grammar/parser.cc" - -// [49] call_expr[ast::nodes::FunctionCall*] -> callee:primary_expr ( args:arguments ) -inline ast::nodes::FunctionCall* ZaneParser::action49_call_expr(SourceLoc loc, ast::nodes::ValueExpr* callee, std::vector>* args) -#line 458 "src/grammar/parser.gr" -{ - return new ast::nodes::FunctionCall( - grammar_support::take_ptr(callee), - grammar_support::take_value(args) - ); - } -#line 554 "src/grammar/parser.cc" - -// [50] call_expr[ast::nodes::FunctionCall*] -> callee:call_expr ( args:arguments ) -inline ast::nodes::FunctionCall* ZaneParser::action50_call_expr(SourceLoc loc, ast::nodes::FunctionCall* callee, std::vector>* args) -#line 464 "src/grammar/parser.gr" -{ - return new ast::nodes::FunctionCall( - std::make_unique(grammar_support::take_value(callee)), - grammar_support::take_value(args) - ); - } -#line 565 "src/grammar/parser.cc" - -// [51] primary_expr[ast::nodes::ValueExpr*] -> identifier:TOK_IDENT -inline ast::nodes::ValueExpr* ZaneParser::action51_primary_expr(SourceLoc loc, std::string* identifier) -#line 475 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr(ast::nodes::ValueSymbol(grammar_support::take_string(identifier))); - } -#line 573 "src/grammar/parser.cc" - -// [52] primary_expr[ast::nodes::ValueExpr*] -> package:TOK_IDENT $ identifier:TOK_IDENT -inline ast::nodes::ValueExpr* ZaneParser::action52_primary_expr(SourceLoc loc, std::string* package, std::string* identifier) -#line 478 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr( - ast::nodes::PackageValueSymbol( - grammar_support::take_string(identifier), - grammar_support::take_string(package) - ) - ); - } -#line 586 "src/grammar/parser.cc" - -// [53] primary_expr[ast::nodes::ValueExpr*] -> @ package:TOK_IDENT $ identifier:TOK_IDENT -inline ast::nodes::ValueExpr* ZaneParser::action53_primary_expr(SourceLoc loc, std::string* package, std::string* identifier) -#line 486 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr( - ast::nodes::IntrinsicValueSymbol( - grammar_support::take_string(identifier), - grammar_support::take_string(package) - ) - ); - } -#line 599 "src/grammar/parser.cc" - -// [54] primary_expr[ast::nodes::ValueExpr*] -> integer:TOK_INT -inline ast::nodes::ValueExpr* ZaneParser::action54_primary_expr(SourceLoc loc, std::string* integer) -#line 494 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr(ast::nodes::IntLiteral(grammar_support::take_string(integer))); - } -#line 607 "src/grammar/parser.cc" - -// [55] primary_expr[ast::nodes::ValueExpr*] -> number:TOK_FLOAT -inline ast::nodes::ValueExpr* ZaneParser::action55_primary_expr(SourceLoc loc, std::string* number) -#line 497 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr(ast::nodes::FloatLiteral(grammar_support::take_string(number))); - } -#line 615 "src/grammar/parser.cc" - -// [56] primary_expr[ast::nodes::ValueExpr*] -> text:TOK_STRING -inline ast::nodes::ValueExpr* ZaneParser::action56_primary_expr(SourceLoc loc, std::string* text) -#line 500 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr(ast::nodes::StringLiteral(grammar_support::take_string(text))); - } -#line 623 "src/grammar/parser.cc" - -// [57] primary_expr[ast::nodes::ValueExpr*] -> value:parenthized_value -inline ast::nodes::ValueExpr* ZaneParser::action57_primary_expr(SourceLoc loc, ast::nodes::ParenthizedValue* value) -#line 503 "src/grammar/parser.gr" -{ - return grammar_support::wrap_parenthesized(value); - } -#line 631 "src/grammar/parser.cc" - -// [58] parenthized_value[ast::nodes::ParenthizedValue*] -> ( value:value_expr ) -inline ast::nodes::ParenthizedValue* ZaneParser::action58_parenthized_value(SourceLoc loc, ast::nodes::ValueExpr* value) -#line 511 "src/grammar/parser.gr" -{ - return new ast::nodes::ParenthizedValue(grammar_support::take_ptr(value)); - } -#line 639 "src/grammar/parser.cc" - -// [59] arguments[std::vector>*] -> empty -inline std::vector>* ZaneParser::action59_arguments(SourceLoc loc) -#line 519 "src/grammar/parser.gr" -{ - return new std::vector>(); - } -#line 647 "src/grammar/parser.cc" - -// [60] arguments[std::vector>*] -> list:argument_list -inline std::vector>* ZaneParser::action60_arguments(SourceLoc loc, std::vector>* list) -#line 522 "src/grammar/parser.gr" -{ - return list; - } -#line 655 "src/grammar/parser.cc" - -// [61] argument_list[std::vector>*] -> value:value_expr -inline std::vector>* ZaneParser::action61_argument_list(SourceLoc loc, ast::nodes::ValueExpr* value) -#line 530 "src/grammar/parser.gr" -{ - auto* list = new std::vector>(); - list->push_back(grammar_support::take_ptr(value)); - return list; - } -#line 665 "src/grammar/parser.cc" - -// [62] argument_list[std::vector>*] -> list:argument_list , value:value_expr -inline std::vector>* ZaneParser::action62_argument_list(SourceLoc loc, std::vector>* list, ast::nodes::ValueExpr* value) -#line 535 "src/grammar/parser.gr" -{ - list->push_back(grammar_support::take_ptr(value)); - return list; - } -#line 674 "src/grammar/parser.cc" - - -/*static*/ SemanticValue ZaneParser::doReductionAction( - ZaneParser *ths, - int productionId, SemanticValue const *semanticValues, - SourceLoc loc) -{ - switch (productionId) { - case 0: - return (SemanticValue)(ths->action0___EarlyStartSymbol(loc, (ast::nodes::Package*)(semanticValues[0]))); - case 1: - return (SemanticValue)(ths->action1_package(loc, (std::vector*)(semanticValues[0]))); - case 2: - return (SemanticValue)(ths->action2_global_scope(loc)); - case 3: - return (SemanticValue)(ths->action3_global_scope(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Declaration*)(semanticValues[1]))); - case 4: - return (SemanticValue)(ths->action4_declaration(loc, (ast::nodes::FunctionDecl*)(semanticValues[0]))); - case 5: - return (SemanticValue)(ths->action5_declaration(loc, (ast::nodes::MethodDecl*)(semanticValues[0]))); - case 6: - return (SemanticValue)(ths->action6_variable_decl(loc, (std::string*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[1]), (ast::nodes::ValueExpr*)(semanticValues[3]))); - case 7: - return (SemanticValue)(ths->action7_function_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammar_support::FunctionBodyValue*)(semanticValues[5]))); - case 8: - return (SemanticValue)(ths->action8_method_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammar_support::FunctionBodyValue*)(semanticValues[5]))); - case 9: - return (SemanticValue)(ths->action9_method_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammar_support::FunctionBodyValue*)(semanticValues[6]))); - case 10: - return (SemanticValue)(ths->action10_parameters(loc)); - case 11: - return (SemanticValue)(ths->action11_parameters(loc, (std::vector*)(semanticValues[0]))); - case 12: - return (SemanticValue)(ths->action12_parameter_list(loc, (ast::nodes::Parameter*)(semanticValues[0]))); - case 13: - return (SemanticValue)(ths->action13_parameter_list(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Parameter*)(semanticValues[2]))); - case 14: - return (SemanticValue)(ths->action14_method_parameters(loc, (std::vector*)(semanticValues[0]))); - case 15: - return (SemanticValue)(ths->action15_method_parameter_seq(loc, (ast::nodes::TypeExpression*)(semanticValues[1]))); - case 16: - return (SemanticValue)(ths->action16_method_parameter_seq(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Parameter*)(semanticValues[2]))); - case 17: - return (SemanticValue)(ths->action17_parameter(loc, (std::string*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[1]))); - case 18: - return (SemanticValue)(ths->action18_type_list(loc)); - case 19: - return (SemanticValue)(ths->action19_type_list(loc, (std::vector>*)(semanticValues[0]))); - case 20: - return (SemanticValue)(ths->action20_type_list_ne(loc, (ast::nodes::TypeExpression*)(semanticValues[0]))); - case 21: - return (SemanticValue)(ths->action21_type_list_ne(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[2]))); - case 22: - return (SemanticValue)(ths->action22_type_expr(loc, (ast::nodes::NameType*)(semanticValues[0]))); - case 23: - return (SemanticValue)(ths->action23_type_expr(loc, (ast::nodes::FunctionType*)(semanticValues[0]))); - case 24: - return (SemanticValue)(ths->action24_type_expr(loc, (ast::nodes::MethodType*)(semanticValues[0]))); - case 25: - return (SemanticValue)(ths->action25_name_type(loc, (std::string*)(semanticValues[0]))); - case 26: - return (SemanticValue)(ths->action26_function_type(loc, (std::vector>*)(semanticValues[1]), (ast::nodes::TypeExpression*)(semanticValues[4]))); - case 27: - return (SemanticValue)(ths->action27_method_type(loc, (std::vector>*)(semanticValues[2]), (ast::nodes::TypeExpression*)(semanticValues[5]))); - case 28: - return (SemanticValue)(ths->action28_method_type(loc, (std::vector>*)(semanticValues[2]), (ast::nodes::TypeExpression*)(semanticValues[6]))); - case 29: - return (SemanticValue)(ths->action29_arrow_body(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); - case 30: - return (SemanticValue)(ths->action30_function_body(loc, (ast::nodes::ArrowBody*)(semanticValues[0]))); - case 31: - return (SemanticValue)(ths->action31_function_body(loc, (ast::nodes::Scope*)(semanticValues[0]))); - case 32: - return (SemanticValue)(ths->action32_scope(loc, (std::vector>*)(semanticValues[1]))); - case 33: - return (SemanticValue)(ths->action33_statements(loc)); - case 34: - return (SemanticValue)(ths->action34_statements(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::Statement*)(semanticValues[1]))); - case 35: - return (SemanticValue)(ths->action35_statement(loc, (ast::nodes::FunctionCall*)(semanticValues[0]))); - case 36: - return (SemanticValue)(ths->action36_statement(loc, (ast::nodes::VariableDecl*)(semanticValues[0]))); - case 37: - return (SemanticValue)(ths->action37_statement_function_call(loc, (ast::nodes::FunctionCall*)(semanticValues[0]))); - case 38: - return (SemanticValue)(ths->action38_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); - case 39: - return (SemanticValue)(ths->action39_additive_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); - case 40: - return (SemanticValue)(ths->action40_additive_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); - case 41: - return (SemanticValue)(ths->action41_additive_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); - case 42: - return (SemanticValue)(ths->action42_multiplicative_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); - case 43: - return (SemanticValue)(ths->action43_multiplicative_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); - case 44: - return (SemanticValue)(ths->action44_multiplicative_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); - case 45: - return (SemanticValue)(ths->action45_unary_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); - case 46: - return (SemanticValue)(ths->action46_unary_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); - case 47: - return (SemanticValue)(ths->action47_postfix_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); - case 48: - return (SemanticValue)(ths->action48_postfix_expr(loc, (ast::nodes::FunctionCall*)(semanticValues[0]))); - case 49: - return (SemanticValue)(ths->action49_call_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (std::vector>*)(semanticValues[2]))); - case 50: - return (SemanticValue)(ths->action50_call_expr(loc, (ast::nodes::FunctionCall*)(semanticValues[0]), (std::vector>*)(semanticValues[2]))); - case 51: - return (SemanticValue)(ths->action51_primary_expr(loc, (std::string*)(semanticValues[0]))); - case 52: - return (SemanticValue)(ths->action52_primary_expr(loc, (std::string*)(semanticValues[0]), (std::string*)(semanticValues[2]))); - case 53: - return (SemanticValue)(ths->action53_primary_expr(loc, (std::string*)(semanticValues[1]), (std::string*)(semanticValues[3]))); - case 54: - return (SemanticValue)(ths->action54_primary_expr(loc, (std::string*)(semanticValues[0]))); - case 55: - return (SemanticValue)(ths->action55_primary_expr(loc, (std::string*)(semanticValues[0]))); - case 56: - return (SemanticValue)(ths->action56_primary_expr(loc, (std::string*)(semanticValues[0]))); - case 57: - return (SemanticValue)(ths->action57_primary_expr(loc, (ast::nodes::ParenthizedValue*)(semanticValues[0]))); - case 58: - return (SemanticValue)(ths->action58_parenthized_value(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); - case 59: - return (SemanticValue)(ths->action59_arguments(loc)); - case 60: - return (SemanticValue)(ths->action60_arguments(loc, (std::vector>*)(semanticValues[0]))); - case 61: - return (SemanticValue)(ths->action61_argument_list(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); - case 62: - return (SemanticValue)(ths->action62_argument_list(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); - default: - assert(!"invalid production code"); - return (SemanticValue)0; // silence warning - } -} - -UserActions::ReductionActionFunc ZaneParser::getReductionAction() -{ - return (ReductionActionFunc)&ZaneParser::doReductionAction; -} - - -// ---------------- dup/del/merge/keep nonterminals --------------- - -inline ast::nodes::Package* ZaneParser::dup_package(ast::nodes::Package* p) -#line 123 "src/grammar/parser.gr" -{return p; } -#line 826 "src/grammar/parser.cc" - -inline void ZaneParser::del_package(ast::nodes::Package* p) -#line 124 "src/grammar/parser.gr" -{ } -#line 831 "src/grammar/parser.cc" - -inline std::vector* ZaneParser::dup_global_scope(std::vector* p) -#line 131 "src/grammar/parser.gr" -{return p; } -#line 836 "src/grammar/parser.cc" - -inline void ZaneParser::del_global_scope(std::vector* p) -#line 132 "src/grammar/parser.gr" -{ } -#line 841 "src/grammar/parser.cc" - -inline ast::nodes::Declaration* ZaneParser::dup_declaration(ast::nodes::Declaration* p) -#line 143 "src/grammar/parser.gr" -{return p; } -#line 846 "src/grammar/parser.cc" - -inline void ZaneParser::del_declaration(ast::nodes::Declaration* p) -#line 144 "src/grammar/parser.gr" -{ } -#line 851 "src/grammar/parser.cc" - -inline ast::nodes::VariableDecl* ZaneParser::dup_variable_decl(ast::nodes::VariableDecl* p) -#line 154 "src/grammar/parser.gr" -{return p; } -#line 856 "src/grammar/parser.cc" - -inline void ZaneParser::del_variable_decl(ast::nodes::VariableDecl* p) -#line 155 "src/grammar/parser.gr" -{ } -#line 861 "src/grammar/parser.cc" - -inline ast::nodes::FunctionDecl* ZaneParser::dup_function_decl(ast::nodes::FunctionDecl* p) -#line 166 "src/grammar/parser.gr" -{return p; } -#line 866 "src/grammar/parser.cc" - -inline void ZaneParser::del_function_decl(ast::nodes::FunctionDecl* p) -#line 167 "src/grammar/parser.gr" -{ } -#line 871 "src/grammar/parser.cc" - -inline ast::nodes::MethodDecl* ZaneParser::dup_method_decl(ast::nodes::MethodDecl* p) -#line 179 "src/grammar/parser.gr" -{return p; } -#line 876 "src/grammar/parser.cc" - -inline void ZaneParser::del_method_decl(ast::nodes::MethodDecl* p) -#line 180 "src/grammar/parser.gr" -{ } -#line 881 "src/grammar/parser.cc" - -inline std::vector* ZaneParser::dup_parameters(std::vector* p) -#line 202 "src/grammar/parser.gr" -{return p; } -#line 886 "src/grammar/parser.cc" - -inline void ZaneParser::del_parameters(std::vector* p) -#line 203 "src/grammar/parser.gr" -{ } -#line 891 "src/grammar/parser.cc" - -inline std::vector* ZaneParser::dup_parameter_list(std::vector* p) -#line 213 "src/grammar/parser.gr" -{return p; } -#line 896 "src/grammar/parser.cc" - -inline void ZaneParser::del_parameter_list(std::vector* p) -#line 214 "src/grammar/parser.gr" -{ } -#line 901 "src/grammar/parser.cc" - -inline std::vector* ZaneParser::dup_method_parameters(std::vector* p) -#line 227 "src/grammar/parser.gr" -{return p; } -#line 906 "src/grammar/parser.cc" - -inline void ZaneParser::del_method_parameters(std::vector* p) -#line 228 "src/grammar/parser.gr" -{ } -#line 911 "src/grammar/parser.cc" - -inline std::vector* ZaneParser::dup_method_parameter_seq(std::vector* p) -#line 235 "src/grammar/parser.gr" -{return p; } -#line 916 "src/grammar/parser.cc" - -inline void ZaneParser::del_method_parameter_seq(std::vector* p) -#line 236 "src/grammar/parser.gr" -{ } -#line 921 "src/grammar/parser.cc" - -inline ast::nodes::Parameter* ZaneParser::dup_parameter(ast::nodes::Parameter* p) -#line 249 "src/grammar/parser.gr" -{return p; } -#line 926 "src/grammar/parser.cc" - -inline void ZaneParser::del_parameter(ast::nodes::Parameter* p) -#line 250 "src/grammar/parser.gr" -{ } -#line 931 "src/grammar/parser.cc" - -inline std::vector>* ZaneParser::dup_type_list(std::vector>* p) -#line 260 "src/grammar/parser.gr" -{return p; } -#line 936 "src/grammar/parser.cc" - -inline void ZaneParser::del_type_list(std::vector>* p) -#line 261 "src/grammar/parser.gr" -{ } -#line 941 "src/grammar/parser.cc" - -inline std::vector>* ZaneParser::dup_type_list_ne(std::vector>* p) -#line 271 "src/grammar/parser.gr" -{return p; } -#line 946 "src/grammar/parser.cc" - -inline void ZaneParser::del_type_list_ne(std::vector>* p) -#line 272 "src/grammar/parser.gr" -{ } -#line 951 "src/grammar/parser.cc" - -inline ast::nodes::TypeExpression* ZaneParser::dup_type_expr(ast::nodes::TypeExpression* p) -#line 285 "src/grammar/parser.gr" -{return p; } -#line 956 "src/grammar/parser.cc" - -inline void ZaneParser::del_type_expr(ast::nodes::TypeExpression* p) -#line 286 "src/grammar/parser.gr" -{ } -#line 961 "src/grammar/parser.cc" - -inline ast::nodes::NameType* ZaneParser::dup_name_type(ast::nodes::NameType* p) -#line 299 "src/grammar/parser.gr" -{return p; } -#line 966 "src/grammar/parser.cc" - -inline void ZaneParser::del_name_type(ast::nodes::NameType* p) -#line 300 "src/grammar/parser.gr" -{ } -#line 971 "src/grammar/parser.cc" - -inline ast::nodes::FunctionType* ZaneParser::dup_function_type(ast::nodes::FunctionType* p) -#line 310 "src/grammar/parser.gr" -{return p; } -#line 976 "src/grammar/parser.cc" - -inline void ZaneParser::del_function_type(ast::nodes::FunctionType* p) -#line 311 "src/grammar/parser.gr" -{ } -#line 981 "src/grammar/parser.cc" - -inline ast::nodes::MethodType* ZaneParser::dup_method_type(ast::nodes::MethodType* p) -#line 321 "src/grammar/parser.gr" -{return p; } -#line 986 "src/grammar/parser.cc" - -inline void ZaneParser::del_method_type(ast::nodes::MethodType* p) -#line 322 "src/grammar/parser.gr" -{ } -#line 991 "src/grammar/parser.cc" - -inline ast::nodes::ArrowBody* ZaneParser::dup_arrow_body(ast::nodes::ArrowBody* p) -#line 340 "src/grammar/parser.gr" -{return p; } -#line 996 "src/grammar/parser.cc" - -inline void ZaneParser::del_arrow_body(ast::nodes::ArrowBody* p) -#line 341 "src/grammar/parser.gr" -{ } -#line 1001 "src/grammar/parser.cc" - -inline grammar_support::FunctionBodyValue* ZaneParser::dup_function_body(grammar_support::FunctionBodyValue* p) -#line 348 "src/grammar/parser.gr" -{return p; } -#line 1006 "src/grammar/parser.cc" - -inline void ZaneParser::del_function_body(grammar_support::FunctionBodyValue* p) -#line 349 "src/grammar/parser.gr" -{ } -#line 1011 "src/grammar/parser.cc" - -inline ast::nodes::Scope* ZaneParser::dup_scope(ast::nodes::Scope* p) -#line 359 "src/grammar/parser.gr" -{return p; } -#line 1016 "src/grammar/parser.cc" - -inline void ZaneParser::del_scope(ast::nodes::Scope* p) -#line 360 "src/grammar/parser.gr" -{ } -#line 1021 "src/grammar/parser.cc" - -inline std::vector>* ZaneParser::dup_statements(std::vector>* p) -#line 367 "src/grammar/parser.gr" -{return p; } -#line 1026 "src/grammar/parser.cc" - -inline void ZaneParser::del_statements(std::vector>* p) -#line 368 "src/grammar/parser.gr" -{ } -#line 1031 "src/grammar/parser.cc" - -inline ast::nodes::Statement* ZaneParser::dup_statement(ast::nodes::Statement* p) -#line 379 "src/grammar/parser.gr" -{return p; } -#line 1036 "src/grammar/parser.cc" - -inline void ZaneParser::del_statement(ast::nodes::Statement* p) -#line 380 "src/grammar/parser.gr" -{ } -#line 1041 "src/grammar/parser.cc" - -inline ast::nodes::FunctionCall* ZaneParser::dup_statement_function_call(ast::nodes::FunctionCall* p) -#line 390 "src/grammar/parser.gr" -{return p; } -#line 1046 "src/grammar/parser.cc" - -inline void ZaneParser::del_statement_function_call(ast::nodes::FunctionCall* p) -#line 391 "src/grammar/parser.gr" -{ } -#line 1051 "src/grammar/parser.cc" - -inline ast::nodes::ValueExpr* ZaneParser::dup_value_expr(ast::nodes::ValueExpr* p) -#line 398 "src/grammar/parser.gr" -{return p; } -#line 1056 "src/grammar/parser.cc" - -inline void ZaneParser::del_value_expr(ast::nodes::ValueExpr* p) -#line 399 "src/grammar/parser.gr" -{ } -#line 1061 "src/grammar/parser.cc" - -inline ast::nodes::ValueExpr* ZaneParser::dup_additive_expr(ast::nodes::ValueExpr* p) -#line 406 "src/grammar/parser.gr" -{return p; } -#line 1066 "src/grammar/parser.cc" - -inline void ZaneParser::del_additive_expr(ast::nodes::ValueExpr* p) -#line 407 "src/grammar/parser.gr" -{ } -#line 1071 "src/grammar/parser.cc" - -inline ast::nodes::ValueExpr* ZaneParser::dup_multiplicative_expr(ast::nodes::ValueExpr* p) -#line 420 "src/grammar/parser.gr" -{return p; } -#line 1076 "src/grammar/parser.cc" - -inline void ZaneParser::del_multiplicative_expr(ast::nodes::ValueExpr* p) -#line 421 "src/grammar/parser.gr" -{ } -#line 1081 "src/grammar/parser.cc" - -inline ast::nodes::ValueExpr* ZaneParser::dup_unary_expr(ast::nodes::ValueExpr* p) -#line 434 "src/grammar/parser.gr" -{return p; } -#line 1086 "src/grammar/parser.cc" - -inline void ZaneParser::del_unary_expr(ast::nodes::ValueExpr* p) -#line 435 "src/grammar/parser.gr" -{ } -#line 1091 "src/grammar/parser.cc" - -inline ast::nodes::ValueExpr* ZaneParser::dup_postfix_expr(ast::nodes::ValueExpr* p) -#line 445 "src/grammar/parser.gr" -{return p; } -#line 1096 "src/grammar/parser.cc" - -inline void ZaneParser::del_postfix_expr(ast::nodes::ValueExpr* p) -#line 446 "src/grammar/parser.gr" -{ } -#line 1101 "src/grammar/parser.cc" - -inline ast::nodes::FunctionCall* ZaneParser::dup_call_expr(ast::nodes::FunctionCall* p) -#line 456 "src/grammar/parser.gr" -{return p; } -#line 1106 "src/grammar/parser.cc" - -inline void ZaneParser::del_call_expr(ast::nodes::FunctionCall* p) -#line 457 "src/grammar/parser.gr" -{ } -#line 1111 "src/grammar/parser.cc" - -inline ast::nodes::ValueExpr* ZaneParser::dup_primary_expr(ast::nodes::ValueExpr* p) -#line 473 "src/grammar/parser.gr" -{return p; } -#line 1116 "src/grammar/parser.cc" - -inline void ZaneParser::del_primary_expr(ast::nodes::ValueExpr* p) -#line 474 "src/grammar/parser.gr" -{ } -#line 1121 "src/grammar/parser.cc" - -inline ast::nodes::ParenthizedValue* ZaneParser::dup_parenthized_value(ast::nodes::ParenthizedValue* p) -#line 509 "src/grammar/parser.gr" -{return p; } -#line 1126 "src/grammar/parser.cc" - -inline void ZaneParser::del_parenthized_value(ast::nodes::ParenthizedValue* p) -#line 510 "src/grammar/parser.gr" -{ } -#line 1131 "src/grammar/parser.cc" - -inline std::vector>* ZaneParser::dup_arguments(std::vector>* p) -#line 517 "src/grammar/parser.gr" -{return p; } -#line 1136 "src/grammar/parser.cc" - -inline void ZaneParser::del_arguments(std::vector>* p) -#line 518 "src/grammar/parser.gr" -{ } -#line 1141 "src/grammar/parser.cc" - -inline std::vector>* ZaneParser::dup_argument_list(std::vector>* p) -#line 528 "src/grammar/parser.gr" -{return p; } -#line 1146 "src/grammar/parser.cc" - -inline void ZaneParser::del_argument_list(std::vector>* p) -#line 529 "src/grammar/parser.gr" -{ } -#line 1151 "src/grammar/parser.cc" - -SemanticValue ZaneParser::duplicateNontermValue(int nontermId, SemanticValue sval) -{ - switch (nontermId) { - case 2: - return (SemanticValue)dup_package((ast::nodes::Package*)sval); - case 3: - return (SemanticValue)dup_global_scope((std::vector*)sval); - case 4: - return (SemanticValue)dup_declaration((ast::nodes::Declaration*)sval); - case 5: - return (SemanticValue)dup_variable_decl((ast::nodes::VariableDecl*)sval); - case 6: - return (SemanticValue)dup_function_decl((ast::nodes::FunctionDecl*)sval); - case 7: - return (SemanticValue)dup_method_decl((ast::nodes::MethodDecl*)sval); - case 8: - return (SemanticValue)dup_parameters((std::vector*)sval); - case 9: - return (SemanticValue)dup_parameter_list((std::vector*)sval); - case 10: - return (SemanticValue)dup_method_parameters((std::vector*)sval); - case 11: - return (SemanticValue)dup_method_parameter_seq((std::vector*)sval); - case 12: - return (SemanticValue)dup_parameter((ast::nodes::Parameter*)sval); - case 13: - return (SemanticValue)dup_type_list((std::vector>*)sval); - case 14: - return (SemanticValue)dup_type_list_ne((std::vector>*)sval); - case 15: - return (SemanticValue)dup_type_expr((ast::nodes::TypeExpression*)sval); - case 16: - return (SemanticValue)dup_name_type((ast::nodes::NameType*)sval); - case 17: - return (SemanticValue)dup_function_type((ast::nodes::FunctionType*)sval); - case 18: - return (SemanticValue)dup_method_type((ast::nodes::MethodType*)sval); - case 19: - return (SemanticValue)dup_arrow_body((ast::nodes::ArrowBody*)sval); - case 20: - return (SemanticValue)dup_function_body((grammar_support::FunctionBodyValue*)sval); - case 21: - return (SemanticValue)dup_scope((ast::nodes::Scope*)sval); - case 22: - return (SemanticValue)dup_statements((std::vector>*)sval); - case 23: - return (SemanticValue)dup_statement((ast::nodes::Statement*)sval); - case 24: - return (SemanticValue)dup_statement_function_call((ast::nodes::FunctionCall*)sval); - case 25: - return (SemanticValue)dup_value_expr((ast::nodes::ValueExpr*)sval); - case 26: - return (SemanticValue)dup_additive_expr((ast::nodes::ValueExpr*)sval); - case 27: - return (SemanticValue)dup_multiplicative_expr((ast::nodes::ValueExpr*)sval); - case 28: - return (SemanticValue)dup_unary_expr((ast::nodes::ValueExpr*)sval); - case 29: - return (SemanticValue)dup_postfix_expr((ast::nodes::ValueExpr*)sval); - case 30: - return (SemanticValue)dup_call_expr((ast::nodes::FunctionCall*)sval); - case 31: - return (SemanticValue)dup_primary_expr((ast::nodes::ValueExpr*)sval); - case 32: - return (SemanticValue)dup_parenthized_value((ast::nodes::ParenthizedValue*)sval); - case 33: - return (SemanticValue)dup_arguments((std::vector>*)sval); - case 34: - return (SemanticValue)dup_argument_list((std::vector>*)sval); - default: - return (SemanticValue)0; - } -} - -void ZaneParser::deallocateNontermValue(int nontermId, SemanticValue sval) -{ - switch (nontermId) { - case 2: - del_package((ast::nodes::Package*)sval); - return; - case 3: - del_global_scope((std::vector*)sval); - return; - case 4: - del_declaration((ast::nodes::Declaration*)sval); - return; - case 5: - del_variable_decl((ast::nodes::VariableDecl*)sval); - return; - case 6: - del_function_decl((ast::nodes::FunctionDecl*)sval); - return; - case 7: - del_method_decl((ast::nodes::MethodDecl*)sval); - return; - case 8: - del_parameters((std::vector*)sval); - return; - case 9: - del_parameter_list((std::vector*)sval); - return; - case 10: - del_method_parameters((std::vector*)sval); - return; - case 11: - del_method_parameter_seq((std::vector*)sval); - return; - case 12: - del_parameter((ast::nodes::Parameter*)sval); - return; - case 13: - del_type_list((std::vector>*)sval); - return; - case 14: - del_type_list_ne((std::vector>*)sval); - return; - case 15: - del_type_expr((ast::nodes::TypeExpression*)sval); - return; - case 16: - del_name_type((ast::nodes::NameType*)sval); - return; - case 17: - del_function_type((ast::nodes::FunctionType*)sval); - return; - case 18: - del_method_type((ast::nodes::MethodType*)sval); - return; - case 19: - del_arrow_body((ast::nodes::ArrowBody*)sval); - return; - case 20: - del_function_body((grammar_support::FunctionBodyValue*)sval); - return; - case 21: - del_scope((ast::nodes::Scope*)sval); - return; - case 22: - del_statements((std::vector>*)sval); - return; - case 23: - del_statement((ast::nodes::Statement*)sval); - return; - case 24: - del_statement_function_call((ast::nodes::FunctionCall*)sval); - return; - case 25: - del_value_expr((ast::nodes::ValueExpr*)sval); - return; - case 26: - del_additive_expr((ast::nodes::ValueExpr*)sval); - return; - case 27: - del_multiplicative_expr((ast::nodes::ValueExpr*)sval); - return; - case 28: - del_unary_expr((ast::nodes::ValueExpr*)sval); - return; - case 29: - del_postfix_expr((ast::nodes::ValueExpr*)sval); - return; - case 30: - del_call_expr((ast::nodes::FunctionCall*)sval); - return; - case 31: - del_primary_expr((ast::nodes::ValueExpr*)sval); - return; - case 32: - del_parenthized_value((ast::nodes::ParenthizedValue*)sval); - return; - case 33: - del_arguments((std::vector>*)sval); - return; - case 34: - del_argument_list((std::vector>*)sval); - return; - default: - std::cout << "WARNING: there is no action to deallocate nonterm " - << nontermNames[nontermId] << std::endl; - } -} - -SemanticValue ZaneParser::mergeAlternativeParses(int nontermId, SemanticValue left, - SemanticValue right, SourceLoc loc) -{ - switch (nontermId) { - default: - std::cout << toString(loc) - << ": error: there is no action to merge nonterm " - << nontermNames[nontermId] << std::endl; - abort(); - } -} - -bool ZaneParser::keepNontermValue(int nontermId, SemanticValue sval) -{ - switch (nontermId) { - default: - return true; - } -} - - -// ---------------- dup/del/classify terminals --------------- -inline std::string* ZaneParser::dup_TOK_STRING(std::string* s) -#line 99 "src/grammar/parser.gr" -{return new std::string(*s); } -#line 1360 "src/grammar/parser.cc" - -inline void ZaneParser::del_TOK_STRING(std::string* s) -#line 100 "src/grammar/parser.gr" -{delete s; } -#line 1365 "src/grammar/parser.cc" - -inline std::string* ZaneParser::dup_TOK_IDENT(std::string* s) -#line 103 "src/grammar/parser.gr" -{return new std::string(*s); } -#line 1370 "src/grammar/parser.cc" - -inline void ZaneParser::del_TOK_IDENT(std::string* s) -#line 104 "src/grammar/parser.gr" -{delete s; } -#line 1375 "src/grammar/parser.cc" - -inline std::string* ZaneParser::dup_TOK_INT(std::string* s) -#line 107 "src/grammar/parser.gr" -{return new std::string(*s); } -#line 1380 "src/grammar/parser.cc" - -inline void ZaneParser::del_TOK_INT(std::string* s) -#line 108 "src/grammar/parser.gr" -{delete s; } -#line 1385 "src/grammar/parser.cc" - -inline std::string* ZaneParser::dup_TOK_FLOAT(std::string* s) -#line 111 "src/grammar/parser.gr" -{return new std::string(*s); } -#line 1390 "src/grammar/parser.cc" - -inline void ZaneParser::del_TOK_FLOAT(std::string* s) -#line 112 "src/grammar/parser.gr" -{delete s; } -#line 1395 "src/grammar/parser.cc" - -SemanticValue ZaneParser::duplicateTerminalValue(int termId, SemanticValue sval) -{ - switch (termId) { - case 0: - return sval; - case 1: - return sval; - case 2: - return sval; - case 3: - return sval; - case 4: - return sval; - case 5: - return sval; - case 6: - return sval; - case 7: - return sval; - case 8: - return sval; - case 9: - return sval; - case 10: - return sval; - case 11: - return sval; - case 12: - return sval; - case 13: - return sval; - case 14: - return (SemanticValue)dup_TOK_STRING((std::string*)sval); - case 15: - return (SemanticValue)dup_TOK_IDENT((std::string*)sval); - case 16: - return (SemanticValue)dup_TOK_INT((std::string*)sval); - case 17: - return (SemanticValue)dup_TOK_FLOAT((std::string*)sval); - case 18: - return sval; - case 19: - return sval; - case 20: - return sval; - case 21: - return sval; - case 22: - return sval; - case 23: - return sval; - default: - return (SemanticValue)0; - } -} - -void ZaneParser::deallocateTerminalValue(int termId, SemanticValue sval) -{ - switch (termId) { - case 0: - break; - case 1: - break; - case 2: - break; - case 3: - break; - case 4: - break; - case 5: - break; - case 6: - break; - case 7: - break; - case 8: - break; - case 9: - break; - case 10: - break; - case 11: - break; - case 12: - break; - case 13: - break; - case 14: - del_TOK_STRING((std::string*)sval); - return; - case 15: - del_TOK_IDENT((std::string*)sval); - return; - case 16: - del_TOK_INT((std::string*)sval); - return; - case 17: - del_TOK_FLOAT((std::string*)sval); - return; - case 18: - break; - case 19: - break; - case 20: - break; - case 21: - break; - case 22: - break; - case 23: - break; - default: - int arrayMin = 0; - int arrayMax = 24; - xassert(termId >= arrayMin && termId < arrayMax); - std::cout << "WARNING: there is no action to deallocate terminal " - << termNames[termId] << std::endl; - } -} - -/*static*/ int ZaneParser::reclassifyToken(ZaneParser *ths, int oldTokenType, SemanticValue sval) -{ - switch (oldTokenType) { - default: - return oldTokenType; - } -} - -UserActions::ReclassifyFunc ZaneParser::getReclassifier() -{ - return (ReclassifyFunc)&ZaneParser::reclassifyToken; -} - - -// this makes a ParseTables from some literal data; -// the code is written by ParseTables::emitConstructionCode() -// in /build/source/src/elkhound/parsetables.cc -class ZaneParser_ParseTables : public ParseTables { -public: - ZaneParser_ParseTables(); -}; - -ZaneParser_ParseTables::ZaneParser_ParseTables() - : ParseTables(false /*owning*/) -{ - numTerms = 24; - numNonterms = 35; - numStates = 106; - numProds = 63; - actionCols = 24; - actionRows = 106; - gotoCols = 35; - gotoRows = 106; - ambigTableSize = 12; - startState = (StateId)0; - finalProductionIndex = 0; - bigProductionListSize = 0; - errorBitsRowSize = 4; - uniqueErrorRows = 0; - - // storage size: 5088 bytes - // rows: 106 cols: 24 - static ActionEntry const actionTable_static[2544] = { - /* 0*/ -3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, - /* 1*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 2*/ 0, 3, -19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, - /* 3*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, - /* 4*/ 0, 4, -60, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, - /* 5*/ 0, 4, -60, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, - /* 6*/ 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, - /* 7*/ 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 27, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 8*/ 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 9*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 11*/ -51, -51, -51, 0, -51, -51, 0, 0, 0, 0, 0, -51, 0, 0, -51, -51, -51, -51, -51, -51, -51, -51, 0, 0, - /* 12*/ -50, -50, -50, 0, -50, -50, 0, 0, 0, 0, 0, -50, 0, 0, -50, -50, -50, -50, -50, -50, -50, -50, 0, 0, - /* 13*/ -59, -59, -59, 0, -59, -59, 0, 0, 0, 0, 0, -59, 0, 0, -59, -59, -59, -59, -59, -59, -59, -59, 0, 0, - /* 14*/ 0, -34, 0, 0, -34, 0, 0, 0, 0, 0, 0, -34, 0, 0, -34, -34, -34, -34, 0, 0, 0, 0, 0, 0, - /* 15*/ -33, -33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -33, 0, 0, 0, 0, 0, 0, 0, 0, - /* 16*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, - /* 17*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, - /* 18*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, - /* 19*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, - /* 20*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, - /* 21*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, - /* 22*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, - /* 23*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, - /* 24*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, - /* 25*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, - /* 26*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, - /* 27*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, - /* 28*/ 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 29*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 30*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, - /* 31*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, - /* 32*/ -57, -57, -57, 0, -57, -57, 0, 0, 0, 0, 0, -57, 0, 0, -57, -57, -57, -57, -57, -57, -57, -57, 0, 0, - /* 33*/ 0, 107, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, - /* 34*/ 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, - /* 35*/ 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 36*/ 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 37*/ -52, -52, -52, 0, -52, -52, 0, 0, 23, 0, 0, -52, 0, 0, -52, -52, -52, -52, -52, -52, -52, -52, 0, 0, - /* 38*/ 0, 0, -26, 0, 0, -26, 0, -26, 0, 0, 0, 0, 0, 0, 0, -26, 0, 0, 0, 0, 0, 0, 0, 0, - /* 39*/ -54, -54, -54, 0, -54, -54, 0, 0, 0, 0, 0, -54, 0, 0, -54, -54, -54, -54, -54, -54, -54, -54, 0, 0, - /* 40*/ -53, -53, -53, 0, -53, -53, 0, 0, 0, 0, 0, -53, 0, 0, -53, -53, -53, -53, -53, -53, -53, -53, 0, 0, - /* 41*/ -55, -55, -55, 0, -55, -55, 0, 0, 0, 0, 0, -55, 0, 0, -55, -55, -55, -55, -55, -55, -55, -55, 0, 0, - /* 42*/ -56, -56, -56, 0, -56, -56, 0, 0, 0, 0, 0, -56, 0, 0, -56, -56, -56, -56, -56, -56, -56, -56, 0, 0, - /* 43*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, - /* 44*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, - /* 45*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, - /* 46*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, - /* 47*/ 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 38, 42, 43, 0, 0, 0, 0, 48, 0, - /* 48*/ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 49*/ -2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, - /* 50*/ -4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, - /* 51*/ 0, -37, 0, 0, -37, 0, 0, 0, 0, 0, 0, -37, 0, 0, -37, -37, -37, -37, 0, 0, 0, 0, 0, 0, - /* 52*/ -5, -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, 0, 0, - /* 53*/ -6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 0, 0, 0, 0, 0, 0, 0, - /* 54*/ 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 55*/ 0, 0, -12, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 56*/ 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 57*/ 0, 0, -15, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 58*/ 0, 0, -14, 0, 0, -14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 59*/ 0, 0, -13, 0, 0, -13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 60*/ 0, 0, -17, 0, 0, -17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 61*/ 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 62*/ 0, 0, 10, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 63*/ 0, 0, -20, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 64*/ 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 65*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, - /* 66*/ 0, 0, -16, 0, 0, -16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 67*/ 0, 0, -18, 0, 0, -18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 68*/ 0, 0, -22, 0, 0, -22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 69*/ 0, 0, -21, 0, 0, -21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 70*/ 0, 0, -27, 0, 0, -27, 0, -27, 0, 0, 0, 0, 0, 0, 0, -27, 0, 0, 0, 0, 0, 0, 0, 0, - /* 71*/ 0, 0, -28, 0, 0, -28, 0, -28, 0, 0, 0, 0, 0, 0, 0, -28, 0, 0, 0, 0, 0, 0, 0, 0, - /* 72*/ 0, 0, -29, 0, 0, -29, 0, -29, 0, 0, 0, 0, 0, 0, 0, -29, 0, 0, 0, 0, 0, 0, 0, 0, - /* 73*/ 0, 0, -23, 0, 0, -23, 0, -23, 0, 0, 0, 0, 0, 0, 0, -23, 0, 0, 0, 0, 0, 0, 0, 0, - /* 74*/ 0, 0, -24, 0, 0, -24, 0, -24, 0, 0, 0, 0, 0, 0, 0, -24, 0, 0, 0, 0, 0, 0, 0, 0, - /* 75*/ 0, 0, -25, 0, 0, -25, 0, -25, 0, 0, 0, 0, 0, 0, 0, -25, 0, 0, 0, 0, 0, 0, 0, 0, - /* 76*/ -31, -31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -31, 0, 0, 0, 0, 0, 0, 0, 0, - /* 77*/ -8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, 0, 0, 0, 0, 0, 0, 0, - /* 78*/ -9, -9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 0, 0, 0, - /* 79*/ -10, -10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, 0, 0, 0, 0, 0, 0, 0, 0, - /* 80*/ -32, -32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -32, 0, 0, 0, 0, 0, 0, 0, 0, - /* 81*/ 0, 4, 0, 0, 16, 0, 0, 0, 0, 0, 0, 28, 0, 0, 33, 34, 42, 43, 0, 0, 0, 0, 0, 0, - /* 82*/ 0, -35, 0, 0, -35, 0, 0, 0, 0, 0, 0, -35, 0, 0, -35, -35, -35, -35, 0, 0, 0, 0, 0, 0, - /* 83*/ 0, -36, 0, 0, -36, 0, 0, 0, 0, 0, 0, -36, 0, 0, -36, -36, -36, -36, 0, 0, 0, 0, 0, 0, - /* 84*/ 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 85*/ 0, 0, -62, 0, 0, -62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 86*/ 0, 0, -63, 0, 0, -63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* 87*/ 0, -7, 0, 0, -7, 0, 0, 0, 0, 0, 0, -7, 0, 0, -7, -7, -7, -7, 0, 0, 0, 0, 0, 0, - /* 88*/ -30, -30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -30, 0, 0, 0, 0, 0, 0, 0, 0, - /* 89*/ -39, -39, -39, 0, -39, -39, 0, 0, 0, 0, 0, -39, 0, 0, -39, -39, -39, -39, 44, 45, 0, 0, 0, 0, - /* 90*/ -41, -41, -41, 0, -41, -41, 0, 0, 0, 0, 0, -41, 0, 0, -41, -41, -41, -41, -41, -41, 46, 47, 0, 0, - /* 91*/ -42, -42, -42, 0, -42, -42, 0, 0, 0, 0, 0, -42, 0, 0, -42, -42, -42, -42, -42, -42, 46, 47, 0, 0, - /* 92*/ -40, -40, -40, 0, -40, -40, 0, 0, 0, 0, 0, -40, 0, 0, -40, -40, -40, -40, -40, -40, 46, 47, 0, 0, - /* 93*/ -44, -44, -44, 0, -44, -44, 0, 0, 0, 0, 0, -44, 0, 0, -44, -44, -44, -44, -44, -44, -44, -44, 0, 0, - /* 94*/ -45, -45, -45, 0, -45, -45, 0, 0, 0, 0, 0, -45, 0, 0, -45, -45, -45, -45, -45, -45, -45, -45, 0, 0, - /* 95*/ -43, -43, -43, 0, -43, -43, 0, 0, 0, 0, 0, -43, 0, 0, -43, -43, -43, -43, -43, -43, -43, -43, 0, 0, - /* 96*/ -47, -47, -47, 0, -47, -47, 0, 0, 0, 0, 0, -47, 0, 0, -47, -47, -47, -47, -47, -47, -47, -47, 0, 0, - /* 97*/ -46, -46, -46, 0, -46, -46, 0, 0, 0, 0, 0, -46, 0, 0, -46, -46, -46, -46, -46, -46, -46, -46, 0, 0, - /* 98*/ 0, 110, 0, 0, -38, 0, 0, 0, 0, 0, 0, -38, 0, 0, -38, -38, -38, -38, 0, 0, 0, 0, 0, 0, - /* 99*/ -49, 113, -49, 0, -49, -49, 0, 0, 0, 0, 0, -49, 0, 0, -49, -49, -49, -49, -49, -49, -49, -49, 0, 0, - /*100*/ 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /*101*/ -48, 116, -48, 0, -48, -48, 0, 0, 0, 0, 0, -48, 0, 0, -48, -48, -48, -48, -48, -48, -48, -48, 0, 0, - /*102*/ -58, -58, -58, 0, -58, -58, 0, 0, 0, 0, 0, -58, 0, 0, -58, -58, -58, -58, -58, -58, -58, -58, 0, 0, - /*103*/ 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /*104*/ 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /*105*/ 0, 0, -61, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - actionTable = const_cast(actionTable_static); - - // storage size: 7420 bytes - // rows: 106 cols: 35 - static GotoEntry const gotoTable_static[3710] = { - /* 0*/ 65535, 65535, 48, 49, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 1*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 2*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 61, 63, 69, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 3*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 84, 89, 92, 95, 97, 99, 101, 102, 65535, 65535, - /* 4*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 85, 89, 92, 95, 97, 99, 101, 102, 103, 105, - /* 5*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 85, 89, 92, 95, 97, 99, 101, 102, 104, 105, - /* 6*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 54, 55, 56, 57, 59, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 7*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 76, 78, 80, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 8*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 76, 77, 80, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 9*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 10*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 11*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 12*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 13*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 14*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 81, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 15*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 16*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 68, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 17*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 86, 89, 92, 95, 97, 99, 101, 102, 65535, 65535, - /* 18*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 60, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 19*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 58, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 20*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 87, 89, 92, 95, 97, 99, 101, 102, 65535, 65535, - /* 21*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 22*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 23*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 72, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 24*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 71, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 25*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 70, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 26*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 88, 89, 92, 95, 97, 99, 101, 102, 65535, 65535, - /* 27*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 28*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 76, 79, 80, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 29*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 30*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 62, 69, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 31*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 66, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 32*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 33*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 64, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 34*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 67, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 35*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 36*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 37*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 38*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 39*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 40*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 41*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 42*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 43*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 90, 95, 97, 99, 101, 102, 65535, 65535, - /* 44*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 91, 95, 97, 99, 101, 102, 65535, 65535, - /* 45*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 93, 97, 99, 101, 102, 65535, 65535, - /* 46*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 94, 97, 99, 101, 102, 65535, 65535, - /* 47*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 96, 97, 99, 101, 102, 65535, 65535, - /* 48*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 49*/ 65535, 65535, 65535, 65535, 50, 65535, 52, 53, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65, 73, 74, 75, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 50*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 51*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 52*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 53*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 54*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 55*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 56*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 57*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 58*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 59*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 60*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 61*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 62*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 63*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 64*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 65*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 66*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 67*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 68*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 69*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 70*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 71*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 72*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 73*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 74*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 75*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 76*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 77*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 78*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 79*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 80*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 81*/ 65535, 65535, 65535, 65535, 65535, 51, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 82, 83, 65535, 65535, 65535, 65535, 65535, 98, 100, 102, 65535, 65535, - /* 82*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 83*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 84*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 85*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 86*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 87*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 88*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 89*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 90*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 91*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 92*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 93*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 94*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 95*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 96*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 97*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 98*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /* 99*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /*100*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /*101*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /*102*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /*103*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /*104*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /*105*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - }; - gotoTable = const_cast(gotoTable_static); - - // storage size: 252 bytes - static ParseTables::ProdInfo const prodInfo_static[63] = { - /*0*/ {2,1}, {1,2}, {0,3}, {2,3}, {1,4}, {1,4}, {4,5}, {6,6}, {6,7}, {7,7}, {0,8}, {1,8}, {1,9}, {3,9}, {1,10}, {2,11}, - /*1*/ {3,11}, {2,12}, {0,13}, {1,13}, {1,14}, {3,14}, {1,15}, {1,15}, {1,15}, {1,16}, {5,17}, {6,18}, {7,18}, {2,19}, {1,20}, {1,20}, - /*2*/ {3,21}, {0,22}, {2,22}, {1,23}, {1,23}, {1,24}, {1,25}, {1,26}, {3,26}, {3,26}, {1,27}, {3,27}, {3,27}, {1,28}, {2,28}, {1,29}, - /*3*/ {1,29}, {4,30}, {4,30}, {1,31}, {3,31}, {4,31}, {1,31}, {1,31}, {1,31}, {1,31}, {3,32}, {0,33}, {1,33}, {1,34}, {3,34}, - }; - prodInfo = const_cast(prodInfo_static); - - // storage size: 212 bytes - static SymbolId const stateSymbol_static[106] = { - /*0*/ 0, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 5, - /*1*/ 6, 6, 6, 6, 8, 9, 9, 10, 10, 10, 11, 12, 13, 13, 14, 14, - /*2*/ 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 18, 19, 20, 21, 22, 23, - /*3*/ -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -13, -13, -14, -15, -15, - /*4*/ -16, -16, -16, -16, -16, -16, -16, -16, -16, -17, -18, -19, -20, -21, -21, -21, - /*5*/ -22, -23, -24, -25, -26, -26, -26, -26, -26, -27, -28, -28, -28, -29, -29, -29, - /*6*/ -29, -30, -31, -31, -32, -32, -33, -34, -34, -35, - }; - stateSymbol = const_cast(stateSymbol_static); - - static ActionEntry const ambigTable_static[12] = { - /*0*/ 2, 3, -52, 2, 5, -38, 2, 5, -49, 2, 6, -48, - }; - ambigTable = const_cast(ambigTable_static); - - // storage size: 70 bytes - static NtIndex const nontermOrder_static[35] = { - /*0*/ 28, 27, 34, 33, 26, 24, 23, 22, 32, 21, 20, 19, 18, 31, 17, 16, - /*1*/ 15, 14, 13, 11, 12, 10, 30, 25, 9, 7, 6, 5, 4, 3, 2, 1, - /*2*/ 0, 29, 8, - }; - nontermOrder = const_cast(nontermOrder_static); - - ErrorBitsEntry *errorBits_static = NULL; - errorBits = const_cast(errorBits_static); - - errorBitsPointers = NULL; - - TermIndex *actionIndexMap_static = NULL; - actionIndexMap = const_cast(actionIndexMap_static); - - actionRowPointers = NULL; - - NtIndex *gotoIndexMap_static = NULL; - gotoIndexMap = const_cast(gotoIndexMap_static); - - gotoRowPointers = NULL; - - firstWithTerminal = NULL; - firstWithNonterminal = NULL; - bigProductionList = NULL; - productionsForState = NULL; - ambigStateTable = NULL; -} - - -ParseTables *ZaneParser::makeTables() -{ - return new ZaneParser_ParseTables; -} - diff --git a/src/grammar/parser.h b/src/grammar/parser.h deleted file mode 100644 index bf75732c..00000000 --- a/src/grammar/parser.h +++ /dev/null @@ -1,245 +0,0 @@ -// src/grammar/parser.h -// *** DO NOT EDIT BY HAND *** -// automatically generated by elkhound, from src/grammar/parser.gr - -#ifndef SRC_GRAMMAR_PARSER_H -#define SRC_GRAMMAR_PARSER_H - -#include "useract.h" // UserActions - - -#line 1 "src/grammar/parser.gr" - - #include "ast/.hpp" - #include - #include - #include - #include - #include - - namespace grammar_support { - - struct FunctionBodyValue { - std::variant value; - - explicit FunctionBodyValue(std::variant value) - : value(std::move(value)) {} - }; - - template - T take_value(T* ptr) { - T value = std::move(*ptr); - delete ptr; - return value; - } - - template - std::unique_ptr take_ptr(T* ptr) { - return std::unique_ptr(ptr); - } - - inline std::string take_string(std::string* ptr) { - std::string value = std::move(*ptr); - delete ptr; - return value; - } - - inline ast::nodes::ValueExpr* make_binary( - std::string op, - ast::nodes::ValueExpr* left, - ast::nodes::ValueExpr* right - ) { - return new ast::nodes::ValueExpr( - ast::nodes::OperatorCall( - std::move(op), - take_ptr(left), - take_ptr(right) - ) - ); - } - - inline ast::nodes::ValueExpr* make_flip(ast::nodes::ValueExpr* value) { - return new ast::nodes::ValueExpr(ast::nodes::OperatorFlipCall(take_ptr(value))); - } - - inline ast::nodes::ValueExpr* wrap_call(ast::nodes::FunctionCall* call) { - return new ast::nodes::ValueExpr(take_value(call)); - } - - inline ast::nodes::ValueExpr* wrap_parenthesized(ast::nodes::ParenthizedValue* value) { - return new ast::nodes::ValueExpr(take_value(value)); - } - - } // namespace grammar_support - -#line 76 "src/grammar/parser.h" - - -// parser context class -class -#line 67 "src/grammar/parser.gr" - ZaneParser : public UserActions { -public: - // generated parser hooks are added by Elkhound - -#line 86 "src/grammar/parser.h" - - -private: - USER_ACTION_FUNCTIONS // see useract.h - - // declare the actual action function - static SemanticValue doReductionAction( - ZaneParser *ths, - int productionId, SemanticValue const *semanticValues, - SourceLoc loc); - - // declare the classifier function - static int reclassifyToken( - ZaneParser *ths, - int oldTokenType, SemanticValue sval); - - ast::nodes::Package* action0___EarlyStartSymbol(SourceLoc loc, ast::nodes::Package* top); - ast::nodes::Package* action1_package(SourceLoc loc, std::vector* declarations); - std::vector* action2_global_scope(SourceLoc loc); - std::vector* action3_global_scope(SourceLoc loc, std::vector* declarations, ast::nodes::Declaration* declaration); - ast::nodes::Declaration* action4_declaration(SourceLoc loc, ast::nodes::FunctionDecl* function); - ast::nodes::Declaration* action5_declaration(SourceLoc loc, ast::nodes::MethodDecl* method); - ast::nodes::VariableDecl* action6_variable_decl(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type, ast::nodes::ValueExpr* value); - ast::nodes::FunctionDecl* action7_function_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body); - ast::nodes::MethodDecl* action8_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body); - ast::nodes::MethodDecl* action9_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammar_support::FunctionBodyValue* body); - std::vector* action10_parameters(SourceLoc loc); - std::vector* action11_parameters(SourceLoc loc, std::vector* list); - std::vector* action12_parameter_list(SourceLoc loc, ast::nodes::Parameter* parameter); - std::vector* action13_parameter_list(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter); - std::vector* action14_method_parameters(SourceLoc loc, std::vector* list); - std::vector* action15_method_parameter_seq(SourceLoc loc, ast::nodes::TypeExpression* type); - std::vector* action16_method_parameter_seq(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter); - ast::nodes::Parameter* action17_parameter(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type); - std::vector>* action18_type_list(SourceLoc loc); - std::vector>* action19_type_list(SourceLoc loc, std::vector>* list); - std::vector>* action20_type_list_ne(SourceLoc loc, ast::nodes::TypeExpression* expr); - std::vector>* action21_type_list_ne(SourceLoc loc, std::vector>* list, ast::nodes::TypeExpression* expr); - ast::nodes::TypeExpression* action22_type_expr(SourceLoc loc, ast::nodes::NameType* name); - ast::nodes::TypeExpression* action23_type_expr(SourceLoc loc, ast::nodes::FunctionType* function); - ast::nodes::TypeExpression* action24_type_expr(SourceLoc loc, ast::nodes::MethodType* method); - ast::nodes::NameType* action25_name_type(SourceLoc loc, std::string* identifier); - ast::nodes::FunctionType* action26_function_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); - ast::nodes::MethodType* action27_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); - ast::nodes::MethodType* action28_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); - ast::nodes::ArrowBody* action29_arrow_body(SourceLoc loc, ast::nodes::ValueExpr* value); - grammar_support::FunctionBodyValue* action30_function_body(SourceLoc loc, ast::nodes::ArrowBody* body); - grammar_support::FunctionBodyValue* action31_function_body(SourceLoc loc, ast::nodes::Scope* body); - ast::nodes::Scope* action32_scope(SourceLoc loc, std::vector>* statements); - std::vector>* action33_statements(SourceLoc loc); - std::vector>* action34_statements(SourceLoc loc, std::vector>* list, ast::nodes::Statement* statement); - ast::nodes::Statement* action35_statement(SourceLoc loc, ast::nodes::FunctionCall* call); - ast::nodes::Statement* action36_statement(SourceLoc loc, ast::nodes::VariableDecl* declaration); - ast::nodes::FunctionCall* action37_statement_function_call(SourceLoc loc, ast::nodes::FunctionCall* call); - ast::nodes::ValueExpr* action38_value_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); - ast::nodes::ValueExpr* action39_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); - ast::nodes::ValueExpr* action40_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); - ast::nodes::ValueExpr* action41_additive_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); - ast::nodes::ValueExpr* action42_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); - ast::nodes::ValueExpr* action43_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); - ast::nodes::ValueExpr* action44_multiplicative_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); - ast::nodes::ValueExpr* action45_unary_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); - ast::nodes::ValueExpr* action46_unary_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); - ast::nodes::ValueExpr* action47_postfix_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); - ast::nodes::ValueExpr* action48_postfix_expr(SourceLoc loc, ast::nodes::FunctionCall* call); - ast::nodes::FunctionCall* action49_call_expr(SourceLoc loc, ast::nodes::ValueExpr* callee, std::vector>* args); - ast::nodes::FunctionCall* action50_call_expr(SourceLoc loc, ast::nodes::FunctionCall* callee, std::vector>* args); - ast::nodes::ValueExpr* action51_primary_expr(SourceLoc loc, std::string* identifier); - ast::nodes::ValueExpr* action52_primary_expr(SourceLoc loc, std::string* package, std::string* identifier); - ast::nodes::ValueExpr* action53_primary_expr(SourceLoc loc, std::string* package, std::string* identifier); - ast::nodes::ValueExpr* action54_primary_expr(SourceLoc loc, std::string* integer); - ast::nodes::ValueExpr* action55_primary_expr(SourceLoc loc, std::string* number); - ast::nodes::ValueExpr* action56_primary_expr(SourceLoc loc, std::string* text); - ast::nodes::ValueExpr* action57_primary_expr(SourceLoc loc, ast::nodes::ParenthizedValue* value); - ast::nodes::ParenthizedValue* action58_parenthized_value(SourceLoc loc, ast::nodes::ValueExpr* value); - std::vector>* action59_arguments(SourceLoc loc); - std::vector>* action60_arguments(SourceLoc loc, std::vector>* list); - std::vector>* action61_argument_list(SourceLoc loc, ast::nodes::ValueExpr* value); - std::vector>* action62_argument_list(SourceLoc loc, std::vector>* list, ast::nodes::ValueExpr* value); - inline ast::nodes::Package* dup_package(ast::nodes::Package* p) ; - inline void del_package(ast::nodes::Package* p) ; - inline std::vector* dup_global_scope(std::vector* p) ; - inline void del_global_scope(std::vector* p) ; - inline ast::nodes::Declaration* dup_declaration(ast::nodes::Declaration* p) ; - inline void del_declaration(ast::nodes::Declaration* p) ; - inline ast::nodes::VariableDecl* dup_variable_decl(ast::nodes::VariableDecl* p) ; - inline void del_variable_decl(ast::nodes::VariableDecl* p) ; - inline ast::nodes::FunctionDecl* dup_function_decl(ast::nodes::FunctionDecl* p) ; - inline void del_function_decl(ast::nodes::FunctionDecl* p) ; - inline ast::nodes::MethodDecl* dup_method_decl(ast::nodes::MethodDecl* p) ; - inline void del_method_decl(ast::nodes::MethodDecl* p) ; - inline std::vector* dup_parameters(std::vector* p) ; - inline void del_parameters(std::vector* p) ; - inline std::vector* dup_parameter_list(std::vector* p) ; - inline void del_parameter_list(std::vector* p) ; - inline std::vector* dup_method_parameters(std::vector* p) ; - inline void del_method_parameters(std::vector* p) ; - inline std::vector* dup_method_parameter_seq(std::vector* p) ; - inline void del_method_parameter_seq(std::vector* p) ; - inline ast::nodes::Parameter* dup_parameter(ast::nodes::Parameter* p) ; - inline void del_parameter(ast::nodes::Parameter* p) ; - inline std::vector>* dup_type_list(std::vector>* p) ; - inline void del_type_list(std::vector>* p) ; - inline std::vector>* dup_type_list_ne(std::vector>* p) ; - inline void del_type_list_ne(std::vector>* p) ; - inline ast::nodes::TypeExpression* dup_type_expr(ast::nodes::TypeExpression* p) ; - inline void del_type_expr(ast::nodes::TypeExpression* p) ; - inline ast::nodes::NameType* dup_name_type(ast::nodes::NameType* p) ; - inline void del_name_type(ast::nodes::NameType* p) ; - inline ast::nodes::FunctionType* dup_function_type(ast::nodes::FunctionType* p) ; - inline void del_function_type(ast::nodes::FunctionType* p) ; - inline ast::nodes::MethodType* dup_method_type(ast::nodes::MethodType* p) ; - inline void del_method_type(ast::nodes::MethodType* p) ; - inline ast::nodes::ArrowBody* dup_arrow_body(ast::nodes::ArrowBody* p) ; - inline void del_arrow_body(ast::nodes::ArrowBody* p) ; - inline grammar_support::FunctionBodyValue* dup_function_body(grammar_support::FunctionBodyValue* p) ; - inline void del_function_body(grammar_support::FunctionBodyValue* p) ; - inline ast::nodes::Scope* dup_scope(ast::nodes::Scope* p) ; - inline void del_scope(ast::nodes::Scope* p) ; - inline std::vector>* dup_statements(std::vector>* p) ; - inline void del_statements(std::vector>* p) ; - inline ast::nodes::Statement* dup_statement(ast::nodes::Statement* p) ; - inline void del_statement(ast::nodes::Statement* p) ; - inline ast::nodes::FunctionCall* dup_statement_function_call(ast::nodes::FunctionCall* p) ; - inline void del_statement_function_call(ast::nodes::FunctionCall* p) ; - inline ast::nodes::ValueExpr* dup_value_expr(ast::nodes::ValueExpr* p) ; - inline void del_value_expr(ast::nodes::ValueExpr* p) ; - inline ast::nodes::ValueExpr* dup_additive_expr(ast::nodes::ValueExpr* p) ; - inline void del_additive_expr(ast::nodes::ValueExpr* p) ; - inline ast::nodes::ValueExpr* dup_multiplicative_expr(ast::nodes::ValueExpr* p) ; - inline void del_multiplicative_expr(ast::nodes::ValueExpr* p) ; - inline ast::nodes::ValueExpr* dup_unary_expr(ast::nodes::ValueExpr* p) ; - inline void del_unary_expr(ast::nodes::ValueExpr* p) ; - inline ast::nodes::ValueExpr* dup_postfix_expr(ast::nodes::ValueExpr* p) ; - inline void del_postfix_expr(ast::nodes::ValueExpr* p) ; - inline ast::nodes::FunctionCall* dup_call_expr(ast::nodes::FunctionCall* p) ; - inline void del_call_expr(ast::nodes::FunctionCall* p) ; - inline ast::nodes::ValueExpr* dup_primary_expr(ast::nodes::ValueExpr* p) ; - inline void del_primary_expr(ast::nodes::ValueExpr* p) ; - inline ast::nodes::ParenthizedValue* dup_parenthized_value(ast::nodes::ParenthizedValue* p) ; - inline void del_parenthized_value(ast::nodes::ParenthizedValue* p) ; - inline std::vector>* dup_arguments(std::vector>* p) ; - inline void del_arguments(std::vector>* p) ; - inline std::vector>* dup_argument_list(std::vector>* p) ; - inline void del_argument_list(std::vector>* p) ; - inline std::string* dup_TOK_STRING(std::string* s) ; - inline void del_TOK_STRING(std::string* s) ; - inline std::string* dup_TOK_IDENT(std::string* s) ; - inline void del_TOK_IDENT(std::string* s) ; - inline std::string* dup_TOK_INT(std::string* s) ; - inline void del_TOK_INT(std::string* s) ; - inline std::string* dup_TOK_FLOAT(std::string* s) ; - inline void del_TOK_FLOAT(std::string* s) ; - -// the function which makes the parse tables -public: - virtual ParseTables *makeTables(); -}; - -#endif // SRC_GRAMMAR_PARSER_H From b9465e90d7acaf4cccc30bf45fe17a34c98198b7 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 00:17:08 +0200 Subject: [PATCH 057/154] update --- src/grammar/parser.gr | 114 +++++++++++------------------------------- 1 file changed, 30 insertions(+), 84 deletions(-) diff --git a/src/grammar/parser.gr b/src/grammar/parser.gr index c16bc8ba..13c29049 100644 --- a/src/grammar/parser.gr +++ b/src/grammar/parser.gr @@ -370,101 +370,29 @@ nonterm(std::vector>*) statements { } } -nonterm(ast::nodes::Statement*) statement { - fun dup(p) [return p;] - fun del(p) [] - -> call:statement_function_call { - return new ast::nodes::Statement(grammarSupport::takeValue(call)); - } - -> declaration:variable_decl { - return new ast::nodes::Statement(grammarSupport::takeValue(declaration)); - } -} - -nonterm(ast::nodes::FunctionCall*) statement_function_call { - fun dup(p) [return p;] - fun del(p) [] - -> call:call_expr { - return call; - } -} - -nonterm(ast::nodes::ValueExpr*) value_expr { - fun dup(p) [return p;] - fun del(p) [] - -> expr:additive_expr { - return expr; - } -} - -nonterm(ast::nodes::ValueExpr*) additive_expr { - fun dup(p) [return p;] - fun del(p) [] - -> expr:multiplicative_expr { - return expr; - } - -> left:additive_expr "+" right:multiplicative_expr { - return grammarSupport::makeBinary("+", left, right); - } - -> left:additive_expr "-" right:multiplicative_expr { - return grammarSupport::makeBinary("-", left, right); - } -} - -nonterm(ast::nodes::ValueExpr*) multiplicative_expr { - fun dup(p) [return p;] - fun del(p) [] - -> expr:unary_expr { - return expr; - } - -> left:multiplicative_expr "*" right:unary_expr { - return grammarSupport::makeBinary("*", left, right); - } - -> left:multiplicative_expr "/" right:unary_expr { - return grammarSupport::makeBinary("/", left, right); - } -} - -nonterm(ast::nodes::ValueExpr*) unary_expr { +nonterm(ast::nodes::FunctionCall*) function_call { fun dup(p) [return p;] fun del(p) [] - -> expr:postfix_expr { - return expr; - } - -> "~" expr:unary_expr precedence("~") { - return grammarSupport::makeFlip(expr); - } -} - -nonterm(ast::nodes::ValueExpr*) postfix_expr { - fun dup(p) [return p;] - fun del(p) [] - -> expr:primary_expr { - return expr; - } - -> call:call_expr { - return grammarSupport::wrapCall(call); + -> callee:value_expr "(" args: arguments ")" { + return new ast::nodes::FunctionCall( + std::make_unique(grammarSupport::takeValue(callee)), + grammarSupport::takeValue(args) + ); } } -nonterm(ast::nodes::FunctionCall*) call_expr { +nonterm(ast::nodes::Statement*) statement { fun dup(p) [return p;] fun del(p) [] - -> callee:primary_expr "(" args:arguments ")" { - return new ast::nodes::FunctionCall( - grammarSupport::takePtr(callee), - grammarSupport::takeValue(args) - ); + -> call:function_call { + return new ast::nodes::Statement(grammarSupport::takeValue(call)); } - -> callee:call_expr "(" args:arguments ")" { - return new ast::nodes::FunctionCall( - std::make_unique(grammarSupport::takeValue(callee)), - grammarSupport::takeValue(args) - ); + -> declaration:variable_decl { + return new ast::nodes::Statement(grammarSupport::takeValue(declaration)); } } -nonterm(ast::nodes::ValueExpr*) primary_expr { +nonterm(ast::nodes::ValueExpr*) value_expr { fun dup(p) [return p;] fun del(p) [] -> identifier:TOK_IDENT { @@ -498,6 +426,24 @@ nonterm(ast::nodes::ValueExpr*) primary_expr { -> value:parenthized_value { return grammarSupport::wrapParenthesized(value); } + -> call:function_call { + return new ast::nodes::ValueExpr(grammarSupport::takeValue(call)); + } + -> "~" expr:value_expr precedence("~") { + return grammarSupport::makeFlip(expr); + } + -> left:value_expr "*" right:value_expr { + return grammarSupport::makeBinary("*", left, right); + } + -> left:value_expr "/" right:value_expr { + return grammarSupport::makeBinary("/", left, right); + } + -> left:value_expr "+" right:value_expr { + return grammarSupport::makeBinary("*", left, right); + } + -> left:value_expr "-" right:value_expr { + return grammarSupport::makeBinary("/", left, right); + } } nonterm(ast::nodes::ParenthizedValue*) parenthized_value { From 5a4325c395aa97b7629cd6011777f0f5105ca355 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 00:18:17 +0200 Subject: [PATCH 058/154] update --- src/grammar/parser.gr | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/grammar/parser.gr b/src/grammar/parser.gr index 13c29049..d212a064 100644 --- a/src/grammar/parser.gr +++ b/src/grammar/parser.gr @@ -50,10 +50,6 @@ verbatim { return new ast::nodes::ValueExpr(takeValue(call)); } - inline ast::nodes::ValueExpr* wrapParenthesized(ast::nodes::ParenthizedValue* value) { - return new ast::nodes::ValueExpr(takeValue(value)); - } - } // namespace grammarSupport } @@ -424,7 +420,7 @@ nonterm(ast::nodes::ValueExpr*) value_expr { return new ast::nodes::ValueExpr(ast::nodes::StringLiteral(grammarSupport::takeString(text))); } -> value:parenthized_value { - return grammarSupport::wrapParenthesized(value); + return new ast::nodes::ValueExpr(grammarSupport::takeValue(value)); } -> call:function_call { return new ast::nodes::ValueExpr(grammarSupport::takeValue(call)); From f78d04e8226ba8d2c7095e16eb4105c6503ba1be Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 00:20:06 +0200 Subject: [PATCH 059/154] update --- src/grammar/parser.gr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/grammar/parser.gr b/src/grammar/parser.gr index d212a064..e1b5b48b 100644 --- a/src/grammar/parser.gr +++ b/src/grammar/parser.gr @@ -435,10 +435,10 @@ nonterm(ast::nodes::ValueExpr*) value_expr { return grammarSupport::makeBinary("/", left, right); } -> left:value_expr "+" right:value_expr { - return grammarSupport::makeBinary("*", left, right); + return grammarSupport::makeBinary("+", left, right); } -> left:value_expr "-" right:value_expr { - return grammarSupport::makeBinary("/", left, right); + return grammarSupport::makeBinary("-", left, right); } } From 09b5abf0fb96d6e12f21d81542136fd776bbebea Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 10:57:57 +0200 Subject: [PATCH 060/154] update --- test-parser/main.zn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-parser/main.zn b/test-parser/main.zn index a71bb9c7..529e5f82 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,6 +1,6 @@ Void main(this Int, a Bool) { print(2, 2) - Std$print(1 + 1 + 3 + 4) + Std$print(1 + 1 3 + 4) @Intrinsics$print("hello") test Int = 3 func (this Int) -> Void = 3.0 From 697976bbe0f3e09a807a38fad07febefd4b367b5 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 11:31:00 +0200 Subject: [PATCH 061/154] fix build issue --- CMakeFiles/CMakeSystem.cmake | 15 +++++++++++++++ meson.build | 7 +------ vcpkg-ports/elkhound-runtime/portfile.cmake | 2 +- 3 files changed, 17 insertions(+), 7 deletions(-) create mode 100644 CMakeFiles/CMakeSystem.cmake diff --git a/CMakeFiles/CMakeSystem.cmake b/CMakeFiles/CMakeSystem.cmake new file mode 100644 index 00000000..2f7ed46e --- /dev/null +++ b/CMakeFiles/CMakeSystem.cmake @@ -0,0 +1,15 @@ +set(CMAKE_HOST_SYSTEM "Linux-6.6.87.2-microsoft-standard-WSL2") +set(CMAKE_HOST_SYSTEM_NAME "Linux") +set(CMAKE_HOST_SYSTEM_VERSION "6.6.87.2-microsoft-standard-WSL2") +set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64") + + + +set(CMAKE_SYSTEM "Linux-6.6.87.2-microsoft-standard-WSL2") +set(CMAKE_SYSTEM_NAME "Linux") +set(CMAKE_SYSTEM_VERSION "6.6.87.2-microsoft-standard-WSL2") +set(CMAKE_SYSTEM_PROCESSOR "x86_64") + +set(CMAKE_CROSSCOMPILING "FALSE") + +set(CMAKE_SYSTEM_LOADED 1) diff --git a/meson.build b/meson.build index f06280b6..9db6f812 100644 --- a/meson.build +++ b/meson.build @@ -5,12 +5,7 @@ project('zane', 'cpp', re2c = find_program('re2c', required: true) elkhound = find_program('elkhound', required: true) -elkhound_runtime = dependency('elkhound_runtime', - method: 'cmake', - cmake_args: [ - '-DCMAKE_PREFIX_PATH=' + meson.project_source_root() / 'vcpkg_installed/x64-linux/share/elkhound-runtime', - ], - required: true) +elkhound_runtime = dependency('elkhound_runtime', method: 'cmake', required: true) parser_gen = custom_target('parser', input: 'src/grammar/parser.gr', diff --git a/vcpkg-ports/elkhound-runtime/portfile.cmake b/vcpkg-ports/elkhound-runtime/portfile.cmake index f779385e..175176d6 100644 --- a/vcpkg-ports/elkhound-runtime/portfile.cmake +++ b/vcpkg-ports/elkhound-runtime/portfile.cmake @@ -16,7 +16,7 @@ vcpkg_configure_cmake( ) vcpkg_install_cmake() -vcpkg_fixup_cmake_targets(CONFIG_PATH share/elkhound_runtime) +vcpkg_fixup_cmake_targets(CONFIG_PATH share/elkhound_runtime TARGET_PATH share/elkhound_runtime) file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") file(INSTALL "${SOURCE_PATH}/license.txt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) From b18989043e5b954534b144a24ce2a542ca86ffd5 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 11:59:38 +0200 Subject: [PATCH 062/154] update --- src/grammar/lexer.hpp | 1 + src/grammar/lexer.re | 4 +- src/grammar/parser.cc | 1507 +++++++++++++++++++++++++++++++++++++++++ src/grammar/parser.gr | 23 +- src/grammar/parser.h | 222 ++++++ 5 files changed, 1751 insertions(+), 6 deletions(-) create mode 100644 src/grammar/parser.cc create mode 100644 src/grammar/parser.h diff --git a/src/grammar/lexer.hpp b/src/grammar/lexer.hpp index 4012ace5..94fd1d5c 100644 --- a/src/grammar/lexer.hpp +++ b/src/grammar/lexer.hpp @@ -28,6 +28,7 @@ enum TokenCode { TOK_STAR, TOK_SLASH, TOK_TILDE, + TOK_LINEBREAK, TOK_ERROR, }; diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index 4c853fcf..b117ac10 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -131,6 +131,7 @@ const char* Lexer::tokenName(int token) { case TOK_STAR: return "*"; case TOK_SLASH: return "/"; case TOK_TILDE: return "~"; + case TOK_LINEBREAK: return "\\n"; case TOK_ERROR: return "invalid token"; default: return "unknown token"; } @@ -214,10 +215,11 @@ void Lexer::nextToken(LexerInterface* base) { int_lit = sw_digits | digits; float_lit = sw_digits "." digits | digits "." digits; - [ \t\r\n]+ { + [ \t]+ { lexer->updateLocation(start, cursor); continue; } + [\r\n]+ { tok = TOK_LINEBREAK; goto done; } "=" { tok = TOK_EQUAL; goto done; } "(" { tok = TOK_LPAREN; goto done; } ")" { tok = TOK_RPAREN; goto done; } diff --git a/src/grammar/parser.cc b/src/grammar/parser.cc new file mode 100644 index 00000000..1c89ea1c --- /dev/null +++ b/src/grammar/parser.cc @@ -0,0 +1,1507 @@ +// src/grammar/parser.cc +// *** DO NOT EDIT BY HAND *** +// automatically generated by gramanl, from src/grammar/parser.gr + +// GLR source location information is enabled + +#include "parser.h" // ZaneParser +#include "parsetables.h" // ParseTables +#include "srcloc.h" // SourceLoc + +#include // assert +#include // std::cout +#include // abort + +static char const *termNames[] = { + "TOK_EOF", // 0 + "TOK_LPAREN", // 1 + "TOK_RPAREN", // 2 + "TOK_LCURLY", // 3 + "TOK_RCURLY", // 4 + "TOK_COMMA", // 5 + "TOK_COLON", // 6 + "TOK_EQUAL", // 7 + "TOK_DOLLAR", // 8 + "TOK_THIN_ARROW", // 9 + "TOK_THICK_ARROW", // 10 + "TOK_AT", // 11 + "TOK_MUT", // 12 + "TOK_THIS", // 13 + "TOK_STRING", // 14 + "TOK_IDENT", // 15 + "TOK_INT", // 16 + "TOK_FLOAT", // 17 + "TOK_PLUS", // 18 + "TOK_MINUS", // 19 + "TOK_STAR", // 20 + "TOK_SLASH", // 21 + "TOK_TILDE", // 22 + "TOK_LINEBREAK", // 23 + "TOK_ERROR", // 24 +}; + +string ZaneParser::terminalDescription(int termId, SemanticValue sval) +{ + return stringc << termNames[termId] + << "(" << (sval % 100000) << ")"; +} + + +static char const *nontermNames[] = { + "empty", // 0 + "__EarlyStartSymbol", // 1 + "may_break", // 2 + "package", // 3 + "global_scope", // 4 + "declaration", // 5 + "variable_decl", // 6 + "function_decl", // 7 + "method_decl", // 8 + "parameters", // 9 + "parameter_list", // 10 + "method_parameters", // 11 + "method_parameter_seq", // 12 + "parameter", // 13 + "type_list", // 14 + "type_list_ne", // 15 + "type_expr", // 16 + "name_type", // 17 + "function_type", // 18 + "method_type", // 19 + "arrow_body", // 20 + "function_body", // 21 + "scope", // 22 + "statements", // 23 + "function_call", // 24 + "statement", // 25 + "value_expr", // 26 + "parenthized_value", // 27 + "arguments", // 28 + "argument_list", // 29 +}; + +string ZaneParser::nonterminalDescription(int nontermId, SemanticValue sval) +{ + return stringc << nontermNames[nontermId] + << "(" << (sval % 100000) << ")"; +} + + +char const *ZaneParser::terminalName(int termId) +{ + return termNames[termId]; +} + +char const *ZaneParser::nonterminalName(int nontermId) +{ + return nontermNames[nontermId]; +} + +// ------------------- actions ------------------ +// [0] __EarlyStartSymbol[int] -> top:may_break TOK_EOF +inline int ZaneParser::action0___EarlyStartSymbol(SourceLoc loc, int top) +#line 1 "" +{ return top; } +#line 106 "src/grammar/parser.cc" + +// [1] may_break[int] -> empty +inline int ZaneParser::action1_may_break(SourceLoc loc) +#line 117 "src/grammar/parser.gr" +{ return 0; } +#line 112 "src/grammar/parser.cc" + +// [2] may_break[int] -> TOK_LINEBREAK +inline int ZaneParser::action2_may_break(SourceLoc loc) +#line 118 "src/grammar/parser.gr" +{ return 0; } +#line 118 "src/grammar/parser.cc" + +// [3] package[ast::nodes::Package*] -> may_break declarations:global_scope may_break +inline ast::nodes::Package* ZaneParser::action3_package(SourceLoc loc, std::vector* declarations) +#line 124 "src/grammar/parser.gr" +{ + return new ast::nodes::Package(grammarSupport::takeValue(declarations)); + } +#line 126 "src/grammar/parser.cc" + +// [4] global_scope[std::vector*] -> empty +inline std::vector* ZaneParser::action4_global_scope(SourceLoc loc) +#line 132 "src/grammar/parser.gr" +{ + return new std::vector(); + } +#line 134 "src/grammar/parser.cc" + +// [5] global_scope[std::vector*] -> declaration:declaration +inline std::vector* ZaneParser::action5_global_scope(SourceLoc loc, ast::nodes::Declaration* declaration) +#line 135 "src/grammar/parser.gr" +{ + auto* list = new std::vector(); + list->push_back(grammarSupport::takeValue(declaration)); + return list; + } +#line 144 "src/grammar/parser.cc" + +// [6] global_scope[std::vector*] -> declarations:global_scope TOK_LINEBREAK declaration:declaration +inline std::vector* ZaneParser::action6_global_scope(SourceLoc loc, std::vector* declarations, ast::nodes::Declaration* declaration) +#line 140 "src/grammar/parser.gr" +{ + declarations->push_back(grammarSupport::takeValue(declaration)); + return declarations; + } +#line 153 "src/grammar/parser.cc" + +// [7] declaration[ast::nodes::Declaration*] -> function:function_decl +inline ast::nodes::Declaration* ZaneParser::action7_declaration(SourceLoc loc, ast::nodes::FunctionDecl* function) +#line 149 "src/grammar/parser.gr" +{ + return new ast::nodes::Declaration(grammarSupport::takeValue(function)); + } +#line 161 "src/grammar/parser.cc" + +// [8] declaration[ast::nodes::Declaration*] -> method:method_decl +inline ast::nodes::Declaration* ZaneParser::action8_declaration(SourceLoc loc, ast::nodes::MethodDecl* method) +#line 152 "src/grammar/parser.gr" +{ + return new ast::nodes::Declaration(grammarSupport::takeValue(method)); + } +#line 169 "src/grammar/parser.cc" + +// [9] variable_decl[ast::nodes::VariableDecl*] -> name:TOK_IDENT type:type_expr = value:value_expr +inline ast::nodes::VariableDecl* ZaneParser::action9_variable_decl(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type, ast::nodes::ValueExpr* value) +#line 160 "src/grammar/parser.gr" +{ + return new ast::nodes::VariableDecl( + grammarSupport::takeString(name), + grammarSupport::takeValue(type), + grammarSupport::takePtr(value) + ); + } +#line 181 "src/grammar/parser.cc" + +// [10] function_decl[ast::nodes::FunctionDecl*] -> return_type:type_expr name:TOK_IDENT ( params:parameters ) body:function_body +inline ast::nodes::FunctionDecl* ZaneParser::action10_function_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body) +#line 172 "src/grammar/parser.gr" +{ + return new ast::nodes::FunctionDecl( + grammarSupport::takeString(name), + grammarSupport::takeValue(params), + grammarSupport::takeValue(return_type), + grammarSupport::takeValue(body) + ); + } +#line 194 "src/grammar/parser.cc" + +// [11] method_decl[ast::nodes::MethodDecl*] -> return_type:type_expr name:TOK_IDENT ( params:method_parameters ) body:function_body +inline ast::nodes::MethodDecl* ZaneParser::action11_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body) +#line 185 "src/grammar/parser.gr" +{ + return new ast::nodes::MethodDecl( + grammarSupport::takeString(name), + grammarSupport::takeValue(params), + grammarSupport::takeValue(return_type), + grammarSupport::takeValue(body), + false + ); + } +#line 208 "src/grammar/parser.cc" + +// [12] method_decl[ast::nodes::MethodDecl*] -> return_type:type_expr name:TOK_IDENT ( params:method_parameters ) mut body:function_body +inline ast::nodes::MethodDecl* ZaneParser::action12_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body) +#line 194 "src/grammar/parser.gr" +{ + return new ast::nodes::MethodDecl( + grammarSupport::takeString(name), + grammarSupport::takeValue(params), + grammarSupport::takeValue(return_type), + grammarSupport::takeValue(body), + true + ); + } +#line 222 "src/grammar/parser.cc" + +// [13] parameters[std::vector*] -> empty +inline std::vector* ZaneParser::action13_parameters(SourceLoc loc) +#line 208 "src/grammar/parser.gr" +{ + return new std::vector(); + } +#line 230 "src/grammar/parser.cc" + +// [14] parameters[std::vector*] -> list:parameter_list +inline std::vector* ZaneParser::action14_parameters(SourceLoc loc, std::vector* list) +#line 211 "src/grammar/parser.gr" +{ + return list; + } +#line 238 "src/grammar/parser.cc" + +// [15] parameter_list[std::vector*] -> parameter:parameter +inline std::vector* ZaneParser::action15_parameter_list(SourceLoc loc, ast::nodes::Parameter* parameter) +#line 219 "src/grammar/parser.gr" +{ + auto* list = new std::vector(); + list->push_back(grammarSupport::takeValue(parameter)); + return list; + } +#line 248 "src/grammar/parser.cc" + +// [16] parameter_list[std::vector*] -> list:parameter_list , parameter:parameter +inline std::vector* ZaneParser::action16_parameter_list(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter) +#line 224 "src/grammar/parser.gr" +{ + list->push_back(grammarSupport::takeValue(parameter)); + return list; + } +#line 257 "src/grammar/parser.cc" + +// [17] method_parameters[std::vector*] -> list:method_parameter_seq +inline std::vector* ZaneParser::action17_method_parameters(SourceLoc loc, std::vector* list) +#line 233 "src/grammar/parser.gr" +{ + return list; + } +#line 265 "src/grammar/parser.cc" + +// [18] method_parameter_seq[std::vector*] -> this type:type_expr +inline std::vector* ZaneParser::action18_method_parameter_seq(SourceLoc loc, ast::nodes::TypeExpression* type) +#line 241 "src/grammar/parser.gr" +{ + auto* list = new std::vector(); + list->push_back(ast::nodes::Parameter(grammarSupport::takePtr(type), "this")); + return list; + } +#line 275 "src/grammar/parser.cc" + +// [19] method_parameter_seq[std::vector*] -> list:method_parameter_seq , parameter:parameter +inline std::vector* ZaneParser::action19_method_parameter_seq(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter) +#line 246 "src/grammar/parser.gr" +{ + list->push_back(grammarSupport::takeValue(parameter)); + return list; + } +#line 284 "src/grammar/parser.cc" + +// [20] parameter[ast::nodes::Parameter*] -> name:TOK_IDENT type:type_expr +inline ast::nodes::Parameter* ZaneParser::action20_parameter(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type) +#line 255 "src/grammar/parser.gr" +{ + return new ast::nodes::Parameter( + grammarSupport::takePtr(type), + grammarSupport::takeString(name) + ); + } +#line 295 "src/grammar/parser.cc" + +// [21] type_list[std::vector>*] -> empty +inline std::vector>* ZaneParser::action21_type_list(SourceLoc loc) +#line 266 "src/grammar/parser.gr" +{ + return new std::vector>(); + } +#line 303 "src/grammar/parser.cc" + +// [22] type_list[std::vector>*] -> list:type_list_ne +inline std::vector>* ZaneParser::action22_type_list(SourceLoc loc, std::vector>* list) +#line 269 "src/grammar/parser.gr" +{ + return list; + } +#line 311 "src/grammar/parser.cc" + +// [23] type_list_ne[std::vector>*] -> expr:type_expr +inline std::vector>* ZaneParser::action23_type_list_ne(SourceLoc loc, ast::nodes::TypeExpression* expr) +#line 277 "src/grammar/parser.gr" +{ + auto* list = new std::vector>(); + list->push_back(grammarSupport::takePtr(expr)); + return list; + } +#line 321 "src/grammar/parser.cc" + +// [24] type_list_ne[std::vector>*] -> list:type_list_ne , expr:type_expr +inline std::vector>* ZaneParser::action24_type_list_ne(SourceLoc loc, std::vector>* list, ast::nodes::TypeExpression* expr) +#line 282 "src/grammar/parser.gr" +{ + list->push_back(grammarSupport::takePtr(expr)); + return list; + } +#line 330 "src/grammar/parser.cc" + +// [25] type_expr[ast::nodes::TypeExpression*] -> name:name_type +inline ast::nodes::TypeExpression* ZaneParser::action25_type_expr(SourceLoc loc, ast::nodes::NameType* name) +#line 291 "src/grammar/parser.gr" +{ + return new ast::nodes::TypeExpression(grammarSupport::takeValue(name)); + } +#line 338 "src/grammar/parser.cc" + +// [26] type_expr[ast::nodes::TypeExpression*] -> function:function_type +inline ast::nodes::TypeExpression* ZaneParser::action26_type_expr(SourceLoc loc, ast::nodes::FunctionType* function) +#line 294 "src/grammar/parser.gr" +{ + return new ast::nodes::TypeExpression(grammarSupport::takeValue(function)); + } +#line 346 "src/grammar/parser.cc" + +// [27] type_expr[ast::nodes::TypeExpression*] -> method:method_type +inline ast::nodes::TypeExpression* ZaneParser::action27_type_expr(SourceLoc loc, ast::nodes::MethodType* method) +#line 297 "src/grammar/parser.gr" +{ + return new ast::nodes::TypeExpression(grammarSupport::takeValue(method)); + } +#line 354 "src/grammar/parser.cc" + +// [28] name_type[ast::nodes::NameType*] -> identifier:TOK_IDENT +inline ast::nodes::NameType* ZaneParser::action28_name_type(SourceLoc loc, std::string* identifier) +#line 305 "src/grammar/parser.gr" +{ + return new ast::nodes::NameType( + grammarSupport::takeString(identifier), + std::vector>() + ); + } +#line 365 "src/grammar/parser.cc" + +// [29] function_type[ast::nodes::FunctionType*] -> ( params:type_list ) -> return_type:type_expr +inline ast::nodes::FunctionType* ZaneParser::action29_function_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) +#line 316 "src/grammar/parser.gr" +{ + return new ast::nodes::FunctionType( + grammarSupport::takeValue(params), + grammarSupport::takePtr(return_type) + ); + } +#line 376 "src/grammar/parser.cc" + +// [30] method_type[ast::nodes::MethodType*] -> ( this params:type_list_ne ) -> return_type:type_expr +inline ast::nodes::MethodType* ZaneParser::action30_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) +#line 327 "src/grammar/parser.gr" +{ + return new ast::nodes::MethodType( + grammarSupport::takeValue(params), + grammarSupport::takePtr(return_type), + false + ); + } +#line 388 "src/grammar/parser.cc" + +// [31] method_type[ast::nodes::MethodType*] -> ( this params:type_list_ne ) mut -> return_type:type_expr +inline ast::nodes::MethodType* ZaneParser::action31_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) +#line 334 "src/grammar/parser.gr" +{ + return new ast::nodes::MethodType( + grammarSupport::takeValue(params), + grammarSupport::takePtr(return_type), + true + ); + } +#line 400 "src/grammar/parser.cc" + +// [32] arrow_body[ast::nodes::ArrowBody*] -> => value:value_expr +inline ast::nodes::ArrowBody* ZaneParser::action32_arrow_body(SourceLoc loc, ast::nodes::ValueExpr* value) +#line 346 "src/grammar/parser.gr" +{ + return new ast::nodes::ArrowBody(grammarSupport::takePtr(value)); + } +#line 408 "src/grammar/parser.cc" + +// [33] function_body[grammarSupport::FunctionBody*] -> body:arrow_body +inline grammarSupport::FunctionBody* ZaneParser::action33_function_body(SourceLoc loc, ast::nodes::ArrowBody* body) +#line 354 "src/grammar/parser.gr" +{ + return new grammarSupport::FunctionBody(grammarSupport::takeValue(body)); + } +#line 416 "src/grammar/parser.cc" + +// [34] function_body[grammarSupport::FunctionBody*] -> body:scope +inline grammarSupport::FunctionBody* ZaneParser::action34_function_body(SourceLoc loc, ast::nodes::Scope* body) +#line 357 "src/grammar/parser.gr" +{ + return new grammarSupport::FunctionBody(grammarSupport::takeValue(body)); + } +#line 424 "src/grammar/parser.cc" + +// [35] scope[ast::nodes::Scope*] -> { TOK_LINEBREAK statements:statements TOK_LINEBREAK } +inline ast::nodes::Scope* ZaneParser::action35_scope(SourceLoc loc, std::vector>* statements) +#line 365 "src/grammar/parser.gr" +{ + return new ast::nodes::Scope(grammarSupport::takeValue(statements)); + } +#line 432 "src/grammar/parser.cc" + +// [36] statements[std::vector>*] -> empty +inline std::vector>* ZaneParser::action36_statements(SourceLoc loc) +#line 373 "src/grammar/parser.gr" +{ + return new std::vector>(); + } +#line 440 "src/grammar/parser.cc" + +// [37] statements[std::vector>*] -> list:statements TOK_LINEBREAK statement:statement +inline std::vector>* ZaneParser::action37_statements(SourceLoc loc, std::vector>* list, ast::nodes::Statement* statement) +#line 376 "src/grammar/parser.gr" +{ + list->push_back(grammarSupport::takePtr(statement)); + return list; + } +#line 449 "src/grammar/parser.cc" + +// [38] function_call[ast::nodes::FunctionCall*] -> callee:value_expr ( args:arguments ) +inline ast::nodes::FunctionCall* ZaneParser::action38_function_call(SourceLoc loc, ast::nodes::ValueExpr* callee, std::vector>* args) +#line 385 "src/grammar/parser.gr" +{ + return new ast::nodes::FunctionCall( + std::make_unique(grammarSupport::takeValue(callee)), + grammarSupport::takeValue(args) + ); + } +#line 460 "src/grammar/parser.cc" + +// [39] statement[ast::nodes::Statement*] -> call:function_call +inline ast::nodes::Statement* ZaneParser::action39_statement(SourceLoc loc, ast::nodes::FunctionCall* call) +#line 396 "src/grammar/parser.gr" +{ + return new ast::nodes::Statement(grammarSupport::takeValue(call)); + } +#line 468 "src/grammar/parser.cc" + +// [40] statement[ast::nodes::Statement*] -> declaration:variable_decl +inline ast::nodes::Statement* ZaneParser::action40_statement(SourceLoc loc, ast::nodes::VariableDecl* declaration) +#line 399 "src/grammar/parser.gr" +{ + return new ast::nodes::Statement(grammarSupport::takeValue(declaration)); + } +#line 476 "src/grammar/parser.cc" + +// [41] value_expr[ast::nodes::ValueExpr*] -> identifier:TOK_IDENT +inline ast::nodes::ValueExpr* ZaneParser::action41_value_expr(SourceLoc loc, std::string* identifier) +#line 407 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr(ast::nodes::ValueSymbol(grammarSupport::takeString(identifier))); + } +#line 484 "src/grammar/parser.cc" + +// [42] value_expr[ast::nodes::ValueExpr*] -> package:TOK_IDENT $ identifier:TOK_IDENT +inline ast::nodes::ValueExpr* ZaneParser::action42_value_expr(SourceLoc loc, std::string* package, std::string* identifier) +#line 410 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr( + ast::nodes::PackageValueSymbol( + grammarSupport::takeString(identifier), + grammarSupport::takeString(package) + ) + ); + } +#line 497 "src/grammar/parser.cc" + +// [43] value_expr[ast::nodes::ValueExpr*] -> @ package:TOK_IDENT $ identifier:TOK_IDENT +inline ast::nodes::ValueExpr* ZaneParser::action43_value_expr(SourceLoc loc, std::string* package, std::string* identifier) +#line 418 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr( + ast::nodes::IntrinsicValueSymbol( + grammarSupport::takeString(identifier), + grammarSupport::takeString(package) + ) + ); + } +#line 510 "src/grammar/parser.cc" + +// [44] value_expr[ast::nodes::ValueExpr*] -> integer:TOK_INT +inline ast::nodes::ValueExpr* ZaneParser::action44_value_expr(SourceLoc loc, std::string* integer) +#line 426 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr(ast::nodes::IntLiteral(grammarSupport::takeString(integer))); + } +#line 518 "src/grammar/parser.cc" + +// [45] value_expr[ast::nodes::ValueExpr*] -> number:TOK_FLOAT +inline ast::nodes::ValueExpr* ZaneParser::action45_value_expr(SourceLoc loc, std::string* number) +#line 429 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr(ast::nodes::FloatLiteral(grammarSupport::takeString(number))); + } +#line 526 "src/grammar/parser.cc" + +// [46] value_expr[ast::nodes::ValueExpr*] -> text:TOK_STRING +inline ast::nodes::ValueExpr* ZaneParser::action46_value_expr(SourceLoc loc, std::string* text) +#line 432 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr(ast::nodes::StringLiteral(grammarSupport::takeString(text))); + } +#line 534 "src/grammar/parser.cc" + +// [47] value_expr[ast::nodes::ValueExpr*] -> value:parenthized_value +inline ast::nodes::ValueExpr* ZaneParser::action47_value_expr(SourceLoc loc, ast::nodes::ParenthizedValue* value) +#line 435 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr(grammarSupport::takeValue(value)); + } +#line 542 "src/grammar/parser.cc" + +// [48] value_expr[ast::nodes::ValueExpr*] -> call:function_call +inline ast::nodes::ValueExpr* ZaneParser::action48_value_expr(SourceLoc loc, ast::nodes::FunctionCall* call) +#line 438 "src/grammar/parser.gr" +{ + return new ast::nodes::ValueExpr(grammarSupport::takeValue(call)); + } +#line 550 "src/grammar/parser.cc" + +// [49] value_expr[ast::nodes::ValueExpr*] -> ~ expr:value_expr %prec(30) +inline ast::nodes::ValueExpr* ZaneParser::action49_value_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) +#line 441 "src/grammar/parser.gr" +{ + return grammarSupport::makeFlip(expr); + } +#line 558 "src/grammar/parser.cc" + +// [50] value_expr[ast::nodes::ValueExpr*] -> left:value_expr * right:value_expr %prec(20) +inline ast::nodes::ValueExpr* ZaneParser::action50_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) +#line 444 "src/grammar/parser.gr" +{ + return grammarSupport::makeBinary("*", left, right); + } +#line 566 "src/grammar/parser.cc" + +// [51] value_expr[ast::nodes::ValueExpr*] -> left:value_expr / right:value_expr %prec(20) +inline ast::nodes::ValueExpr* ZaneParser::action51_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) +#line 447 "src/grammar/parser.gr" +{ + return grammarSupport::makeBinary("/", left, right); + } +#line 574 "src/grammar/parser.cc" + +// [52] value_expr[ast::nodes::ValueExpr*] -> left:value_expr + right:value_expr %prec(10) +inline ast::nodes::ValueExpr* ZaneParser::action52_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) +#line 450 "src/grammar/parser.gr" +{ + return grammarSupport::makeBinary("+", left, right); + } +#line 582 "src/grammar/parser.cc" + +// [53] value_expr[ast::nodes::ValueExpr*] -> left:value_expr - right:value_expr %prec(10) +inline ast::nodes::ValueExpr* ZaneParser::action53_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) +#line 453 "src/grammar/parser.gr" +{ + return grammarSupport::makeBinary("-", left, right); + } +#line 590 "src/grammar/parser.cc" + +// [54] parenthized_value[ast::nodes::ParenthizedValue*] -> ( value:value_expr ) +inline ast::nodes::ParenthizedValue* ZaneParser::action54_parenthized_value(SourceLoc loc, ast::nodes::ValueExpr* value) +#line 461 "src/grammar/parser.gr" +{ + return new ast::nodes::ParenthizedValue(grammarSupport::takePtr(value)); + } +#line 598 "src/grammar/parser.cc" + +// [55] arguments[std::vector>*] -> empty +inline std::vector>* ZaneParser::action55_arguments(SourceLoc loc) +#line 469 "src/grammar/parser.gr" +{ + return new std::vector>(); + } +#line 606 "src/grammar/parser.cc" + +// [56] arguments[std::vector>*] -> list:argument_list +inline std::vector>* ZaneParser::action56_arguments(SourceLoc loc, std::vector>* list) +#line 472 "src/grammar/parser.gr" +{ + return list; + } +#line 614 "src/grammar/parser.cc" + +// [57] argument_list[std::vector>*] -> value:value_expr +inline std::vector>* ZaneParser::action57_argument_list(SourceLoc loc, ast::nodes::ValueExpr* value) +#line 480 "src/grammar/parser.gr" +{ + auto* list = new std::vector>(); + list->push_back(grammarSupport::takePtr(value)); + return list; + } +#line 624 "src/grammar/parser.cc" + +// [58] argument_list[std::vector>*] -> list:argument_list , value:value_expr +inline std::vector>* ZaneParser::action58_argument_list(SourceLoc loc, std::vector>* list, ast::nodes::ValueExpr* value) +#line 485 "src/grammar/parser.gr" +{ + list->push_back(grammarSupport::takePtr(value)); + return list; + } +#line 633 "src/grammar/parser.cc" + + +/*static*/ SemanticValue ZaneParser::doReductionAction( + ZaneParser *ths, + int productionId, SemanticValue const *semanticValues, + SourceLoc loc) +{ + switch (productionId) { + case 0: + return (SemanticValue)(ths->action0___EarlyStartSymbol(loc, (int)(semanticValues[0]))); + case 1: + return (SemanticValue)(ths->action1_may_break(loc)); + case 2: + return (SemanticValue)(ths->action2_may_break(loc)); + case 3: + return (SemanticValue)(ths->action3_package(loc, (std::vector*)(semanticValues[1]))); + case 4: + return (SemanticValue)(ths->action4_global_scope(loc)); + case 5: + return (SemanticValue)(ths->action5_global_scope(loc, (ast::nodes::Declaration*)(semanticValues[0]))); + case 6: + return (SemanticValue)(ths->action6_global_scope(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Declaration*)(semanticValues[2]))); + case 7: + return (SemanticValue)(ths->action7_declaration(loc, (ast::nodes::FunctionDecl*)(semanticValues[0]))); + case 8: + return (SemanticValue)(ths->action8_declaration(loc, (ast::nodes::MethodDecl*)(semanticValues[0]))); + case 9: + return (SemanticValue)(ths->action9_variable_decl(loc, (std::string*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[1]), (ast::nodes::ValueExpr*)(semanticValues[3]))); + case 10: + return (SemanticValue)(ths->action10_function_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammarSupport::FunctionBody*)(semanticValues[5]))); + case 11: + return (SemanticValue)(ths->action11_method_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammarSupport::FunctionBody*)(semanticValues[5]))); + case 12: + return (SemanticValue)(ths->action12_method_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammarSupport::FunctionBody*)(semanticValues[6]))); + case 13: + return (SemanticValue)(ths->action13_parameters(loc)); + case 14: + return (SemanticValue)(ths->action14_parameters(loc, (std::vector*)(semanticValues[0]))); + case 15: + return (SemanticValue)(ths->action15_parameter_list(loc, (ast::nodes::Parameter*)(semanticValues[0]))); + case 16: + return (SemanticValue)(ths->action16_parameter_list(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Parameter*)(semanticValues[2]))); + case 17: + return (SemanticValue)(ths->action17_method_parameters(loc, (std::vector*)(semanticValues[0]))); + case 18: + return (SemanticValue)(ths->action18_method_parameter_seq(loc, (ast::nodes::TypeExpression*)(semanticValues[1]))); + case 19: + return (SemanticValue)(ths->action19_method_parameter_seq(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Parameter*)(semanticValues[2]))); + case 20: + return (SemanticValue)(ths->action20_parameter(loc, (std::string*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[1]))); + case 21: + return (SemanticValue)(ths->action21_type_list(loc)); + case 22: + return (SemanticValue)(ths->action22_type_list(loc, (std::vector>*)(semanticValues[0]))); + case 23: + return (SemanticValue)(ths->action23_type_list_ne(loc, (ast::nodes::TypeExpression*)(semanticValues[0]))); + case 24: + return (SemanticValue)(ths->action24_type_list_ne(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[2]))); + case 25: + return (SemanticValue)(ths->action25_type_expr(loc, (ast::nodes::NameType*)(semanticValues[0]))); + case 26: + return (SemanticValue)(ths->action26_type_expr(loc, (ast::nodes::FunctionType*)(semanticValues[0]))); + case 27: + return (SemanticValue)(ths->action27_type_expr(loc, (ast::nodes::MethodType*)(semanticValues[0]))); + case 28: + return (SemanticValue)(ths->action28_name_type(loc, (std::string*)(semanticValues[0]))); + case 29: + return (SemanticValue)(ths->action29_function_type(loc, (std::vector>*)(semanticValues[1]), (ast::nodes::TypeExpression*)(semanticValues[4]))); + case 30: + return (SemanticValue)(ths->action30_method_type(loc, (std::vector>*)(semanticValues[2]), (ast::nodes::TypeExpression*)(semanticValues[5]))); + case 31: + return (SemanticValue)(ths->action31_method_type(loc, (std::vector>*)(semanticValues[2]), (ast::nodes::TypeExpression*)(semanticValues[6]))); + case 32: + return (SemanticValue)(ths->action32_arrow_body(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); + case 33: + return (SemanticValue)(ths->action33_function_body(loc, (ast::nodes::ArrowBody*)(semanticValues[0]))); + case 34: + return (SemanticValue)(ths->action34_function_body(loc, (ast::nodes::Scope*)(semanticValues[0]))); + case 35: + return (SemanticValue)(ths->action35_scope(loc, (std::vector>*)(semanticValues[2]))); + case 36: + return (SemanticValue)(ths->action36_statements(loc)); + case 37: + return (SemanticValue)(ths->action37_statements(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::Statement*)(semanticValues[2]))); + case 38: + return (SemanticValue)(ths->action38_function_call(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (std::vector>*)(semanticValues[2]))); + case 39: + return (SemanticValue)(ths->action39_statement(loc, (ast::nodes::FunctionCall*)(semanticValues[0]))); + case 40: + return (SemanticValue)(ths->action40_statement(loc, (ast::nodes::VariableDecl*)(semanticValues[0]))); + case 41: + return (SemanticValue)(ths->action41_value_expr(loc, (std::string*)(semanticValues[0]))); + case 42: + return (SemanticValue)(ths->action42_value_expr(loc, (std::string*)(semanticValues[0]), (std::string*)(semanticValues[2]))); + case 43: + return (SemanticValue)(ths->action43_value_expr(loc, (std::string*)(semanticValues[1]), (std::string*)(semanticValues[3]))); + case 44: + return (SemanticValue)(ths->action44_value_expr(loc, (std::string*)(semanticValues[0]))); + case 45: + return (SemanticValue)(ths->action45_value_expr(loc, (std::string*)(semanticValues[0]))); + case 46: + return (SemanticValue)(ths->action46_value_expr(loc, (std::string*)(semanticValues[0]))); + case 47: + return (SemanticValue)(ths->action47_value_expr(loc, (ast::nodes::ParenthizedValue*)(semanticValues[0]))); + case 48: + return (SemanticValue)(ths->action48_value_expr(loc, (ast::nodes::FunctionCall*)(semanticValues[0]))); + case 49: + return (SemanticValue)(ths->action49_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); + case 50: + return (SemanticValue)(ths->action50_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); + case 51: + return (SemanticValue)(ths->action51_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); + case 52: + return (SemanticValue)(ths->action52_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); + case 53: + return (SemanticValue)(ths->action53_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); + case 54: + return (SemanticValue)(ths->action54_parenthized_value(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); + case 55: + return (SemanticValue)(ths->action55_arguments(loc)); + case 56: + return (SemanticValue)(ths->action56_arguments(loc, (std::vector>*)(semanticValues[0]))); + case 57: + return (SemanticValue)(ths->action57_argument_list(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); + case 58: + return (SemanticValue)(ths->action58_argument_list(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); + default: + assert(!"invalid production code"); + return (SemanticValue)0; // silence warning + } +} + +UserActions::ReductionActionFunc ZaneParser::getReductionAction() +{ + return (ReductionActionFunc)&ZaneParser::doReductionAction; +} + + +// ---------------- dup/del/merge/keep nonterminals --------------- + +inline int ZaneParser::dup_may_break(int p) +#line 115 "src/grammar/parser.gr" +{return p; } +#line 777 "src/grammar/parser.cc" + +inline void ZaneParser::del_may_break(int p) +#line 116 "src/grammar/parser.gr" +{ } +#line 782 "src/grammar/parser.cc" + +inline ast::nodes::Package* ZaneParser::dup_package(ast::nodes::Package* p) +#line 122 "src/grammar/parser.gr" +{return p; } +#line 787 "src/grammar/parser.cc" + +inline void ZaneParser::del_package(ast::nodes::Package* p) +#line 123 "src/grammar/parser.gr" +{ } +#line 792 "src/grammar/parser.cc" + +inline std::vector* ZaneParser::dup_global_scope(std::vector* p) +#line 130 "src/grammar/parser.gr" +{return p; } +#line 797 "src/grammar/parser.cc" + +inline void ZaneParser::del_global_scope(std::vector* p) +#line 131 "src/grammar/parser.gr" +{ } +#line 802 "src/grammar/parser.cc" + +inline ast::nodes::Declaration* ZaneParser::dup_declaration(ast::nodes::Declaration* p) +#line 147 "src/grammar/parser.gr" +{return p; } +#line 807 "src/grammar/parser.cc" + +inline void ZaneParser::del_declaration(ast::nodes::Declaration* p) +#line 148 "src/grammar/parser.gr" +{ } +#line 812 "src/grammar/parser.cc" + +inline ast::nodes::VariableDecl* ZaneParser::dup_variable_decl(ast::nodes::VariableDecl* p) +#line 158 "src/grammar/parser.gr" +{return p; } +#line 817 "src/grammar/parser.cc" + +inline void ZaneParser::del_variable_decl(ast::nodes::VariableDecl* p) +#line 159 "src/grammar/parser.gr" +{ } +#line 822 "src/grammar/parser.cc" + +inline ast::nodes::FunctionDecl* ZaneParser::dup_function_decl(ast::nodes::FunctionDecl* p) +#line 170 "src/grammar/parser.gr" +{return p; } +#line 827 "src/grammar/parser.cc" + +inline void ZaneParser::del_function_decl(ast::nodes::FunctionDecl* p) +#line 171 "src/grammar/parser.gr" +{ } +#line 832 "src/grammar/parser.cc" + +inline ast::nodes::MethodDecl* ZaneParser::dup_method_decl(ast::nodes::MethodDecl* p) +#line 183 "src/grammar/parser.gr" +{return p; } +#line 837 "src/grammar/parser.cc" + +inline void ZaneParser::del_method_decl(ast::nodes::MethodDecl* p) +#line 184 "src/grammar/parser.gr" +{ } +#line 842 "src/grammar/parser.cc" + +inline std::vector* ZaneParser::dup_parameters(std::vector* p) +#line 206 "src/grammar/parser.gr" +{return p; } +#line 847 "src/grammar/parser.cc" + +inline void ZaneParser::del_parameters(std::vector* p) +#line 207 "src/grammar/parser.gr" +{ } +#line 852 "src/grammar/parser.cc" + +inline std::vector* ZaneParser::dup_parameter_list(std::vector* p) +#line 217 "src/grammar/parser.gr" +{return p; } +#line 857 "src/grammar/parser.cc" + +inline void ZaneParser::del_parameter_list(std::vector* p) +#line 218 "src/grammar/parser.gr" +{ } +#line 862 "src/grammar/parser.cc" + +inline std::vector* ZaneParser::dup_method_parameters(std::vector* p) +#line 231 "src/grammar/parser.gr" +{return p; } +#line 867 "src/grammar/parser.cc" + +inline void ZaneParser::del_method_parameters(std::vector* p) +#line 232 "src/grammar/parser.gr" +{ } +#line 872 "src/grammar/parser.cc" + +inline std::vector* ZaneParser::dup_method_parameter_seq(std::vector* p) +#line 239 "src/grammar/parser.gr" +{return p; } +#line 877 "src/grammar/parser.cc" + +inline void ZaneParser::del_method_parameter_seq(std::vector* p) +#line 240 "src/grammar/parser.gr" +{ } +#line 882 "src/grammar/parser.cc" + +inline ast::nodes::Parameter* ZaneParser::dup_parameter(ast::nodes::Parameter* p) +#line 253 "src/grammar/parser.gr" +{return p; } +#line 887 "src/grammar/parser.cc" + +inline void ZaneParser::del_parameter(ast::nodes::Parameter* p) +#line 254 "src/grammar/parser.gr" +{ } +#line 892 "src/grammar/parser.cc" + +inline std::vector>* ZaneParser::dup_type_list(std::vector>* p) +#line 264 "src/grammar/parser.gr" +{return p; } +#line 897 "src/grammar/parser.cc" + +inline void ZaneParser::del_type_list(std::vector>* p) +#line 265 "src/grammar/parser.gr" +{ } +#line 902 "src/grammar/parser.cc" + +inline std::vector>* ZaneParser::dup_type_list_ne(std::vector>* p) +#line 275 "src/grammar/parser.gr" +{return p; } +#line 907 "src/grammar/parser.cc" + +inline void ZaneParser::del_type_list_ne(std::vector>* p) +#line 276 "src/grammar/parser.gr" +{ } +#line 912 "src/grammar/parser.cc" + +inline ast::nodes::TypeExpression* ZaneParser::dup_type_expr(ast::nodes::TypeExpression* p) +#line 289 "src/grammar/parser.gr" +{return p; } +#line 917 "src/grammar/parser.cc" + +inline void ZaneParser::del_type_expr(ast::nodes::TypeExpression* p) +#line 290 "src/grammar/parser.gr" +{ } +#line 922 "src/grammar/parser.cc" + +inline ast::nodes::NameType* ZaneParser::dup_name_type(ast::nodes::NameType* p) +#line 303 "src/grammar/parser.gr" +{return p; } +#line 927 "src/grammar/parser.cc" + +inline void ZaneParser::del_name_type(ast::nodes::NameType* p) +#line 304 "src/grammar/parser.gr" +{ } +#line 932 "src/grammar/parser.cc" + +inline ast::nodes::FunctionType* ZaneParser::dup_function_type(ast::nodes::FunctionType* p) +#line 314 "src/grammar/parser.gr" +{return p; } +#line 937 "src/grammar/parser.cc" + +inline void ZaneParser::del_function_type(ast::nodes::FunctionType* p) +#line 315 "src/grammar/parser.gr" +{ } +#line 942 "src/grammar/parser.cc" + +inline ast::nodes::MethodType* ZaneParser::dup_method_type(ast::nodes::MethodType* p) +#line 325 "src/grammar/parser.gr" +{return p; } +#line 947 "src/grammar/parser.cc" + +inline void ZaneParser::del_method_type(ast::nodes::MethodType* p) +#line 326 "src/grammar/parser.gr" +{ } +#line 952 "src/grammar/parser.cc" + +inline ast::nodes::ArrowBody* ZaneParser::dup_arrow_body(ast::nodes::ArrowBody* p) +#line 344 "src/grammar/parser.gr" +{return p; } +#line 957 "src/grammar/parser.cc" + +inline void ZaneParser::del_arrow_body(ast::nodes::ArrowBody* p) +#line 345 "src/grammar/parser.gr" +{ } +#line 962 "src/grammar/parser.cc" + +inline grammarSupport::FunctionBody* ZaneParser::dup_function_body(grammarSupport::FunctionBody* p) +#line 352 "src/grammar/parser.gr" +{return p; } +#line 967 "src/grammar/parser.cc" + +inline void ZaneParser::del_function_body(grammarSupport::FunctionBody* p) +#line 353 "src/grammar/parser.gr" +{ } +#line 972 "src/grammar/parser.cc" + +inline ast::nodes::Scope* ZaneParser::dup_scope(ast::nodes::Scope* p) +#line 363 "src/grammar/parser.gr" +{return p; } +#line 977 "src/grammar/parser.cc" + +inline void ZaneParser::del_scope(ast::nodes::Scope* p) +#line 364 "src/grammar/parser.gr" +{ } +#line 982 "src/grammar/parser.cc" + +inline std::vector>* ZaneParser::dup_statements(std::vector>* p) +#line 371 "src/grammar/parser.gr" +{return p; } +#line 987 "src/grammar/parser.cc" + +inline void ZaneParser::del_statements(std::vector>* p) +#line 372 "src/grammar/parser.gr" +{ } +#line 992 "src/grammar/parser.cc" + +inline ast::nodes::FunctionCall* ZaneParser::dup_function_call(ast::nodes::FunctionCall* p) +#line 383 "src/grammar/parser.gr" +{return p; } +#line 997 "src/grammar/parser.cc" + +inline void ZaneParser::del_function_call(ast::nodes::FunctionCall* p) +#line 384 "src/grammar/parser.gr" +{ } +#line 1002 "src/grammar/parser.cc" + +inline ast::nodes::Statement* ZaneParser::dup_statement(ast::nodes::Statement* p) +#line 394 "src/grammar/parser.gr" +{return p; } +#line 1007 "src/grammar/parser.cc" + +inline void ZaneParser::del_statement(ast::nodes::Statement* p) +#line 395 "src/grammar/parser.gr" +{ } +#line 1012 "src/grammar/parser.cc" + +inline ast::nodes::ValueExpr* ZaneParser::dup_value_expr(ast::nodes::ValueExpr* p) +#line 405 "src/grammar/parser.gr" +{return p; } +#line 1017 "src/grammar/parser.cc" + +inline void ZaneParser::del_value_expr(ast::nodes::ValueExpr* p) +#line 406 "src/grammar/parser.gr" +{ } +#line 1022 "src/grammar/parser.cc" + +inline ast::nodes::ParenthizedValue* ZaneParser::dup_parenthized_value(ast::nodes::ParenthizedValue* p) +#line 459 "src/grammar/parser.gr" +{return p; } +#line 1027 "src/grammar/parser.cc" + +inline void ZaneParser::del_parenthized_value(ast::nodes::ParenthizedValue* p) +#line 460 "src/grammar/parser.gr" +{ } +#line 1032 "src/grammar/parser.cc" + +inline std::vector>* ZaneParser::dup_arguments(std::vector>* p) +#line 467 "src/grammar/parser.gr" +{return p; } +#line 1037 "src/grammar/parser.cc" + +inline void ZaneParser::del_arguments(std::vector>* p) +#line 468 "src/grammar/parser.gr" +{ } +#line 1042 "src/grammar/parser.cc" + +inline std::vector>* ZaneParser::dup_argument_list(std::vector>* p) +#line 478 "src/grammar/parser.gr" +{return p; } +#line 1047 "src/grammar/parser.cc" + +inline void ZaneParser::del_argument_list(std::vector>* p) +#line 479 "src/grammar/parser.gr" +{ } +#line 1052 "src/grammar/parser.cc" + +SemanticValue ZaneParser::duplicateNontermValue(int nontermId, SemanticValue sval) +{ + switch (nontermId) { + case 2: + return (SemanticValue)dup_may_break((int)sval); + case 3: + return (SemanticValue)dup_package((ast::nodes::Package*)sval); + case 4: + return (SemanticValue)dup_global_scope((std::vector*)sval); + case 5: + return (SemanticValue)dup_declaration((ast::nodes::Declaration*)sval); + case 6: + return (SemanticValue)dup_variable_decl((ast::nodes::VariableDecl*)sval); + case 7: + return (SemanticValue)dup_function_decl((ast::nodes::FunctionDecl*)sval); + case 8: + return (SemanticValue)dup_method_decl((ast::nodes::MethodDecl*)sval); + case 9: + return (SemanticValue)dup_parameters((std::vector*)sval); + case 10: + return (SemanticValue)dup_parameter_list((std::vector*)sval); + case 11: + return (SemanticValue)dup_method_parameters((std::vector*)sval); + case 12: + return (SemanticValue)dup_method_parameter_seq((std::vector*)sval); + case 13: + return (SemanticValue)dup_parameter((ast::nodes::Parameter*)sval); + case 14: + return (SemanticValue)dup_type_list((std::vector>*)sval); + case 15: + return (SemanticValue)dup_type_list_ne((std::vector>*)sval); + case 16: + return (SemanticValue)dup_type_expr((ast::nodes::TypeExpression*)sval); + case 17: + return (SemanticValue)dup_name_type((ast::nodes::NameType*)sval); + case 18: + return (SemanticValue)dup_function_type((ast::nodes::FunctionType*)sval); + case 19: + return (SemanticValue)dup_method_type((ast::nodes::MethodType*)sval); + case 20: + return (SemanticValue)dup_arrow_body((ast::nodes::ArrowBody*)sval); + case 21: + return (SemanticValue)dup_function_body((grammarSupport::FunctionBody*)sval); + case 22: + return (SemanticValue)dup_scope((ast::nodes::Scope*)sval); + case 23: + return (SemanticValue)dup_statements((std::vector>*)sval); + case 24: + return (SemanticValue)dup_function_call((ast::nodes::FunctionCall*)sval); + case 25: + return (SemanticValue)dup_statement((ast::nodes::Statement*)sval); + case 26: + return (SemanticValue)dup_value_expr((ast::nodes::ValueExpr*)sval); + case 27: + return (SemanticValue)dup_parenthized_value((ast::nodes::ParenthizedValue*)sval); + case 28: + return (SemanticValue)dup_arguments((std::vector>*)sval); + case 29: + return (SemanticValue)dup_argument_list((std::vector>*)sval); + default: + return (SemanticValue)0; + } +} + +void ZaneParser::deallocateNontermValue(int nontermId, SemanticValue sval) +{ + switch (nontermId) { + case 2: + del_may_break((int)sval); + return; + case 3: + del_package((ast::nodes::Package*)sval); + return; + case 4: + del_global_scope((std::vector*)sval); + return; + case 5: + del_declaration((ast::nodes::Declaration*)sval); + return; + case 6: + del_variable_decl((ast::nodes::VariableDecl*)sval); + return; + case 7: + del_function_decl((ast::nodes::FunctionDecl*)sval); + return; + case 8: + del_method_decl((ast::nodes::MethodDecl*)sval); + return; + case 9: + del_parameters((std::vector*)sval); + return; + case 10: + del_parameter_list((std::vector*)sval); + return; + case 11: + del_method_parameters((std::vector*)sval); + return; + case 12: + del_method_parameter_seq((std::vector*)sval); + return; + case 13: + del_parameter((ast::nodes::Parameter*)sval); + return; + case 14: + del_type_list((std::vector>*)sval); + return; + case 15: + del_type_list_ne((std::vector>*)sval); + return; + case 16: + del_type_expr((ast::nodes::TypeExpression*)sval); + return; + case 17: + del_name_type((ast::nodes::NameType*)sval); + return; + case 18: + del_function_type((ast::nodes::FunctionType*)sval); + return; + case 19: + del_method_type((ast::nodes::MethodType*)sval); + return; + case 20: + del_arrow_body((ast::nodes::ArrowBody*)sval); + return; + case 21: + del_function_body((grammarSupport::FunctionBody*)sval); + return; + case 22: + del_scope((ast::nodes::Scope*)sval); + return; + case 23: + del_statements((std::vector>*)sval); + return; + case 24: + del_function_call((ast::nodes::FunctionCall*)sval); + return; + case 25: + del_statement((ast::nodes::Statement*)sval); + return; + case 26: + del_value_expr((ast::nodes::ValueExpr*)sval); + return; + case 27: + del_parenthized_value((ast::nodes::ParenthizedValue*)sval); + return; + case 28: + del_arguments((std::vector>*)sval); + return; + case 29: + del_argument_list((std::vector>*)sval); + return; + default: + std::cout << "WARNING: there is no action to deallocate nonterm " + << nontermNames[nontermId] << std::endl; + } +} + +SemanticValue ZaneParser::mergeAlternativeParses(int nontermId, SemanticValue left, + SemanticValue right, SourceLoc loc) +{ + switch (nontermId) { + default: + std::cout << toString(loc) + << ": error: there is no action to merge nonterm " + << nontermNames[nontermId] << std::endl; + abort(); + } +} + +bool ZaneParser::keepNontermValue(int nontermId, SemanticValue sval) +{ + switch (nontermId) { + default: + return true; + } +} + + +// ---------------- dup/del/classify terminals --------------- +inline std::string* ZaneParser::dup_TOK_STRING(std::string* s) +#line 91 "src/grammar/parser.gr" +{return new std::string(*s); } +#line 1236 "src/grammar/parser.cc" + +inline void ZaneParser::del_TOK_STRING(std::string* s) +#line 92 "src/grammar/parser.gr" +{delete s; } +#line 1241 "src/grammar/parser.cc" + +inline std::string* ZaneParser::dup_TOK_IDENT(std::string* s) +#line 95 "src/grammar/parser.gr" +{return new std::string(*s); } +#line 1246 "src/grammar/parser.cc" + +inline void ZaneParser::del_TOK_IDENT(std::string* s) +#line 96 "src/grammar/parser.gr" +{delete s; } +#line 1251 "src/grammar/parser.cc" + +inline std::string* ZaneParser::dup_TOK_INT(std::string* s) +#line 99 "src/grammar/parser.gr" +{return new std::string(*s); } +#line 1256 "src/grammar/parser.cc" + +inline void ZaneParser::del_TOK_INT(std::string* s) +#line 100 "src/grammar/parser.gr" +{delete s; } +#line 1261 "src/grammar/parser.cc" + +inline std::string* ZaneParser::dup_TOK_FLOAT(std::string* s) +#line 103 "src/grammar/parser.gr" +{return new std::string(*s); } +#line 1266 "src/grammar/parser.cc" + +inline void ZaneParser::del_TOK_FLOAT(std::string* s) +#line 104 "src/grammar/parser.gr" +{delete s; } +#line 1271 "src/grammar/parser.cc" + +SemanticValue ZaneParser::duplicateTerminalValue(int termId, SemanticValue sval) +{ + switch (termId) { + case 0: + return sval; + case 1: + return sval; + case 2: + return sval; + case 3: + return sval; + case 4: + return sval; + case 5: + return sval; + case 6: + return sval; + case 7: + return sval; + case 8: + return sval; + case 9: + return sval; + case 10: + return sval; + case 11: + return sval; + case 12: + return sval; + case 13: + return sval; + case 14: + return (SemanticValue)dup_TOK_STRING((std::string*)sval); + case 15: + return (SemanticValue)dup_TOK_IDENT((std::string*)sval); + case 16: + return (SemanticValue)dup_TOK_INT((std::string*)sval); + case 17: + return (SemanticValue)dup_TOK_FLOAT((std::string*)sval); + case 18: + return sval; + case 19: + return sval; + case 20: + return sval; + case 21: + return sval; + case 22: + return sval; + case 23: + return sval; + case 24: + return sval; + default: + return (SemanticValue)0; + } +} + +void ZaneParser::deallocateTerminalValue(int termId, SemanticValue sval) +{ + switch (termId) { + case 0: + break; + case 1: + break; + case 2: + break; + case 3: + break; + case 4: + break; + case 5: + break; + case 6: + break; + case 7: + break; + case 8: + break; + case 9: + break; + case 10: + break; + case 11: + break; + case 12: + break; + case 13: + break; + case 14: + del_TOK_STRING((std::string*)sval); + return; + case 15: + del_TOK_IDENT((std::string*)sval); + return; + case 16: + del_TOK_INT((std::string*)sval); + return; + case 17: + del_TOK_FLOAT((std::string*)sval); + return; + case 18: + break; + case 19: + break; + case 20: + break; + case 21: + break; + case 22: + break; + case 23: + break; + case 24: + break; + default: + int arrayMin = 0; + int arrayMax = 25; + xassert(termId >= arrayMin && termId < arrayMax); + std::cout << "WARNING: there is no action to deallocate terminal " + << termNames[termId] << std::endl; + } +} + +/*static*/ int ZaneParser::reclassifyToken(ZaneParser *ths, int oldTokenType, SemanticValue sval) +{ + switch (oldTokenType) { + default: + return oldTokenType; + } +} + +UserActions::ReclassifyFunc ZaneParser::getReclassifier() +{ + return (ReclassifyFunc)&ZaneParser::reclassifyToken; +} + + +// this makes a ParseTables from some literal data; +// the code is written by ParseTables::emitConstructionCode() +// in /build/source/src/elkhound/parsetables.cc +class ZaneParser_ParseTables : public ParseTables { +public: + ZaneParser_ParseTables(); +}; + +ZaneParser_ParseTables::ZaneParser_ParseTables() + : ParseTables(false /*owning*/) +{ + numTerms = 25; + numNonterms = 30; + numStates = 4; + numProds = 59; + actionCols = 25; + actionRows = 4; + gotoCols = 30; + gotoRows = 4; + ambigTableSize = 0; + startState = (StateId)0; + finalProductionIndex = 0; + bigProductionListSize = 0; + errorBitsRowSize = 4; + uniqueErrorRows = 0; + + // storage size: 200 bytes + // rows: 4 cols: 25 + static ActionEntry const actionTable_static[100] = { + /*0*/ -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, + /*1*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /*2*/ -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /*3*/ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + actionTable = const_cast(actionTable_static); + + // storage size: 240 bytes + // rows: 4 cols: 30 + static GotoEntry const gotoTable_static[120] = { + /*0*/ 65535, 65535, 3, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /*1*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /*2*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + /*3*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + }; + gotoTable = const_cast(gotoTable_static); + + // storage size: 236 bytes + static ParseTables::ProdInfo const prodInfo_static[59] = { + /*0*/ {2,1}, {0,2}, {1,2}, {3,3}, {0,4}, {1,4}, {3,4}, {1,5}, {1,5}, {4,6}, {6,7}, {6,8}, {7,8}, {0,9}, {1,9}, {1,10}, + /*1*/ {3,10}, {1,11}, {2,12}, {3,12}, {2,13}, {0,14}, {1,14}, {1,15}, {3,15}, {1,16}, {1,16}, {1,16}, {1,17}, {5,18}, {6,19}, {7,19}, + /*2*/ {2,20}, {1,21}, {1,21}, {5,22}, {0,23}, {3,23}, {4,24}, {1,25}, {1,25}, {1,26}, {3,26}, {4,26}, {1,26}, {1,26}, {1,26}, {1,26}, + /*3*/ {1,26}, {2,26}, {3,26}, {3,26}, {3,26}, {3,26}, {3,27}, {0,28}, {1,28}, {1,29}, {3,29}, + }; + prodInfo = const_cast(prodInfo_static); + + static SymbolId const stateSymbol_static[4] = { + /*0*/ 0, 1, 24, -3, + }; + stateSymbol = const_cast(stateSymbol_static); + + ActionEntry *ambigTable_static = NULL; + ambigTable = const_cast(ambigTable_static); + + // storage size: 60 bytes + static NtIndex const nontermOrder_static[30] = { + /*0*/ 22, 21, 28, 29, 27, 20, 18, 17, 16, 26, 15, 14, 13, 12, 25, 11, + /*1*/ 10, 9, 8, 7, 5, 6, 4, 24, 1, 19, 2, 0, 23, 3, + }; + nontermOrder = const_cast(nontermOrder_static); + + ErrorBitsEntry *errorBits_static = NULL; + errorBits = const_cast(errorBits_static); + + errorBitsPointers = NULL; + + TermIndex *actionIndexMap_static = NULL; + actionIndexMap = const_cast(actionIndexMap_static); + + actionRowPointers = NULL; + + NtIndex *gotoIndexMap_static = NULL; + gotoIndexMap = const_cast(gotoIndexMap_static); + + gotoRowPointers = NULL; + + firstWithTerminal = NULL; + firstWithNonterminal = NULL; + bigProductionList = NULL; + productionsForState = NULL; + ambigStateTable = NULL; +} + + +ParseTables *ZaneParser::makeTables() +{ + return new ZaneParser_ParseTables; +} + diff --git a/src/grammar/parser.gr b/src/grammar/parser.gr index e1b5b48b..152cdcd8 100644 --- a/src/grammar/parser.gr +++ b/src/grammar/parser.gr @@ -84,7 +84,8 @@ terminals { 20 : TOK_STAR "*"; 21 : TOK_SLASH "/"; 22 : TOK_TILDE "~"; - 23 : TOK_ERROR; + 23 : TOK_LINEBREAK; + 24 : TOK_ERROR; token(std::string*) TOK_STRING { fun dup(s) [return new std::string(*s);] @@ -113,18 +114,30 @@ terminals { nonterm(ast::nodes::Package*) package { fun dup(p) [return p;] fun del(p) [] - -> declarations:global_scope { + -> may_break declarations:global_scope may_break { return new ast::nodes::Package(grammarSupport::takeValue(declarations)); } } +nonterm(int) may_break { + fun dup(p) [return p;] + fun del(p) [] + -> { return 0; } + -> TOK_LINEBREAK { return 0; } +} + nonterm(std::vector*) global_scope { fun dup(p) [return p;] fun del(p) [] -> { return new std::vector(); } - -> declarations:global_scope declaration:declaration { + -> declaration:declaration { + auto* list = new std::vector(); + list->push_back(grammarSupport::takeValue(declaration)); + return list; + } + -> declarations:global_scope TOK_LINEBREAK declaration:declaration { declarations->push_back(grammarSupport::takeValue(declaration)); return declarations; } @@ -349,7 +362,7 @@ nonterm(grammarSupport::FunctionBody*) function_body { nonterm(ast::nodes::Scope*) scope { fun dup(p) [return p;] fun del(p) [] - -> "{" statements:statements "}" { + -> "{" TOK_LINEBREAK statements:statements TOK_LINEBREAK "}" { return new ast::nodes::Scope(grammarSupport::takeValue(statements)); } } @@ -360,7 +373,7 @@ nonterm(std::vector>*) statements { -> { return new std::vector>(); } - -> list:statements statement:statement { + -> list:statements TOK_LINEBREAK statement:statement { list->push_back(grammarSupport::takePtr(statement)); return list; } diff --git a/src/grammar/parser.h b/src/grammar/parser.h new file mode 100644 index 00000000..3d996ff5 --- /dev/null +++ b/src/grammar/parser.h @@ -0,0 +1,222 @@ +// src/grammar/parser.h +// *** DO NOT EDIT BY HAND *** +// automatically generated by elkhound, from src/grammar/parser.gr + +#ifndef SRC_GRAMMAR_PARSER_H +#define SRC_GRAMMAR_PARSER_H + +#include "useract.h" // UserActions + + +#line 1 "src/grammar/parser.gr" + + #include "ast/.hpp" + #include + #include + #include + #include + #include + + namespace grammarSupport { + + using FunctionBody = std::variant; + + template + T takeValue(T* ptr) { + T value = std::move(*ptr); + delete ptr; + return value; + } + + template + std::unique_ptr takePtr(T* ptr) { + return std::unique_ptr(ptr); + } + + inline std::string takeString(std::string* ptr) { + std::string value = std::move(*ptr); + delete ptr; + return value; + } + + inline ast::nodes::ValueExpr* makeBinary( + std::string op, + ast::nodes::ValueExpr* left, + ast::nodes::ValueExpr* right + ) { + return new ast::nodes::ValueExpr( + ast::nodes::OperatorCall( + std::move(op), + takePtr(left), + takePtr(right) + ) + ); + } + + inline ast::nodes::ValueExpr* makeFlip(ast::nodes::ValueExpr* value) { + return new ast::nodes::ValueExpr(ast::nodes::OperatorFlipCall(takePtr(value))); + } + + inline ast::nodes::ValueExpr* wrapCall(ast::nodes::FunctionCall* call) { + return new ast::nodes::ValueExpr(takeValue(call)); + } + + } // namespace grammarSupport + +#line 67 "src/grammar/parser.h" + + +// parser context class +class +#line 58 "src/grammar/parser.gr" + ZaneParser : public UserActions { +public: + // generated parser hooks are added by Elkhound + +#line 77 "src/grammar/parser.h" + + +private: + USER_ACTION_FUNCTIONS // see useract.h + + // declare the actual action function + static SemanticValue doReductionAction( + ZaneParser *ths, + int productionId, SemanticValue const *semanticValues, + SourceLoc loc); + + // declare the classifier function + static int reclassifyToken( + ZaneParser *ths, + int oldTokenType, SemanticValue sval); + + int action0___EarlyStartSymbol(SourceLoc loc, int top); + int action1_may_break(SourceLoc loc); + int action2_may_break(SourceLoc loc); + ast::nodes::Package* action3_package(SourceLoc loc, std::vector* declarations); + std::vector* action4_global_scope(SourceLoc loc); + std::vector* action5_global_scope(SourceLoc loc, ast::nodes::Declaration* declaration); + std::vector* action6_global_scope(SourceLoc loc, std::vector* declarations, ast::nodes::Declaration* declaration); + ast::nodes::Declaration* action7_declaration(SourceLoc loc, ast::nodes::FunctionDecl* function); + ast::nodes::Declaration* action8_declaration(SourceLoc loc, ast::nodes::MethodDecl* method); + ast::nodes::VariableDecl* action9_variable_decl(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type, ast::nodes::ValueExpr* value); + ast::nodes::FunctionDecl* action10_function_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body); + ast::nodes::MethodDecl* action11_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body); + ast::nodes::MethodDecl* action12_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body); + std::vector* action13_parameters(SourceLoc loc); + std::vector* action14_parameters(SourceLoc loc, std::vector* list); + std::vector* action15_parameter_list(SourceLoc loc, ast::nodes::Parameter* parameter); + std::vector* action16_parameter_list(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter); + std::vector* action17_method_parameters(SourceLoc loc, std::vector* list); + std::vector* action18_method_parameter_seq(SourceLoc loc, ast::nodes::TypeExpression* type); + std::vector* action19_method_parameter_seq(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter); + ast::nodes::Parameter* action20_parameter(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type); + std::vector>* action21_type_list(SourceLoc loc); + std::vector>* action22_type_list(SourceLoc loc, std::vector>* list); + std::vector>* action23_type_list_ne(SourceLoc loc, ast::nodes::TypeExpression* expr); + std::vector>* action24_type_list_ne(SourceLoc loc, std::vector>* list, ast::nodes::TypeExpression* expr); + ast::nodes::TypeExpression* action25_type_expr(SourceLoc loc, ast::nodes::NameType* name); + ast::nodes::TypeExpression* action26_type_expr(SourceLoc loc, ast::nodes::FunctionType* function); + ast::nodes::TypeExpression* action27_type_expr(SourceLoc loc, ast::nodes::MethodType* method); + ast::nodes::NameType* action28_name_type(SourceLoc loc, std::string* identifier); + ast::nodes::FunctionType* action29_function_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); + ast::nodes::MethodType* action30_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); + ast::nodes::MethodType* action31_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); + ast::nodes::ArrowBody* action32_arrow_body(SourceLoc loc, ast::nodes::ValueExpr* value); + grammarSupport::FunctionBody* action33_function_body(SourceLoc loc, ast::nodes::ArrowBody* body); + grammarSupport::FunctionBody* action34_function_body(SourceLoc loc, ast::nodes::Scope* body); + ast::nodes::Scope* action35_scope(SourceLoc loc, std::vector>* statements); + std::vector>* action36_statements(SourceLoc loc); + std::vector>* action37_statements(SourceLoc loc, std::vector>* list, ast::nodes::Statement* statement); + ast::nodes::FunctionCall* action38_function_call(SourceLoc loc, ast::nodes::ValueExpr* callee, std::vector>* args); + ast::nodes::Statement* action39_statement(SourceLoc loc, ast::nodes::FunctionCall* call); + ast::nodes::Statement* action40_statement(SourceLoc loc, ast::nodes::VariableDecl* declaration); + ast::nodes::ValueExpr* action41_value_expr(SourceLoc loc, std::string* identifier); + ast::nodes::ValueExpr* action42_value_expr(SourceLoc loc, std::string* package, std::string* identifier); + ast::nodes::ValueExpr* action43_value_expr(SourceLoc loc, std::string* package, std::string* identifier); + ast::nodes::ValueExpr* action44_value_expr(SourceLoc loc, std::string* integer); + ast::nodes::ValueExpr* action45_value_expr(SourceLoc loc, std::string* number); + ast::nodes::ValueExpr* action46_value_expr(SourceLoc loc, std::string* text); + ast::nodes::ValueExpr* action47_value_expr(SourceLoc loc, ast::nodes::ParenthizedValue* value); + ast::nodes::ValueExpr* action48_value_expr(SourceLoc loc, ast::nodes::FunctionCall* call); + ast::nodes::ValueExpr* action49_value_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); + ast::nodes::ValueExpr* action50_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); + ast::nodes::ValueExpr* action51_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); + ast::nodes::ValueExpr* action52_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); + ast::nodes::ValueExpr* action53_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); + ast::nodes::ParenthizedValue* action54_parenthized_value(SourceLoc loc, ast::nodes::ValueExpr* value); + std::vector>* action55_arguments(SourceLoc loc); + std::vector>* action56_arguments(SourceLoc loc, std::vector>* list); + std::vector>* action57_argument_list(SourceLoc loc, ast::nodes::ValueExpr* value); + std::vector>* action58_argument_list(SourceLoc loc, std::vector>* list, ast::nodes::ValueExpr* value); + inline int dup_may_break(int p) ; + inline void del_may_break(int p) ; + inline ast::nodes::Package* dup_package(ast::nodes::Package* p) ; + inline void del_package(ast::nodes::Package* p) ; + inline std::vector* dup_global_scope(std::vector* p) ; + inline void del_global_scope(std::vector* p) ; + inline ast::nodes::Declaration* dup_declaration(ast::nodes::Declaration* p) ; + inline void del_declaration(ast::nodes::Declaration* p) ; + inline ast::nodes::VariableDecl* dup_variable_decl(ast::nodes::VariableDecl* p) ; + inline void del_variable_decl(ast::nodes::VariableDecl* p) ; + inline ast::nodes::FunctionDecl* dup_function_decl(ast::nodes::FunctionDecl* p) ; + inline void del_function_decl(ast::nodes::FunctionDecl* p) ; + inline ast::nodes::MethodDecl* dup_method_decl(ast::nodes::MethodDecl* p) ; + inline void del_method_decl(ast::nodes::MethodDecl* p) ; + inline std::vector* dup_parameters(std::vector* p) ; + inline void del_parameters(std::vector* p) ; + inline std::vector* dup_parameter_list(std::vector* p) ; + inline void del_parameter_list(std::vector* p) ; + inline std::vector* dup_method_parameters(std::vector* p) ; + inline void del_method_parameters(std::vector* p) ; + inline std::vector* dup_method_parameter_seq(std::vector* p) ; + inline void del_method_parameter_seq(std::vector* p) ; + inline ast::nodes::Parameter* dup_parameter(ast::nodes::Parameter* p) ; + inline void del_parameter(ast::nodes::Parameter* p) ; + inline std::vector>* dup_type_list(std::vector>* p) ; + inline void del_type_list(std::vector>* p) ; + inline std::vector>* dup_type_list_ne(std::vector>* p) ; + inline void del_type_list_ne(std::vector>* p) ; + inline ast::nodes::TypeExpression* dup_type_expr(ast::nodes::TypeExpression* p) ; + inline void del_type_expr(ast::nodes::TypeExpression* p) ; + inline ast::nodes::NameType* dup_name_type(ast::nodes::NameType* p) ; + inline void del_name_type(ast::nodes::NameType* p) ; + inline ast::nodes::FunctionType* dup_function_type(ast::nodes::FunctionType* p) ; + inline void del_function_type(ast::nodes::FunctionType* p) ; + inline ast::nodes::MethodType* dup_method_type(ast::nodes::MethodType* p) ; + inline void del_method_type(ast::nodes::MethodType* p) ; + inline ast::nodes::ArrowBody* dup_arrow_body(ast::nodes::ArrowBody* p) ; + inline void del_arrow_body(ast::nodes::ArrowBody* p) ; + inline grammarSupport::FunctionBody* dup_function_body(grammarSupport::FunctionBody* p) ; + inline void del_function_body(grammarSupport::FunctionBody* p) ; + inline ast::nodes::Scope* dup_scope(ast::nodes::Scope* p) ; + inline void del_scope(ast::nodes::Scope* p) ; + inline std::vector>* dup_statements(std::vector>* p) ; + inline void del_statements(std::vector>* p) ; + inline ast::nodes::FunctionCall* dup_function_call(ast::nodes::FunctionCall* p) ; + inline void del_function_call(ast::nodes::FunctionCall* p) ; + inline ast::nodes::Statement* dup_statement(ast::nodes::Statement* p) ; + inline void del_statement(ast::nodes::Statement* p) ; + inline ast::nodes::ValueExpr* dup_value_expr(ast::nodes::ValueExpr* p) ; + inline void del_value_expr(ast::nodes::ValueExpr* p) ; + inline ast::nodes::ParenthizedValue* dup_parenthized_value(ast::nodes::ParenthizedValue* p) ; + inline void del_parenthized_value(ast::nodes::ParenthizedValue* p) ; + inline std::vector>* dup_arguments(std::vector>* p) ; + inline void del_arguments(std::vector>* p) ; + inline std::vector>* dup_argument_list(std::vector>* p) ; + inline void del_argument_list(std::vector>* p) ; + inline std::string* dup_TOK_STRING(std::string* s) ; + inline void del_TOK_STRING(std::string* s) ; + inline std::string* dup_TOK_IDENT(std::string* s) ; + inline void del_TOK_IDENT(std::string* s) ; + inline std::string* dup_TOK_INT(std::string* s) ; + inline void del_TOK_INT(std::string* s) ; + inline std::string* dup_TOK_FLOAT(std::string* s) ; + inline void del_TOK_FLOAT(std::string* s) ; + +// the function which makes the parse tables +public: + virtual ParseTables *makeTables(); +}; + +#endif // SRC_GRAMMAR_PARSER_H From 46823f80f5d01f7352c0ee75b9c4b7b44fc98215 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 12:01:28 +0200 Subject: [PATCH 063/154] update --- src/grammar/parser.gr | 5 +++++ test-parser/main.zn | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/grammar/parser.gr b/src/grammar/parser.gr index 152cdcd8..6feaba40 100644 --- a/src/grammar/parser.gr +++ b/src/grammar/parser.gr @@ -373,6 +373,11 @@ nonterm(std::vector>*) statements { -> { return new std::vector>(); } + -> statement:statement { + auto* list = new std::vector>(); + list->push_back(grammarSupport::takePtr(statement)); + return list; + } -> list:statements TOK_LINEBREAK statement:statement { list->push_back(grammarSupport::takePtr(statement)); return list; diff --git a/test-parser/main.zn b/test-parser/main.zn index 529e5f82..046c3a90 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,11 +1,10 @@ Void main(this Int, a Bool) { print(2, 2) - Std$print(1 + 1 3 + 4) + Std$print(1 + 1 + 3 + 4) @Intrinsics$print("hello") test Int = 3 func (this Int) -> Void = 3.0 } - Int getNum() { print() } From 25110e66e63456def51f399e1e2da9697c73e00e Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 13:25:21 +0200 Subject: [PATCH 064/154] stop tracking --- src/grammar/parser.cc | 1507 ----------------------------------------- src/grammar/parser.h | 222 ------ 2 files changed, 1729 deletions(-) delete mode 100644 src/grammar/parser.cc delete mode 100644 src/grammar/parser.h diff --git a/src/grammar/parser.cc b/src/grammar/parser.cc deleted file mode 100644 index 1c89ea1c..00000000 --- a/src/grammar/parser.cc +++ /dev/null @@ -1,1507 +0,0 @@ -// src/grammar/parser.cc -// *** DO NOT EDIT BY HAND *** -// automatically generated by gramanl, from src/grammar/parser.gr - -// GLR source location information is enabled - -#include "parser.h" // ZaneParser -#include "parsetables.h" // ParseTables -#include "srcloc.h" // SourceLoc - -#include // assert -#include // std::cout -#include // abort - -static char const *termNames[] = { - "TOK_EOF", // 0 - "TOK_LPAREN", // 1 - "TOK_RPAREN", // 2 - "TOK_LCURLY", // 3 - "TOK_RCURLY", // 4 - "TOK_COMMA", // 5 - "TOK_COLON", // 6 - "TOK_EQUAL", // 7 - "TOK_DOLLAR", // 8 - "TOK_THIN_ARROW", // 9 - "TOK_THICK_ARROW", // 10 - "TOK_AT", // 11 - "TOK_MUT", // 12 - "TOK_THIS", // 13 - "TOK_STRING", // 14 - "TOK_IDENT", // 15 - "TOK_INT", // 16 - "TOK_FLOAT", // 17 - "TOK_PLUS", // 18 - "TOK_MINUS", // 19 - "TOK_STAR", // 20 - "TOK_SLASH", // 21 - "TOK_TILDE", // 22 - "TOK_LINEBREAK", // 23 - "TOK_ERROR", // 24 -}; - -string ZaneParser::terminalDescription(int termId, SemanticValue sval) -{ - return stringc << termNames[termId] - << "(" << (sval % 100000) << ")"; -} - - -static char const *nontermNames[] = { - "empty", // 0 - "__EarlyStartSymbol", // 1 - "may_break", // 2 - "package", // 3 - "global_scope", // 4 - "declaration", // 5 - "variable_decl", // 6 - "function_decl", // 7 - "method_decl", // 8 - "parameters", // 9 - "parameter_list", // 10 - "method_parameters", // 11 - "method_parameter_seq", // 12 - "parameter", // 13 - "type_list", // 14 - "type_list_ne", // 15 - "type_expr", // 16 - "name_type", // 17 - "function_type", // 18 - "method_type", // 19 - "arrow_body", // 20 - "function_body", // 21 - "scope", // 22 - "statements", // 23 - "function_call", // 24 - "statement", // 25 - "value_expr", // 26 - "parenthized_value", // 27 - "arguments", // 28 - "argument_list", // 29 -}; - -string ZaneParser::nonterminalDescription(int nontermId, SemanticValue sval) -{ - return stringc << nontermNames[nontermId] - << "(" << (sval % 100000) << ")"; -} - - -char const *ZaneParser::terminalName(int termId) -{ - return termNames[termId]; -} - -char const *ZaneParser::nonterminalName(int nontermId) -{ - return nontermNames[nontermId]; -} - -// ------------------- actions ------------------ -// [0] __EarlyStartSymbol[int] -> top:may_break TOK_EOF -inline int ZaneParser::action0___EarlyStartSymbol(SourceLoc loc, int top) -#line 1 "" -{ return top; } -#line 106 "src/grammar/parser.cc" - -// [1] may_break[int] -> empty -inline int ZaneParser::action1_may_break(SourceLoc loc) -#line 117 "src/grammar/parser.gr" -{ return 0; } -#line 112 "src/grammar/parser.cc" - -// [2] may_break[int] -> TOK_LINEBREAK -inline int ZaneParser::action2_may_break(SourceLoc loc) -#line 118 "src/grammar/parser.gr" -{ return 0; } -#line 118 "src/grammar/parser.cc" - -// [3] package[ast::nodes::Package*] -> may_break declarations:global_scope may_break -inline ast::nodes::Package* ZaneParser::action3_package(SourceLoc loc, std::vector* declarations) -#line 124 "src/grammar/parser.gr" -{ - return new ast::nodes::Package(grammarSupport::takeValue(declarations)); - } -#line 126 "src/grammar/parser.cc" - -// [4] global_scope[std::vector*] -> empty -inline std::vector* ZaneParser::action4_global_scope(SourceLoc loc) -#line 132 "src/grammar/parser.gr" -{ - return new std::vector(); - } -#line 134 "src/grammar/parser.cc" - -// [5] global_scope[std::vector*] -> declaration:declaration -inline std::vector* ZaneParser::action5_global_scope(SourceLoc loc, ast::nodes::Declaration* declaration) -#line 135 "src/grammar/parser.gr" -{ - auto* list = new std::vector(); - list->push_back(grammarSupport::takeValue(declaration)); - return list; - } -#line 144 "src/grammar/parser.cc" - -// [6] global_scope[std::vector*] -> declarations:global_scope TOK_LINEBREAK declaration:declaration -inline std::vector* ZaneParser::action6_global_scope(SourceLoc loc, std::vector* declarations, ast::nodes::Declaration* declaration) -#line 140 "src/grammar/parser.gr" -{ - declarations->push_back(grammarSupport::takeValue(declaration)); - return declarations; - } -#line 153 "src/grammar/parser.cc" - -// [7] declaration[ast::nodes::Declaration*] -> function:function_decl -inline ast::nodes::Declaration* ZaneParser::action7_declaration(SourceLoc loc, ast::nodes::FunctionDecl* function) -#line 149 "src/grammar/parser.gr" -{ - return new ast::nodes::Declaration(grammarSupport::takeValue(function)); - } -#line 161 "src/grammar/parser.cc" - -// [8] declaration[ast::nodes::Declaration*] -> method:method_decl -inline ast::nodes::Declaration* ZaneParser::action8_declaration(SourceLoc loc, ast::nodes::MethodDecl* method) -#line 152 "src/grammar/parser.gr" -{ - return new ast::nodes::Declaration(grammarSupport::takeValue(method)); - } -#line 169 "src/grammar/parser.cc" - -// [9] variable_decl[ast::nodes::VariableDecl*] -> name:TOK_IDENT type:type_expr = value:value_expr -inline ast::nodes::VariableDecl* ZaneParser::action9_variable_decl(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type, ast::nodes::ValueExpr* value) -#line 160 "src/grammar/parser.gr" -{ - return new ast::nodes::VariableDecl( - grammarSupport::takeString(name), - grammarSupport::takeValue(type), - grammarSupport::takePtr(value) - ); - } -#line 181 "src/grammar/parser.cc" - -// [10] function_decl[ast::nodes::FunctionDecl*] -> return_type:type_expr name:TOK_IDENT ( params:parameters ) body:function_body -inline ast::nodes::FunctionDecl* ZaneParser::action10_function_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body) -#line 172 "src/grammar/parser.gr" -{ - return new ast::nodes::FunctionDecl( - grammarSupport::takeString(name), - grammarSupport::takeValue(params), - grammarSupport::takeValue(return_type), - grammarSupport::takeValue(body) - ); - } -#line 194 "src/grammar/parser.cc" - -// [11] method_decl[ast::nodes::MethodDecl*] -> return_type:type_expr name:TOK_IDENT ( params:method_parameters ) body:function_body -inline ast::nodes::MethodDecl* ZaneParser::action11_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body) -#line 185 "src/grammar/parser.gr" -{ - return new ast::nodes::MethodDecl( - grammarSupport::takeString(name), - grammarSupport::takeValue(params), - grammarSupport::takeValue(return_type), - grammarSupport::takeValue(body), - false - ); - } -#line 208 "src/grammar/parser.cc" - -// [12] method_decl[ast::nodes::MethodDecl*] -> return_type:type_expr name:TOK_IDENT ( params:method_parameters ) mut body:function_body -inline ast::nodes::MethodDecl* ZaneParser::action12_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body) -#line 194 "src/grammar/parser.gr" -{ - return new ast::nodes::MethodDecl( - grammarSupport::takeString(name), - grammarSupport::takeValue(params), - grammarSupport::takeValue(return_type), - grammarSupport::takeValue(body), - true - ); - } -#line 222 "src/grammar/parser.cc" - -// [13] parameters[std::vector*] -> empty -inline std::vector* ZaneParser::action13_parameters(SourceLoc loc) -#line 208 "src/grammar/parser.gr" -{ - return new std::vector(); - } -#line 230 "src/grammar/parser.cc" - -// [14] parameters[std::vector*] -> list:parameter_list -inline std::vector* ZaneParser::action14_parameters(SourceLoc loc, std::vector* list) -#line 211 "src/grammar/parser.gr" -{ - return list; - } -#line 238 "src/grammar/parser.cc" - -// [15] parameter_list[std::vector*] -> parameter:parameter -inline std::vector* ZaneParser::action15_parameter_list(SourceLoc loc, ast::nodes::Parameter* parameter) -#line 219 "src/grammar/parser.gr" -{ - auto* list = new std::vector(); - list->push_back(grammarSupport::takeValue(parameter)); - return list; - } -#line 248 "src/grammar/parser.cc" - -// [16] parameter_list[std::vector*] -> list:parameter_list , parameter:parameter -inline std::vector* ZaneParser::action16_parameter_list(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter) -#line 224 "src/grammar/parser.gr" -{ - list->push_back(grammarSupport::takeValue(parameter)); - return list; - } -#line 257 "src/grammar/parser.cc" - -// [17] method_parameters[std::vector*] -> list:method_parameter_seq -inline std::vector* ZaneParser::action17_method_parameters(SourceLoc loc, std::vector* list) -#line 233 "src/grammar/parser.gr" -{ - return list; - } -#line 265 "src/grammar/parser.cc" - -// [18] method_parameter_seq[std::vector*] -> this type:type_expr -inline std::vector* ZaneParser::action18_method_parameter_seq(SourceLoc loc, ast::nodes::TypeExpression* type) -#line 241 "src/grammar/parser.gr" -{ - auto* list = new std::vector(); - list->push_back(ast::nodes::Parameter(grammarSupport::takePtr(type), "this")); - return list; - } -#line 275 "src/grammar/parser.cc" - -// [19] method_parameter_seq[std::vector*] -> list:method_parameter_seq , parameter:parameter -inline std::vector* ZaneParser::action19_method_parameter_seq(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter) -#line 246 "src/grammar/parser.gr" -{ - list->push_back(grammarSupport::takeValue(parameter)); - return list; - } -#line 284 "src/grammar/parser.cc" - -// [20] parameter[ast::nodes::Parameter*] -> name:TOK_IDENT type:type_expr -inline ast::nodes::Parameter* ZaneParser::action20_parameter(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type) -#line 255 "src/grammar/parser.gr" -{ - return new ast::nodes::Parameter( - grammarSupport::takePtr(type), - grammarSupport::takeString(name) - ); - } -#line 295 "src/grammar/parser.cc" - -// [21] type_list[std::vector>*] -> empty -inline std::vector>* ZaneParser::action21_type_list(SourceLoc loc) -#line 266 "src/grammar/parser.gr" -{ - return new std::vector>(); - } -#line 303 "src/grammar/parser.cc" - -// [22] type_list[std::vector>*] -> list:type_list_ne -inline std::vector>* ZaneParser::action22_type_list(SourceLoc loc, std::vector>* list) -#line 269 "src/grammar/parser.gr" -{ - return list; - } -#line 311 "src/grammar/parser.cc" - -// [23] type_list_ne[std::vector>*] -> expr:type_expr -inline std::vector>* ZaneParser::action23_type_list_ne(SourceLoc loc, ast::nodes::TypeExpression* expr) -#line 277 "src/grammar/parser.gr" -{ - auto* list = new std::vector>(); - list->push_back(grammarSupport::takePtr(expr)); - return list; - } -#line 321 "src/grammar/parser.cc" - -// [24] type_list_ne[std::vector>*] -> list:type_list_ne , expr:type_expr -inline std::vector>* ZaneParser::action24_type_list_ne(SourceLoc loc, std::vector>* list, ast::nodes::TypeExpression* expr) -#line 282 "src/grammar/parser.gr" -{ - list->push_back(grammarSupport::takePtr(expr)); - return list; - } -#line 330 "src/grammar/parser.cc" - -// [25] type_expr[ast::nodes::TypeExpression*] -> name:name_type -inline ast::nodes::TypeExpression* ZaneParser::action25_type_expr(SourceLoc loc, ast::nodes::NameType* name) -#line 291 "src/grammar/parser.gr" -{ - return new ast::nodes::TypeExpression(grammarSupport::takeValue(name)); - } -#line 338 "src/grammar/parser.cc" - -// [26] type_expr[ast::nodes::TypeExpression*] -> function:function_type -inline ast::nodes::TypeExpression* ZaneParser::action26_type_expr(SourceLoc loc, ast::nodes::FunctionType* function) -#line 294 "src/grammar/parser.gr" -{ - return new ast::nodes::TypeExpression(grammarSupport::takeValue(function)); - } -#line 346 "src/grammar/parser.cc" - -// [27] type_expr[ast::nodes::TypeExpression*] -> method:method_type -inline ast::nodes::TypeExpression* ZaneParser::action27_type_expr(SourceLoc loc, ast::nodes::MethodType* method) -#line 297 "src/grammar/parser.gr" -{ - return new ast::nodes::TypeExpression(grammarSupport::takeValue(method)); - } -#line 354 "src/grammar/parser.cc" - -// [28] name_type[ast::nodes::NameType*] -> identifier:TOK_IDENT -inline ast::nodes::NameType* ZaneParser::action28_name_type(SourceLoc loc, std::string* identifier) -#line 305 "src/grammar/parser.gr" -{ - return new ast::nodes::NameType( - grammarSupport::takeString(identifier), - std::vector>() - ); - } -#line 365 "src/grammar/parser.cc" - -// [29] function_type[ast::nodes::FunctionType*] -> ( params:type_list ) -> return_type:type_expr -inline ast::nodes::FunctionType* ZaneParser::action29_function_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) -#line 316 "src/grammar/parser.gr" -{ - return new ast::nodes::FunctionType( - grammarSupport::takeValue(params), - grammarSupport::takePtr(return_type) - ); - } -#line 376 "src/grammar/parser.cc" - -// [30] method_type[ast::nodes::MethodType*] -> ( this params:type_list_ne ) -> return_type:type_expr -inline ast::nodes::MethodType* ZaneParser::action30_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) -#line 327 "src/grammar/parser.gr" -{ - return new ast::nodes::MethodType( - grammarSupport::takeValue(params), - grammarSupport::takePtr(return_type), - false - ); - } -#line 388 "src/grammar/parser.cc" - -// [31] method_type[ast::nodes::MethodType*] -> ( this params:type_list_ne ) mut -> return_type:type_expr -inline ast::nodes::MethodType* ZaneParser::action31_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type) -#line 334 "src/grammar/parser.gr" -{ - return new ast::nodes::MethodType( - grammarSupport::takeValue(params), - grammarSupport::takePtr(return_type), - true - ); - } -#line 400 "src/grammar/parser.cc" - -// [32] arrow_body[ast::nodes::ArrowBody*] -> => value:value_expr -inline ast::nodes::ArrowBody* ZaneParser::action32_arrow_body(SourceLoc loc, ast::nodes::ValueExpr* value) -#line 346 "src/grammar/parser.gr" -{ - return new ast::nodes::ArrowBody(grammarSupport::takePtr(value)); - } -#line 408 "src/grammar/parser.cc" - -// [33] function_body[grammarSupport::FunctionBody*] -> body:arrow_body -inline grammarSupport::FunctionBody* ZaneParser::action33_function_body(SourceLoc loc, ast::nodes::ArrowBody* body) -#line 354 "src/grammar/parser.gr" -{ - return new grammarSupport::FunctionBody(grammarSupport::takeValue(body)); - } -#line 416 "src/grammar/parser.cc" - -// [34] function_body[grammarSupport::FunctionBody*] -> body:scope -inline grammarSupport::FunctionBody* ZaneParser::action34_function_body(SourceLoc loc, ast::nodes::Scope* body) -#line 357 "src/grammar/parser.gr" -{ - return new grammarSupport::FunctionBody(grammarSupport::takeValue(body)); - } -#line 424 "src/grammar/parser.cc" - -// [35] scope[ast::nodes::Scope*] -> { TOK_LINEBREAK statements:statements TOK_LINEBREAK } -inline ast::nodes::Scope* ZaneParser::action35_scope(SourceLoc loc, std::vector>* statements) -#line 365 "src/grammar/parser.gr" -{ - return new ast::nodes::Scope(grammarSupport::takeValue(statements)); - } -#line 432 "src/grammar/parser.cc" - -// [36] statements[std::vector>*] -> empty -inline std::vector>* ZaneParser::action36_statements(SourceLoc loc) -#line 373 "src/grammar/parser.gr" -{ - return new std::vector>(); - } -#line 440 "src/grammar/parser.cc" - -// [37] statements[std::vector>*] -> list:statements TOK_LINEBREAK statement:statement -inline std::vector>* ZaneParser::action37_statements(SourceLoc loc, std::vector>* list, ast::nodes::Statement* statement) -#line 376 "src/grammar/parser.gr" -{ - list->push_back(grammarSupport::takePtr(statement)); - return list; - } -#line 449 "src/grammar/parser.cc" - -// [38] function_call[ast::nodes::FunctionCall*] -> callee:value_expr ( args:arguments ) -inline ast::nodes::FunctionCall* ZaneParser::action38_function_call(SourceLoc loc, ast::nodes::ValueExpr* callee, std::vector>* args) -#line 385 "src/grammar/parser.gr" -{ - return new ast::nodes::FunctionCall( - std::make_unique(grammarSupport::takeValue(callee)), - grammarSupport::takeValue(args) - ); - } -#line 460 "src/grammar/parser.cc" - -// [39] statement[ast::nodes::Statement*] -> call:function_call -inline ast::nodes::Statement* ZaneParser::action39_statement(SourceLoc loc, ast::nodes::FunctionCall* call) -#line 396 "src/grammar/parser.gr" -{ - return new ast::nodes::Statement(grammarSupport::takeValue(call)); - } -#line 468 "src/grammar/parser.cc" - -// [40] statement[ast::nodes::Statement*] -> declaration:variable_decl -inline ast::nodes::Statement* ZaneParser::action40_statement(SourceLoc loc, ast::nodes::VariableDecl* declaration) -#line 399 "src/grammar/parser.gr" -{ - return new ast::nodes::Statement(grammarSupport::takeValue(declaration)); - } -#line 476 "src/grammar/parser.cc" - -// [41] value_expr[ast::nodes::ValueExpr*] -> identifier:TOK_IDENT -inline ast::nodes::ValueExpr* ZaneParser::action41_value_expr(SourceLoc loc, std::string* identifier) -#line 407 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr(ast::nodes::ValueSymbol(grammarSupport::takeString(identifier))); - } -#line 484 "src/grammar/parser.cc" - -// [42] value_expr[ast::nodes::ValueExpr*] -> package:TOK_IDENT $ identifier:TOK_IDENT -inline ast::nodes::ValueExpr* ZaneParser::action42_value_expr(SourceLoc loc, std::string* package, std::string* identifier) -#line 410 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr( - ast::nodes::PackageValueSymbol( - grammarSupport::takeString(identifier), - grammarSupport::takeString(package) - ) - ); - } -#line 497 "src/grammar/parser.cc" - -// [43] value_expr[ast::nodes::ValueExpr*] -> @ package:TOK_IDENT $ identifier:TOK_IDENT -inline ast::nodes::ValueExpr* ZaneParser::action43_value_expr(SourceLoc loc, std::string* package, std::string* identifier) -#line 418 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr( - ast::nodes::IntrinsicValueSymbol( - grammarSupport::takeString(identifier), - grammarSupport::takeString(package) - ) - ); - } -#line 510 "src/grammar/parser.cc" - -// [44] value_expr[ast::nodes::ValueExpr*] -> integer:TOK_INT -inline ast::nodes::ValueExpr* ZaneParser::action44_value_expr(SourceLoc loc, std::string* integer) -#line 426 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr(ast::nodes::IntLiteral(grammarSupport::takeString(integer))); - } -#line 518 "src/grammar/parser.cc" - -// [45] value_expr[ast::nodes::ValueExpr*] -> number:TOK_FLOAT -inline ast::nodes::ValueExpr* ZaneParser::action45_value_expr(SourceLoc loc, std::string* number) -#line 429 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr(ast::nodes::FloatLiteral(grammarSupport::takeString(number))); - } -#line 526 "src/grammar/parser.cc" - -// [46] value_expr[ast::nodes::ValueExpr*] -> text:TOK_STRING -inline ast::nodes::ValueExpr* ZaneParser::action46_value_expr(SourceLoc loc, std::string* text) -#line 432 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr(ast::nodes::StringLiteral(grammarSupport::takeString(text))); - } -#line 534 "src/grammar/parser.cc" - -// [47] value_expr[ast::nodes::ValueExpr*] -> value:parenthized_value -inline ast::nodes::ValueExpr* ZaneParser::action47_value_expr(SourceLoc loc, ast::nodes::ParenthizedValue* value) -#line 435 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr(grammarSupport::takeValue(value)); - } -#line 542 "src/grammar/parser.cc" - -// [48] value_expr[ast::nodes::ValueExpr*] -> call:function_call -inline ast::nodes::ValueExpr* ZaneParser::action48_value_expr(SourceLoc loc, ast::nodes::FunctionCall* call) -#line 438 "src/grammar/parser.gr" -{ - return new ast::nodes::ValueExpr(grammarSupport::takeValue(call)); - } -#line 550 "src/grammar/parser.cc" - -// [49] value_expr[ast::nodes::ValueExpr*] -> ~ expr:value_expr %prec(30) -inline ast::nodes::ValueExpr* ZaneParser::action49_value_expr(SourceLoc loc, ast::nodes::ValueExpr* expr) -#line 441 "src/grammar/parser.gr" -{ - return grammarSupport::makeFlip(expr); - } -#line 558 "src/grammar/parser.cc" - -// [50] value_expr[ast::nodes::ValueExpr*] -> left:value_expr * right:value_expr %prec(20) -inline ast::nodes::ValueExpr* ZaneParser::action50_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) -#line 444 "src/grammar/parser.gr" -{ - return grammarSupport::makeBinary("*", left, right); - } -#line 566 "src/grammar/parser.cc" - -// [51] value_expr[ast::nodes::ValueExpr*] -> left:value_expr / right:value_expr %prec(20) -inline ast::nodes::ValueExpr* ZaneParser::action51_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) -#line 447 "src/grammar/parser.gr" -{ - return grammarSupport::makeBinary("/", left, right); - } -#line 574 "src/grammar/parser.cc" - -// [52] value_expr[ast::nodes::ValueExpr*] -> left:value_expr + right:value_expr %prec(10) -inline ast::nodes::ValueExpr* ZaneParser::action52_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) -#line 450 "src/grammar/parser.gr" -{ - return grammarSupport::makeBinary("+", left, right); - } -#line 582 "src/grammar/parser.cc" - -// [53] value_expr[ast::nodes::ValueExpr*] -> left:value_expr - right:value_expr %prec(10) -inline ast::nodes::ValueExpr* ZaneParser::action53_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right) -#line 453 "src/grammar/parser.gr" -{ - return grammarSupport::makeBinary("-", left, right); - } -#line 590 "src/grammar/parser.cc" - -// [54] parenthized_value[ast::nodes::ParenthizedValue*] -> ( value:value_expr ) -inline ast::nodes::ParenthizedValue* ZaneParser::action54_parenthized_value(SourceLoc loc, ast::nodes::ValueExpr* value) -#line 461 "src/grammar/parser.gr" -{ - return new ast::nodes::ParenthizedValue(grammarSupport::takePtr(value)); - } -#line 598 "src/grammar/parser.cc" - -// [55] arguments[std::vector>*] -> empty -inline std::vector>* ZaneParser::action55_arguments(SourceLoc loc) -#line 469 "src/grammar/parser.gr" -{ - return new std::vector>(); - } -#line 606 "src/grammar/parser.cc" - -// [56] arguments[std::vector>*] -> list:argument_list -inline std::vector>* ZaneParser::action56_arguments(SourceLoc loc, std::vector>* list) -#line 472 "src/grammar/parser.gr" -{ - return list; - } -#line 614 "src/grammar/parser.cc" - -// [57] argument_list[std::vector>*] -> value:value_expr -inline std::vector>* ZaneParser::action57_argument_list(SourceLoc loc, ast::nodes::ValueExpr* value) -#line 480 "src/grammar/parser.gr" -{ - auto* list = new std::vector>(); - list->push_back(grammarSupport::takePtr(value)); - return list; - } -#line 624 "src/grammar/parser.cc" - -// [58] argument_list[std::vector>*] -> list:argument_list , value:value_expr -inline std::vector>* ZaneParser::action58_argument_list(SourceLoc loc, std::vector>* list, ast::nodes::ValueExpr* value) -#line 485 "src/grammar/parser.gr" -{ - list->push_back(grammarSupport::takePtr(value)); - return list; - } -#line 633 "src/grammar/parser.cc" - - -/*static*/ SemanticValue ZaneParser::doReductionAction( - ZaneParser *ths, - int productionId, SemanticValue const *semanticValues, - SourceLoc loc) -{ - switch (productionId) { - case 0: - return (SemanticValue)(ths->action0___EarlyStartSymbol(loc, (int)(semanticValues[0]))); - case 1: - return (SemanticValue)(ths->action1_may_break(loc)); - case 2: - return (SemanticValue)(ths->action2_may_break(loc)); - case 3: - return (SemanticValue)(ths->action3_package(loc, (std::vector*)(semanticValues[1]))); - case 4: - return (SemanticValue)(ths->action4_global_scope(loc)); - case 5: - return (SemanticValue)(ths->action5_global_scope(loc, (ast::nodes::Declaration*)(semanticValues[0]))); - case 6: - return (SemanticValue)(ths->action6_global_scope(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Declaration*)(semanticValues[2]))); - case 7: - return (SemanticValue)(ths->action7_declaration(loc, (ast::nodes::FunctionDecl*)(semanticValues[0]))); - case 8: - return (SemanticValue)(ths->action8_declaration(loc, (ast::nodes::MethodDecl*)(semanticValues[0]))); - case 9: - return (SemanticValue)(ths->action9_variable_decl(loc, (std::string*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[1]), (ast::nodes::ValueExpr*)(semanticValues[3]))); - case 10: - return (SemanticValue)(ths->action10_function_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammarSupport::FunctionBody*)(semanticValues[5]))); - case 11: - return (SemanticValue)(ths->action11_method_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammarSupport::FunctionBody*)(semanticValues[5]))); - case 12: - return (SemanticValue)(ths->action12_method_decl(loc, (ast::nodes::TypeExpression*)(semanticValues[0]), (std::string*)(semanticValues[1]), (std::vector*)(semanticValues[3]), (grammarSupport::FunctionBody*)(semanticValues[6]))); - case 13: - return (SemanticValue)(ths->action13_parameters(loc)); - case 14: - return (SemanticValue)(ths->action14_parameters(loc, (std::vector*)(semanticValues[0]))); - case 15: - return (SemanticValue)(ths->action15_parameter_list(loc, (ast::nodes::Parameter*)(semanticValues[0]))); - case 16: - return (SemanticValue)(ths->action16_parameter_list(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Parameter*)(semanticValues[2]))); - case 17: - return (SemanticValue)(ths->action17_method_parameters(loc, (std::vector*)(semanticValues[0]))); - case 18: - return (SemanticValue)(ths->action18_method_parameter_seq(loc, (ast::nodes::TypeExpression*)(semanticValues[1]))); - case 19: - return (SemanticValue)(ths->action19_method_parameter_seq(loc, (std::vector*)(semanticValues[0]), (ast::nodes::Parameter*)(semanticValues[2]))); - case 20: - return (SemanticValue)(ths->action20_parameter(loc, (std::string*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[1]))); - case 21: - return (SemanticValue)(ths->action21_type_list(loc)); - case 22: - return (SemanticValue)(ths->action22_type_list(loc, (std::vector>*)(semanticValues[0]))); - case 23: - return (SemanticValue)(ths->action23_type_list_ne(loc, (ast::nodes::TypeExpression*)(semanticValues[0]))); - case 24: - return (SemanticValue)(ths->action24_type_list_ne(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::TypeExpression*)(semanticValues[2]))); - case 25: - return (SemanticValue)(ths->action25_type_expr(loc, (ast::nodes::NameType*)(semanticValues[0]))); - case 26: - return (SemanticValue)(ths->action26_type_expr(loc, (ast::nodes::FunctionType*)(semanticValues[0]))); - case 27: - return (SemanticValue)(ths->action27_type_expr(loc, (ast::nodes::MethodType*)(semanticValues[0]))); - case 28: - return (SemanticValue)(ths->action28_name_type(loc, (std::string*)(semanticValues[0]))); - case 29: - return (SemanticValue)(ths->action29_function_type(loc, (std::vector>*)(semanticValues[1]), (ast::nodes::TypeExpression*)(semanticValues[4]))); - case 30: - return (SemanticValue)(ths->action30_method_type(loc, (std::vector>*)(semanticValues[2]), (ast::nodes::TypeExpression*)(semanticValues[5]))); - case 31: - return (SemanticValue)(ths->action31_method_type(loc, (std::vector>*)(semanticValues[2]), (ast::nodes::TypeExpression*)(semanticValues[6]))); - case 32: - return (SemanticValue)(ths->action32_arrow_body(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); - case 33: - return (SemanticValue)(ths->action33_function_body(loc, (ast::nodes::ArrowBody*)(semanticValues[0]))); - case 34: - return (SemanticValue)(ths->action34_function_body(loc, (ast::nodes::Scope*)(semanticValues[0]))); - case 35: - return (SemanticValue)(ths->action35_scope(loc, (std::vector>*)(semanticValues[2]))); - case 36: - return (SemanticValue)(ths->action36_statements(loc)); - case 37: - return (SemanticValue)(ths->action37_statements(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::Statement*)(semanticValues[2]))); - case 38: - return (SemanticValue)(ths->action38_function_call(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (std::vector>*)(semanticValues[2]))); - case 39: - return (SemanticValue)(ths->action39_statement(loc, (ast::nodes::FunctionCall*)(semanticValues[0]))); - case 40: - return (SemanticValue)(ths->action40_statement(loc, (ast::nodes::VariableDecl*)(semanticValues[0]))); - case 41: - return (SemanticValue)(ths->action41_value_expr(loc, (std::string*)(semanticValues[0]))); - case 42: - return (SemanticValue)(ths->action42_value_expr(loc, (std::string*)(semanticValues[0]), (std::string*)(semanticValues[2]))); - case 43: - return (SemanticValue)(ths->action43_value_expr(loc, (std::string*)(semanticValues[1]), (std::string*)(semanticValues[3]))); - case 44: - return (SemanticValue)(ths->action44_value_expr(loc, (std::string*)(semanticValues[0]))); - case 45: - return (SemanticValue)(ths->action45_value_expr(loc, (std::string*)(semanticValues[0]))); - case 46: - return (SemanticValue)(ths->action46_value_expr(loc, (std::string*)(semanticValues[0]))); - case 47: - return (SemanticValue)(ths->action47_value_expr(loc, (ast::nodes::ParenthizedValue*)(semanticValues[0]))); - case 48: - return (SemanticValue)(ths->action48_value_expr(loc, (ast::nodes::FunctionCall*)(semanticValues[0]))); - case 49: - return (SemanticValue)(ths->action49_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); - case 50: - return (SemanticValue)(ths->action50_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); - case 51: - return (SemanticValue)(ths->action51_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); - case 52: - return (SemanticValue)(ths->action52_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); - case 53: - return (SemanticValue)(ths->action53_value_expr(loc, (ast::nodes::ValueExpr*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); - case 54: - return (SemanticValue)(ths->action54_parenthized_value(loc, (ast::nodes::ValueExpr*)(semanticValues[1]))); - case 55: - return (SemanticValue)(ths->action55_arguments(loc)); - case 56: - return (SemanticValue)(ths->action56_arguments(loc, (std::vector>*)(semanticValues[0]))); - case 57: - return (SemanticValue)(ths->action57_argument_list(loc, (ast::nodes::ValueExpr*)(semanticValues[0]))); - case 58: - return (SemanticValue)(ths->action58_argument_list(loc, (std::vector>*)(semanticValues[0]), (ast::nodes::ValueExpr*)(semanticValues[2]))); - default: - assert(!"invalid production code"); - return (SemanticValue)0; // silence warning - } -} - -UserActions::ReductionActionFunc ZaneParser::getReductionAction() -{ - return (ReductionActionFunc)&ZaneParser::doReductionAction; -} - - -// ---------------- dup/del/merge/keep nonterminals --------------- - -inline int ZaneParser::dup_may_break(int p) -#line 115 "src/grammar/parser.gr" -{return p; } -#line 777 "src/grammar/parser.cc" - -inline void ZaneParser::del_may_break(int p) -#line 116 "src/grammar/parser.gr" -{ } -#line 782 "src/grammar/parser.cc" - -inline ast::nodes::Package* ZaneParser::dup_package(ast::nodes::Package* p) -#line 122 "src/grammar/parser.gr" -{return p; } -#line 787 "src/grammar/parser.cc" - -inline void ZaneParser::del_package(ast::nodes::Package* p) -#line 123 "src/grammar/parser.gr" -{ } -#line 792 "src/grammar/parser.cc" - -inline std::vector* ZaneParser::dup_global_scope(std::vector* p) -#line 130 "src/grammar/parser.gr" -{return p; } -#line 797 "src/grammar/parser.cc" - -inline void ZaneParser::del_global_scope(std::vector* p) -#line 131 "src/grammar/parser.gr" -{ } -#line 802 "src/grammar/parser.cc" - -inline ast::nodes::Declaration* ZaneParser::dup_declaration(ast::nodes::Declaration* p) -#line 147 "src/grammar/parser.gr" -{return p; } -#line 807 "src/grammar/parser.cc" - -inline void ZaneParser::del_declaration(ast::nodes::Declaration* p) -#line 148 "src/grammar/parser.gr" -{ } -#line 812 "src/grammar/parser.cc" - -inline ast::nodes::VariableDecl* ZaneParser::dup_variable_decl(ast::nodes::VariableDecl* p) -#line 158 "src/grammar/parser.gr" -{return p; } -#line 817 "src/grammar/parser.cc" - -inline void ZaneParser::del_variable_decl(ast::nodes::VariableDecl* p) -#line 159 "src/grammar/parser.gr" -{ } -#line 822 "src/grammar/parser.cc" - -inline ast::nodes::FunctionDecl* ZaneParser::dup_function_decl(ast::nodes::FunctionDecl* p) -#line 170 "src/grammar/parser.gr" -{return p; } -#line 827 "src/grammar/parser.cc" - -inline void ZaneParser::del_function_decl(ast::nodes::FunctionDecl* p) -#line 171 "src/grammar/parser.gr" -{ } -#line 832 "src/grammar/parser.cc" - -inline ast::nodes::MethodDecl* ZaneParser::dup_method_decl(ast::nodes::MethodDecl* p) -#line 183 "src/grammar/parser.gr" -{return p; } -#line 837 "src/grammar/parser.cc" - -inline void ZaneParser::del_method_decl(ast::nodes::MethodDecl* p) -#line 184 "src/grammar/parser.gr" -{ } -#line 842 "src/grammar/parser.cc" - -inline std::vector* ZaneParser::dup_parameters(std::vector* p) -#line 206 "src/grammar/parser.gr" -{return p; } -#line 847 "src/grammar/parser.cc" - -inline void ZaneParser::del_parameters(std::vector* p) -#line 207 "src/grammar/parser.gr" -{ } -#line 852 "src/grammar/parser.cc" - -inline std::vector* ZaneParser::dup_parameter_list(std::vector* p) -#line 217 "src/grammar/parser.gr" -{return p; } -#line 857 "src/grammar/parser.cc" - -inline void ZaneParser::del_parameter_list(std::vector* p) -#line 218 "src/grammar/parser.gr" -{ } -#line 862 "src/grammar/parser.cc" - -inline std::vector* ZaneParser::dup_method_parameters(std::vector* p) -#line 231 "src/grammar/parser.gr" -{return p; } -#line 867 "src/grammar/parser.cc" - -inline void ZaneParser::del_method_parameters(std::vector* p) -#line 232 "src/grammar/parser.gr" -{ } -#line 872 "src/grammar/parser.cc" - -inline std::vector* ZaneParser::dup_method_parameter_seq(std::vector* p) -#line 239 "src/grammar/parser.gr" -{return p; } -#line 877 "src/grammar/parser.cc" - -inline void ZaneParser::del_method_parameter_seq(std::vector* p) -#line 240 "src/grammar/parser.gr" -{ } -#line 882 "src/grammar/parser.cc" - -inline ast::nodes::Parameter* ZaneParser::dup_parameter(ast::nodes::Parameter* p) -#line 253 "src/grammar/parser.gr" -{return p; } -#line 887 "src/grammar/parser.cc" - -inline void ZaneParser::del_parameter(ast::nodes::Parameter* p) -#line 254 "src/grammar/parser.gr" -{ } -#line 892 "src/grammar/parser.cc" - -inline std::vector>* ZaneParser::dup_type_list(std::vector>* p) -#line 264 "src/grammar/parser.gr" -{return p; } -#line 897 "src/grammar/parser.cc" - -inline void ZaneParser::del_type_list(std::vector>* p) -#line 265 "src/grammar/parser.gr" -{ } -#line 902 "src/grammar/parser.cc" - -inline std::vector>* ZaneParser::dup_type_list_ne(std::vector>* p) -#line 275 "src/grammar/parser.gr" -{return p; } -#line 907 "src/grammar/parser.cc" - -inline void ZaneParser::del_type_list_ne(std::vector>* p) -#line 276 "src/grammar/parser.gr" -{ } -#line 912 "src/grammar/parser.cc" - -inline ast::nodes::TypeExpression* ZaneParser::dup_type_expr(ast::nodes::TypeExpression* p) -#line 289 "src/grammar/parser.gr" -{return p; } -#line 917 "src/grammar/parser.cc" - -inline void ZaneParser::del_type_expr(ast::nodes::TypeExpression* p) -#line 290 "src/grammar/parser.gr" -{ } -#line 922 "src/grammar/parser.cc" - -inline ast::nodes::NameType* ZaneParser::dup_name_type(ast::nodes::NameType* p) -#line 303 "src/grammar/parser.gr" -{return p; } -#line 927 "src/grammar/parser.cc" - -inline void ZaneParser::del_name_type(ast::nodes::NameType* p) -#line 304 "src/grammar/parser.gr" -{ } -#line 932 "src/grammar/parser.cc" - -inline ast::nodes::FunctionType* ZaneParser::dup_function_type(ast::nodes::FunctionType* p) -#line 314 "src/grammar/parser.gr" -{return p; } -#line 937 "src/grammar/parser.cc" - -inline void ZaneParser::del_function_type(ast::nodes::FunctionType* p) -#line 315 "src/grammar/parser.gr" -{ } -#line 942 "src/grammar/parser.cc" - -inline ast::nodes::MethodType* ZaneParser::dup_method_type(ast::nodes::MethodType* p) -#line 325 "src/grammar/parser.gr" -{return p; } -#line 947 "src/grammar/parser.cc" - -inline void ZaneParser::del_method_type(ast::nodes::MethodType* p) -#line 326 "src/grammar/parser.gr" -{ } -#line 952 "src/grammar/parser.cc" - -inline ast::nodes::ArrowBody* ZaneParser::dup_arrow_body(ast::nodes::ArrowBody* p) -#line 344 "src/grammar/parser.gr" -{return p; } -#line 957 "src/grammar/parser.cc" - -inline void ZaneParser::del_arrow_body(ast::nodes::ArrowBody* p) -#line 345 "src/grammar/parser.gr" -{ } -#line 962 "src/grammar/parser.cc" - -inline grammarSupport::FunctionBody* ZaneParser::dup_function_body(grammarSupport::FunctionBody* p) -#line 352 "src/grammar/parser.gr" -{return p; } -#line 967 "src/grammar/parser.cc" - -inline void ZaneParser::del_function_body(grammarSupport::FunctionBody* p) -#line 353 "src/grammar/parser.gr" -{ } -#line 972 "src/grammar/parser.cc" - -inline ast::nodes::Scope* ZaneParser::dup_scope(ast::nodes::Scope* p) -#line 363 "src/grammar/parser.gr" -{return p; } -#line 977 "src/grammar/parser.cc" - -inline void ZaneParser::del_scope(ast::nodes::Scope* p) -#line 364 "src/grammar/parser.gr" -{ } -#line 982 "src/grammar/parser.cc" - -inline std::vector>* ZaneParser::dup_statements(std::vector>* p) -#line 371 "src/grammar/parser.gr" -{return p; } -#line 987 "src/grammar/parser.cc" - -inline void ZaneParser::del_statements(std::vector>* p) -#line 372 "src/grammar/parser.gr" -{ } -#line 992 "src/grammar/parser.cc" - -inline ast::nodes::FunctionCall* ZaneParser::dup_function_call(ast::nodes::FunctionCall* p) -#line 383 "src/grammar/parser.gr" -{return p; } -#line 997 "src/grammar/parser.cc" - -inline void ZaneParser::del_function_call(ast::nodes::FunctionCall* p) -#line 384 "src/grammar/parser.gr" -{ } -#line 1002 "src/grammar/parser.cc" - -inline ast::nodes::Statement* ZaneParser::dup_statement(ast::nodes::Statement* p) -#line 394 "src/grammar/parser.gr" -{return p; } -#line 1007 "src/grammar/parser.cc" - -inline void ZaneParser::del_statement(ast::nodes::Statement* p) -#line 395 "src/grammar/parser.gr" -{ } -#line 1012 "src/grammar/parser.cc" - -inline ast::nodes::ValueExpr* ZaneParser::dup_value_expr(ast::nodes::ValueExpr* p) -#line 405 "src/grammar/parser.gr" -{return p; } -#line 1017 "src/grammar/parser.cc" - -inline void ZaneParser::del_value_expr(ast::nodes::ValueExpr* p) -#line 406 "src/grammar/parser.gr" -{ } -#line 1022 "src/grammar/parser.cc" - -inline ast::nodes::ParenthizedValue* ZaneParser::dup_parenthized_value(ast::nodes::ParenthizedValue* p) -#line 459 "src/grammar/parser.gr" -{return p; } -#line 1027 "src/grammar/parser.cc" - -inline void ZaneParser::del_parenthized_value(ast::nodes::ParenthizedValue* p) -#line 460 "src/grammar/parser.gr" -{ } -#line 1032 "src/grammar/parser.cc" - -inline std::vector>* ZaneParser::dup_arguments(std::vector>* p) -#line 467 "src/grammar/parser.gr" -{return p; } -#line 1037 "src/grammar/parser.cc" - -inline void ZaneParser::del_arguments(std::vector>* p) -#line 468 "src/grammar/parser.gr" -{ } -#line 1042 "src/grammar/parser.cc" - -inline std::vector>* ZaneParser::dup_argument_list(std::vector>* p) -#line 478 "src/grammar/parser.gr" -{return p; } -#line 1047 "src/grammar/parser.cc" - -inline void ZaneParser::del_argument_list(std::vector>* p) -#line 479 "src/grammar/parser.gr" -{ } -#line 1052 "src/grammar/parser.cc" - -SemanticValue ZaneParser::duplicateNontermValue(int nontermId, SemanticValue sval) -{ - switch (nontermId) { - case 2: - return (SemanticValue)dup_may_break((int)sval); - case 3: - return (SemanticValue)dup_package((ast::nodes::Package*)sval); - case 4: - return (SemanticValue)dup_global_scope((std::vector*)sval); - case 5: - return (SemanticValue)dup_declaration((ast::nodes::Declaration*)sval); - case 6: - return (SemanticValue)dup_variable_decl((ast::nodes::VariableDecl*)sval); - case 7: - return (SemanticValue)dup_function_decl((ast::nodes::FunctionDecl*)sval); - case 8: - return (SemanticValue)dup_method_decl((ast::nodes::MethodDecl*)sval); - case 9: - return (SemanticValue)dup_parameters((std::vector*)sval); - case 10: - return (SemanticValue)dup_parameter_list((std::vector*)sval); - case 11: - return (SemanticValue)dup_method_parameters((std::vector*)sval); - case 12: - return (SemanticValue)dup_method_parameter_seq((std::vector*)sval); - case 13: - return (SemanticValue)dup_parameter((ast::nodes::Parameter*)sval); - case 14: - return (SemanticValue)dup_type_list((std::vector>*)sval); - case 15: - return (SemanticValue)dup_type_list_ne((std::vector>*)sval); - case 16: - return (SemanticValue)dup_type_expr((ast::nodes::TypeExpression*)sval); - case 17: - return (SemanticValue)dup_name_type((ast::nodes::NameType*)sval); - case 18: - return (SemanticValue)dup_function_type((ast::nodes::FunctionType*)sval); - case 19: - return (SemanticValue)dup_method_type((ast::nodes::MethodType*)sval); - case 20: - return (SemanticValue)dup_arrow_body((ast::nodes::ArrowBody*)sval); - case 21: - return (SemanticValue)dup_function_body((grammarSupport::FunctionBody*)sval); - case 22: - return (SemanticValue)dup_scope((ast::nodes::Scope*)sval); - case 23: - return (SemanticValue)dup_statements((std::vector>*)sval); - case 24: - return (SemanticValue)dup_function_call((ast::nodes::FunctionCall*)sval); - case 25: - return (SemanticValue)dup_statement((ast::nodes::Statement*)sval); - case 26: - return (SemanticValue)dup_value_expr((ast::nodes::ValueExpr*)sval); - case 27: - return (SemanticValue)dup_parenthized_value((ast::nodes::ParenthizedValue*)sval); - case 28: - return (SemanticValue)dup_arguments((std::vector>*)sval); - case 29: - return (SemanticValue)dup_argument_list((std::vector>*)sval); - default: - return (SemanticValue)0; - } -} - -void ZaneParser::deallocateNontermValue(int nontermId, SemanticValue sval) -{ - switch (nontermId) { - case 2: - del_may_break((int)sval); - return; - case 3: - del_package((ast::nodes::Package*)sval); - return; - case 4: - del_global_scope((std::vector*)sval); - return; - case 5: - del_declaration((ast::nodes::Declaration*)sval); - return; - case 6: - del_variable_decl((ast::nodes::VariableDecl*)sval); - return; - case 7: - del_function_decl((ast::nodes::FunctionDecl*)sval); - return; - case 8: - del_method_decl((ast::nodes::MethodDecl*)sval); - return; - case 9: - del_parameters((std::vector*)sval); - return; - case 10: - del_parameter_list((std::vector*)sval); - return; - case 11: - del_method_parameters((std::vector*)sval); - return; - case 12: - del_method_parameter_seq((std::vector*)sval); - return; - case 13: - del_parameter((ast::nodes::Parameter*)sval); - return; - case 14: - del_type_list((std::vector>*)sval); - return; - case 15: - del_type_list_ne((std::vector>*)sval); - return; - case 16: - del_type_expr((ast::nodes::TypeExpression*)sval); - return; - case 17: - del_name_type((ast::nodes::NameType*)sval); - return; - case 18: - del_function_type((ast::nodes::FunctionType*)sval); - return; - case 19: - del_method_type((ast::nodes::MethodType*)sval); - return; - case 20: - del_arrow_body((ast::nodes::ArrowBody*)sval); - return; - case 21: - del_function_body((grammarSupport::FunctionBody*)sval); - return; - case 22: - del_scope((ast::nodes::Scope*)sval); - return; - case 23: - del_statements((std::vector>*)sval); - return; - case 24: - del_function_call((ast::nodes::FunctionCall*)sval); - return; - case 25: - del_statement((ast::nodes::Statement*)sval); - return; - case 26: - del_value_expr((ast::nodes::ValueExpr*)sval); - return; - case 27: - del_parenthized_value((ast::nodes::ParenthizedValue*)sval); - return; - case 28: - del_arguments((std::vector>*)sval); - return; - case 29: - del_argument_list((std::vector>*)sval); - return; - default: - std::cout << "WARNING: there is no action to deallocate nonterm " - << nontermNames[nontermId] << std::endl; - } -} - -SemanticValue ZaneParser::mergeAlternativeParses(int nontermId, SemanticValue left, - SemanticValue right, SourceLoc loc) -{ - switch (nontermId) { - default: - std::cout << toString(loc) - << ": error: there is no action to merge nonterm " - << nontermNames[nontermId] << std::endl; - abort(); - } -} - -bool ZaneParser::keepNontermValue(int nontermId, SemanticValue sval) -{ - switch (nontermId) { - default: - return true; - } -} - - -// ---------------- dup/del/classify terminals --------------- -inline std::string* ZaneParser::dup_TOK_STRING(std::string* s) -#line 91 "src/grammar/parser.gr" -{return new std::string(*s); } -#line 1236 "src/grammar/parser.cc" - -inline void ZaneParser::del_TOK_STRING(std::string* s) -#line 92 "src/grammar/parser.gr" -{delete s; } -#line 1241 "src/grammar/parser.cc" - -inline std::string* ZaneParser::dup_TOK_IDENT(std::string* s) -#line 95 "src/grammar/parser.gr" -{return new std::string(*s); } -#line 1246 "src/grammar/parser.cc" - -inline void ZaneParser::del_TOK_IDENT(std::string* s) -#line 96 "src/grammar/parser.gr" -{delete s; } -#line 1251 "src/grammar/parser.cc" - -inline std::string* ZaneParser::dup_TOK_INT(std::string* s) -#line 99 "src/grammar/parser.gr" -{return new std::string(*s); } -#line 1256 "src/grammar/parser.cc" - -inline void ZaneParser::del_TOK_INT(std::string* s) -#line 100 "src/grammar/parser.gr" -{delete s; } -#line 1261 "src/grammar/parser.cc" - -inline std::string* ZaneParser::dup_TOK_FLOAT(std::string* s) -#line 103 "src/grammar/parser.gr" -{return new std::string(*s); } -#line 1266 "src/grammar/parser.cc" - -inline void ZaneParser::del_TOK_FLOAT(std::string* s) -#line 104 "src/grammar/parser.gr" -{delete s; } -#line 1271 "src/grammar/parser.cc" - -SemanticValue ZaneParser::duplicateTerminalValue(int termId, SemanticValue sval) -{ - switch (termId) { - case 0: - return sval; - case 1: - return sval; - case 2: - return sval; - case 3: - return sval; - case 4: - return sval; - case 5: - return sval; - case 6: - return sval; - case 7: - return sval; - case 8: - return sval; - case 9: - return sval; - case 10: - return sval; - case 11: - return sval; - case 12: - return sval; - case 13: - return sval; - case 14: - return (SemanticValue)dup_TOK_STRING((std::string*)sval); - case 15: - return (SemanticValue)dup_TOK_IDENT((std::string*)sval); - case 16: - return (SemanticValue)dup_TOK_INT((std::string*)sval); - case 17: - return (SemanticValue)dup_TOK_FLOAT((std::string*)sval); - case 18: - return sval; - case 19: - return sval; - case 20: - return sval; - case 21: - return sval; - case 22: - return sval; - case 23: - return sval; - case 24: - return sval; - default: - return (SemanticValue)0; - } -} - -void ZaneParser::deallocateTerminalValue(int termId, SemanticValue sval) -{ - switch (termId) { - case 0: - break; - case 1: - break; - case 2: - break; - case 3: - break; - case 4: - break; - case 5: - break; - case 6: - break; - case 7: - break; - case 8: - break; - case 9: - break; - case 10: - break; - case 11: - break; - case 12: - break; - case 13: - break; - case 14: - del_TOK_STRING((std::string*)sval); - return; - case 15: - del_TOK_IDENT((std::string*)sval); - return; - case 16: - del_TOK_INT((std::string*)sval); - return; - case 17: - del_TOK_FLOAT((std::string*)sval); - return; - case 18: - break; - case 19: - break; - case 20: - break; - case 21: - break; - case 22: - break; - case 23: - break; - case 24: - break; - default: - int arrayMin = 0; - int arrayMax = 25; - xassert(termId >= arrayMin && termId < arrayMax); - std::cout << "WARNING: there is no action to deallocate terminal " - << termNames[termId] << std::endl; - } -} - -/*static*/ int ZaneParser::reclassifyToken(ZaneParser *ths, int oldTokenType, SemanticValue sval) -{ - switch (oldTokenType) { - default: - return oldTokenType; - } -} - -UserActions::ReclassifyFunc ZaneParser::getReclassifier() -{ - return (ReclassifyFunc)&ZaneParser::reclassifyToken; -} - - -// this makes a ParseTables from some literal data; -// the code is written by ParseTables::emitConstructionCode() -// in /build/source/src/elkhound/parsetables.cc -class ZaneParser_ParseTables : public ParseTables { -public: - ZaneParser_ParseTables(); -}; - -ZaneParser_ParseTables::ZaneParser_ParseTables() - : ParseTables(false /*owning*/) -{ - numTerms = 25; - numNonterms = 30; - numStates = 4; - numProds = 59; - actionCols = 25; - actionRows = 4; - gotoCols = 30; - gotoRows = 4; - ambigTableSize = 0; - startState = (StateId)0; - finalProductionIndex = 0; - bigProductionListSize = 0; - errorBitsRowSize = 4; - uniqueErrorRows = 0; - - // storage size: 200 bytes - // rows: 4 cols: 25 - static ActionEntry const actionTable_static[100] = { - /*0*/ -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, - /*1*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /*2*/ -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /*3*/ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - actionTable = const_cast(actionTable_static); - - // storage size: 240 bytes - // rows: 4 cols: 30 - static GotoEntry const gotoTable_static[120] = { - /*0*/ 65535, 65535, 3, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /*1*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /*2*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - /*3*/ 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, - }; - gotoTable = const_cast(gotoTable_static); - - // storage size: 236 bytes - static ParseTables::ProdInfo const prodInfo_static[59] = { - /*0*/ {2,1}, {0,2}, {1,2}, {3,3}, {0,4}, {1,4}, {3,4}, {1,5}, {1,5}, {4,6}, {6,7}, {6,8}, {7,8}, {0,9}, {1,9}, {1,10}, - /*1*/ {3,10}, {1,11}, {2,12}, {3,12}, {2,13}, {0,14}, {1,14}, {1,15}, {3,15}, {1,16}, {1,16}, {1,16}, {1,17}, {5,18}, {6,19}, {7,19}, - /*2*/ {2,20}, {1,21}, {1,21}, {5,22}, {0,23}, {3,23}, {4,24}, {1,25}, {1,25}, {1,26}, {3,26}, {4,26}, {1,26}, {1,26}, {1,26}, {1,26}, - /*3*/ {1,26}, {2,26}, {3,26}, {3,26}, {3,26}, {3,26}, {3,27}, {0,28}, {1,28}, {1,29}, {3,29}, - }; - prodInfo = const_cast(prodInfo_static); - - static SymbolId const stateSymbol_static[4] = { - /*0*/ 0, 1, 24, -3, - }; - stateSymbol = const_cast(stateSymbol_static); - - ActionEntry *ambigTable_static = NULL; - ambigTable = const_cast(ambigTable_static); - - // storage size: 60 bytes - static NtIndex const nontermOrder_static[30] = { - /*0*/ 22, 21, 28, 29, 27, 20, 18, 17, 16, 26, 15, 14, 13, 12, 25, 11, - /*1*/ 10, 9, 8, 7, 5, 6, 4, 24, 1, 19, 2, 0, 23, 3, - }; - nontermOrder = const_cast(nontermOrder_static); - - ErrorBitsEntry *errorBits_static = NULL; - errorBits = const_cast(errorBits_static); - - errorBitsPointers = NULL; - - TermIndex *actionIndexMap_static = NULL; - actionIndexMap = const_cast(actionIndexMap_static); - - actionRowPointers = NULL; - - NtIndex *gotoIndexMap_static = NULL; - gotoIndexMap = const_cast(gotoIndexMap_static); - - gotoRowPointers = NULL; - - firstWithTerminal = NULL; - firstWithNonterminal = NULL; - bigProductionList = NULL; - productionsForState = NULL; - ambigStateTable = NULL; -} - - -ParseTables *ZaneParser::makeTables() -{ - return new ZaneParser_ParseTables; -} - diff --git a/src/grammar/parser.h b/src/grammar/parser.h deleted file mode 100644 index 3d996ff5..00000000 --- a/src/grammar/parser.h +++ /dev/null @@ -1,222 +0,0 @@ -// src/grammar/parser.h -// *** DO NOT EDIT BY HAND *** -// automatically generated by elkhound, from src/grammar/parser.gr - -#ifndef SRC_GRAMMAR_PARSER_H -#define SRC_GRAMMAR_PARSER_H - -#include "useract.h" // UserActions - - -#line 1 "src/grammar/parser.gr" - - #include "ast/.hpp" - #include - #include - #include - #include - #include - - namespace grammarSupport { - - using FunctionBody = std::variant; - - template - T takeValue(T* ptr) { - T value = std::move(*ptr); - delete ptr; - return value; - } - - template - std::unique_ptr takePtr(T* ptr) { - return std::unique_ptr(ptr); - } - - inline std::string takeString(std::string* ptr) { - std::string value = std::move(*ptr); - delete ptr; - return value; - } - - inline ast::nodes::ValueExpr* makeBinary( - std::string op, - ast::nodes::ValueExpr* left, - ast::nodes::ValueExpr* right - ) { - return new ast::nodes::ValueExpr( - ast::nodes::OperatorCall( - std::move(op), - takePtr(left), - takePtr(right) - ) - ); - } - - inline ast::nodes::ValueExpr* makeFlip(ast::nodes::ValueExpr* value) { - return new ast::nodes::ValueExpr(ast::nodes::OperatorFlipCall(takePtr(value))); - } - - inline ast::nodes::ValueExpr* wrapCall(ast::nodes::FunctionCall* call) { - return new ast::nodes::ValueExpr(takeValue(call)); - } - - } // namespace grammarSupport - -#line 67 "src/grammar/parser.h" - - -// parser context class -class -#line 58 "src/grammar/parser.gr" - ZaneParser : public UserActions { -public: - // generated parser hooks are added by Elkhound - -#line 77 "src/grammar/parser.h" - - -private: - USER_ACTION_FUNCTIONS // see useract.h - - // declare the actual action function - static SemanticValue doReductionAction( - ZaneParser *ths, - int productionId, SemanticValue const *semanticValues, - SourceLoc loc); - - // declare the classifier function - static int reclassifyToken( - ZaneParser *ths, - int oldTokenType, SemanticValue sval); - - int action0___EarlyStartSymbol(SourceLoc loc, int top); - int action1_may_break(SourceLoc loc); - int action2_may_break(SourceLoc loc); - ast::nodes::Package* action3_package(SourceLoc loc, std::vector* declarations); - std::vector* action4_global_scope(SourceLoc loc); - std::vector* action5_global_scope(SourceLoc loc, ast::nodes::Declaration* declaration); - std::vector* action6_global_scope(SourceLoc loc, std::vector* declarations, ast::nodes::Declaration* declaration); - ast::nodes::Declaration* action7_declaration(SourceLoc loc, ast::nodes::FunctionDecl* function); - ast::nodes::Declaration* action8_declaration(SourceLoc loc, ast::nodes::MethodDecl* method); - ast::nodes::VariableDecl* action9_variable_decl(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type, ast::nodes::ValueExpr* value); - ast::nodes::FunctionDecl* action10_function_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body); - ast::nodes::MethodDecl* action11_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body); - ast::nodes::MethodDecl* action12_method_decl(SourceLoc loc, ast::nodes::TypeExpression* return_type, std::string* name, std::vector* params, grammarSupport::FunctionBody* body); - std::vector* action13_parameters(SourceLoc loc); - std::vector* action14_parameters(SourceLoc loc, std::vector* list); - std::vector* action15_parameter_list(SourceLoc loc, ast::nodes::Parameter* parameter); - std::vector* action16_parameter_list(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter); - std::vector* action17_method_parameters(SourceLoc loc, std::vector* list); - std::vector* action18_method_parameter_seq(SourceLoc loc, ast::nodes::TypeExpression* type); - std::vector* action19_method_parameter_seq(SourceLoc loc, std::vector* list, ast::nodes::Parameter* parameter); - ast::nodes::Parameter* action20_parameter(SourceLoc loc, std::string* name, ast::nodes::TypeExpression* type); - std::vector>* action21_type_list(SourceLoc loc); - std::vector>* action22_type_list(SourceLoc loc, std::vector>* list); - std::vector>* action23_type_list_ne(SourceLoc loc, ast::nodes::TypeExpression* expr); - std::vector>* action24_type_list_ne(SourceLoc loc, std::vector>* list, ast::nodes::TypeExpression* expr); - ast::nodes::TypeExpression* action25_type_expr(SourceLoc loc, ast::nodes::NameType* name); - ast::nodes::TypeExpression* action26_type_expr(SourceLoc loc, ast::nodes::FunctionType* function); - ast::nodes::TypeExpression* action27_type_expr(SourceLoc loc, ast::nodes::MethodType* method); - ast::nodes::NameType* action28_name_type(SourceLoc loc, std::string* identifier); - ast::nodes::FunctionType* action29_function_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); - ast::nodes::MethodType* action30_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); - ast::nodes::MethodType* action31_method_type(SourceLoc loc, std::vector>* params, ast::nodes::TypeExpression* return_type); - ast::nodes::ArrowBody* action32_arrow_body(SourceLoc loc, ast::nodes::ValueExpr* value); - grammarSupport::FunctionBody* action33_function_body(SourceLoc loc, ast::nodes::ArrowBody* body); - grammarSupport::FunctionBody* action34_function_body(SourceLoc loc, ast::nodes::Scope* body); - ast::nodes::Scope* action35_scope(SourceLoc loc, std::vector>* statements); - std::vector>* action36_statements(SourceLoc loc); - std::vector>* action37_statements(SourceLoc loc, std::vector>* list, ast::nodes::Statement* statement); - ast::nodes::FunctionCall* action38_function_call(SourceLoc loc, ast::nodes::ValueExpr* callee, std::vector>* args); - ast::nodes::Statement* action39_statement(SourceLoc loc, ast::nodes::FunctionCall* call); - ast::nodes::Statement* action40_statement(SourceLoc loc, ast::nodes::VariableDecl* declaration); - ast::nodes::ValueExpr* action41_value_expr(SourceLoc loc, std::string* identifier); - ast::nodes::ValueExpr* action42_value_expr(SourceLoc loc, std::string* package, std::string* identifier); - ast::nodes::ValueExpr* action43_value_expr(SourceLoc loc, std::string* package, std::string* identifier); - ast::nodes::ValueExpr* action44_value_expr(SourceLoc loc, std::string* integer); - ast::nodes::ValueExpr* action45_value_expr(SourceLoc loc, std::string* number); - ast::nodes::ValueExpr* action46_value_expr(SourceLoc loc, std::string* text); - ast::nodes::ValueExpr* action47_value_expr(SourceLoc loc, ast::nodes::ParenthizedValue* value); - ast::nodes::ValueExpr* action48_value_expr(SourceLoc loc, ast::nodes::FunctionCall* call); - ast::nodes::ValueExpr* action49_value_expr(SourceLoc loc, ast::nodes::ValueExpr* expr); - ast::nodes::ValueExpr* action50_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); - ast::nodes::ValueExpr* action51_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); - ast::nodes::ValueExpr* action52_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); - ast::nodes::ValueExpr* action53_value_expr(SourceLoc loc, ast::nodes::ValueExpr* left, ast::nodes::ValueExpr* right); - ast::nodes::ParenthizedValue* action54_parenthized_value(SourceLoc loc, ast::nodes::ValueExpr* value); - std::vector>* action55_arguments(SourceLoc loc); - std::vector>* action56_arguments(SourceLoc loc, std::vector>* list); - std::vector>* action57_argument_list(SourceLoc loc, ast::nodes::ValueExpr* value); - std::vector>* action58_argument_list(SourceLoc loc, std::vector>* list, ast::nodes::ValueExpr* value); - inline int dup_may_break(int p) ; - inline void del_may_break(int p) ; - inline ast::nodes::Package* dup_package(ast::nodes::Package* p) ; - inline void del_package(ast::nodes::Package* p) ; - inline std::vector* dup_global_scope(std::vector* p) ; - inline void del_global_scope(std::vector* p) ; - inline ast::nodes::Declaration* dup_declaration(ast::nodes::Declaration* p) ; - inline void del_declaration(ast::nodes::Declaration* p) ; - inline ast::nodes::VariableDecl* dup_variable_decl(ast::nodes::VariableDecl* p) ; - inline void del_variable_decl(ast::nodes::VariableDecl* p) ; - inline ast::nodes::FunctionDecl* dup_function_decl(ast::nodes::FunctionDecl* p) ; - inline void del_function_decl(ast::nodes::FunctionDecl* p) ; - inline ast::nodes::MethodDecl* dup_method_decl(ast::nodes::MethodDecl* p) ; - inline void del_method_decl(ast::nodes::MethodDecl* p) ; - inline std::vector* dup_parameters(std::vector* p) ; - inline void del_parameters(std::vector* p) ; - inline std::vector* dup_parameter_list(std::vector* p) ; - inline void del_parameter_list(std::vector* p) ; - inline std::vector* dup_method_parameters(std::vector* p) ; - inline void del_method_parameters(std::vector* p) ; - inline std::vector* dup_method_parameter_seq(std::vector* p) ; - inline void del_method_parameter_seq(std::vector* p) ; - inline ast::nodes::Parameter* dup_parameter(ast::nodes::Parameter* p) ; - inline void del_parameter(ast::nodes::Parameter* p) ; - inline std::vector>* dup_type_list(std::vector>* p) ; - inline void del_type_list(std::vector>* p) ; - inline std::vector>* dup_type_list_ne(std::vector>* p) ; - inline void del_type_list_ne(std::vector>* p) ; - inline ast::nodes::TypeExpression* dup_type_expr(ast::nodes::TypeExpression* p) ; - inline void del_type_expr(ast::nodes::TypeExpression* p) ; - inline ast::nodes::NameType* dup_name_type(ast::nodes::NameType* p) ; - inline void del_name_type(ast::nodes::NameType* p) ; - inline ast::nodes::FunctionType* dup_function_type(ast::nodes::FunctionType* p) ; - inline void del_function_type(ast::nodes::FunctionType* p) ; - inline ast::nodes::MethodType* dup_method_type(ast::nodes::MethodType* p) ; - inline void del_method_type(ast::nodes::MethodType* p) ; - inline ast::nodes::ArrowBody* dup_arrow_body(ast::nodes::ArrowBody* p) ; - inline void del_arrow_body(ast::nodes::ArrowBody* p) ; - inline grammarSupport::FunctionBody* dup_function_body(grammarSupport::FunctionBody* p) ; - inline void del_function_body(grammarSupport::FunctionBody* p) ; - inline ast::nodes::Scope* dup_scope(ast::nodes::Scope* p) ; - inline void del_scope(ast::nodes::Scope* p) ; - inline std::vector>* dup_statements(std::vector>* p) ; - inline void del_statements(std::vector>* p) ; - inline ast::nodes::FunctionCall* dup_function_call(ast::nodes::FunctionCall* p) ; - inline void del_function_call(ast::nodes::FunctionCall* p) ; - inline ast::nodes::Statement* dup_statement(ast::nodes::Statement* p) ; - inline void del_statement(ast::nodes::Statement* p) ; - inline ast::nodes::ValueExpr* dup_value_expr(ast::nodes::ValueExpr* p) ; - inline void del_value_expr(ast::nodes::ValueExpr* p) ; - inline ast::nodes::ParenthizedValue* dup_parenthized_value(ast::nodes::ParenthizedValue* p) ; - inline void del_parenthized_value(ast::nodes::ParenthizedValue* p) ; - inline std::vector>* dup_arguments(std::vector>* p) ; - inline void del_arguments(std::vector>* p) ; - inline std::vector>* dup_argument_list(std::vector>* p) ; - inline void del_argument_list(std::vector>* p) ; - inline std::string* dup_TOK_STRING(std::string* s) ; - inline void del_TOK_STRING(std::string* s) ; - inline std::string* dup_TOK_IDENT(std::string* s) ; - inline void del_TOK_IDENT(std::string* s) ; - inline std::string* dup_TOK_INT(std::string* s) ; - inline void del_TOK_INT(std::string* s) ; - inline std::string* dup_TOK_FLOAT(std::string* s) ; - inline void del_TOK_FLOAT(std::string* s) ; - -// the function which makes the parse tables -public: - virtual ParseTables *makeTables(); -}; - -#endif // SRC_GRAMMAR_PARSER_H From 05ace9d4473d195fb014c535c37d431a3871f7bc Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 14:47:29 +0200 Subject: [PATCH 065/154] update --- justfile | 2 +- notes.txt | 7 +++++++ test-parser/main.zn | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 notes.txt diff --git a/justfile b/justfile index 9d9943c9..c2225e50 100644 --- a/justfile +++ b/justfile @@ -17,4 +17,4 @@ glr-stats: ELKHOUND_DEBUG=1 ./build/zane 2>/dev/null grammar-conflicts: - elkhound -v -tr conflict,prec src/grammar/parser.gr + elkhound -v -tr conflict,prec -o build/zane_parser src/grammar/parser.gr diff --git a/notes.txt b/notes.txt new file mode 100644 index 00000000..ba6c5992 --- /dev/null +++ b/notes.txt @@ -0,0 +1,7 @@ +loseHp (this Player, x Int)! Void { + +} + +sqrt (x Float) Float?ArithmeticError { + +} diff --git a/test-parser/main.zn b/test-parser/main.zn index 046c3a90..a58cd47b 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,10 +1,10 @@ -Void main(this Int, a Bool) { +main (this Int, a Bool) -> Void { print(2, 2) Std$print(1 + 1 + 3 + 4) @Intrinsics$print("hello") test Int = 3 func (this Int) -> Void = 3.0 } -Int getNum() { +getNum () -> { print() } From 6984eb2ec3af756f2f3254254a3abe30daba796e Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 15:04:17 +0200 Subject: [PATCH 066/154] update --- src/grammar/lexer.hpp | 2 +- src/grammar/lexer.re | 4 ++-- src/grammar/parser.gr | 10 +++++----- test-parser/main.zn | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/grammar/lexer.hpp b/src/grammar/lexer.hpp index 94fd1d5c..318ac090 100644 --- a/src/grammar/lexer.hpp +++ b/src/grammar/lexer.hpp @@ -17,7 +17,7 @@ enum TokenCode { TOK_THIN_ARROW, TOK_THICK_ARROW, TOK_AT, - TOK_MUT, + TOK_EXCL, TOK_THIS, TOK_STRING, TOK_IDENT, diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re index b117ac10..9eba971d 100644 --- a/src/grammar/lexer.re +++ b/src/grammar/lexer.re @@ -120,7 +120,7 @@ const char* Lexer::tokenName(int token) { case TOK_THIN_ARROW: return "->"; case TOK_THICK_ARROW: return "=>"; case TOK_AT: return "@"; - case TOK_MUT: return "mut"; + case TOK_EXCL: return "!"; case TOK_THIS: return "this"; case TOK_STRING: return "string"; case TOK_IDENT: return "identifier"; @@ -227,6 +227,7 @@ void Lexer::nextToken(LexerInterface* base) { "}" { tok = TOK_RCURLY; goto done; } "," { tok = TOK_COMMA; goto done; } ":" { tok = TOK_COLON; goto done; } + "!" { tok = TOK_EXCL; goto done; } "~" { tok = TOK_TILDE; goto done; } "+" { tok = TOK_PLUS; goto done; } "-" { tok = TOK_MINUS; goto done; } @@ -250,7 +251,6 @@ void Lexer::nextToken(LexerInterface* base) { sval = reinterpret_cast(new std::string(unescape(start + 1, cursor - 1))); tok = TOK_STRING; goto done; } - "mut" { tok = TOK_MUT; goto done; } "this" { tok = TOK_THIS; goto done; } ident+ { sval = reinterpret_cast(new std::string(toStr(start, cursor))); diff --git a/src/grammar/parser.gr b/src/grammar/parser.gr index 6feaba40..5dcac17f 100644 --- a/src/grammar/parser.gr +++ b/src/grammar/parser.gr @@ -73,7 +73,7 @@ terminals { 9 : TOK_THIN_ARROW "->"; 10 : TOK_THICK_ARROW "=>"; 11 : TOK_AT "@"; - 12 : TOK_MUT "mut"; + 12 : TOK_EXCL "!"; 13 : TOK_THIS "this"; 14 : TOK_STRING; 15 : TOK_IDENT; @@ -169,7 +169,7 @@ nonterm(ast::nodes::VariableDecl*) variable_decl { nonterm(ast::nodes::FunctionDecl*) function_decl { fun dup(p) [return p;] fun del(p) [] - -> return_type:type_expr name:TOK_IDENT "(" params:parameters ")" body:function_body { + -> name:TOK_IDENT "(" params:parameters ")" return_type:type_expr body:function_body { return new ast::nodes::FunctionDecl( grammarSupport::takeString(name), grammarSupport::takeValue(params), @@ -182,7 +182,7 @@ nonterm(ast::nodes::FunctionDecl*) function_decl { nonterm(ast::nodes::MethodDecl*) method_decl { fun dup(p) [return p;] fun del(p) [] - -> return_type:type_expr name:TOK_IDENT "(" params:method_parameters ")" body:function_body { + -> name:TOK_IDENT "(" params:method_parameters ")" return_type:type_expr body:function_body { return new ast::nodes::MethodDecl( grammarSupport::takeString(name), grammarSupport::takeValue(params), @@ -191,7 +191,7 @@ nonterm(ast::nodes::MethodDecl*) method_decl { false ); } - -> return_type:type_expr name:TOK_IDENT "(" params:method_parameters ")" "mut" body:function_body { + -> name:TOK_IDENT "(" params:method_parameters ")" "!" return_type:type_expr body:function_body { return new ast::nodes::MethodDecl( grammarSupport::takeString(name), grammarSupport::takeValue(params), @@ -331,7 +331,7 @@ nonterm(ast::nodes::MethodType*) method_type { false ); } - -> "(" "this" params:type_list_ne ")" "mut" "->" return_type:type_expr { + -> "(" "this" params:type_list_ne ")" "!" "->" return_type:type_expr { return new ast::nodes::MethodType( grammarSupport::takeValue(params), grammarSupport::takePtr(return_type), diff --git a/test-parser/main.zn b/test-parser/main.zn index a58cd47b..5de9f96f 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,10 +1,10 @@ -main (this Int, a Bool) -> Void { +main (this Int, a Bool)! Void { print(2, 2) Std$print(1 + 1 + 3 + 4) @Intrinsics$print("hello") test Int = 3 func (this Int) -> Void = 3.0 } -getNum () -> { +getNum() Void { print() } From a2dc358f4e032f50729018223f00d247ad8d780d Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 29 May 2026 15:11:42 +0200 Subject: [PATCH 067/154] update --- test-parser/main.zn | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test-parser/main.zn b/test-parser/main.zn index 5de9f96f..42b4197b 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -5,6 +5,7 @@ main (this Int, a Bool)! Void { test Int = 3 func (this Int) -> Void = 3.0 } -getNum() Void { + +getNum () Void { print() } From 60ee02fd92478e822109a8a52180de56f9b7208b Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 2 Jun 2026 09:17:02 +0200 Subject: [PATCH 068/154] update --- error.txt | 95 ------------------------------------------------------- notes.txt | 7 ---- 2 files changed, 102 deletions(-) delete mode 100644 error.txt delete mode 100644 notes.txt diff --git a/error.txt b/error.txt deleted file mode 100644 index 335848ea..00000000 --- a/error.txt +++ /dev/null @@ -1,95 +0,0 @@ - manuel on  ~/projects/zane/compiler essential/parser -# devbox shell -Starting a devbox shell... -Welcome to devbox! - manuel on  ~/projects/zane/compiler essential/parser -# just debug test-parser -rm -rf build -vcpkg install -Detecting compiler hash for triplet x64-linux... -Compiler found: /nix/store/qd70v8g0561vm8m33kmnp79z00cgyi5n-gcc-wrapper-15.2.0/bin/g++ -The following packages are already installed: - cereal:x64-linux@1.3.2#1 -- git+https://github.com/microsoft/vcpkg@075869fcf5302c6dd11d564286d0dfa1d2d4d7a1 - nlohmann-json:x64-linux@3.12.0#2 -- git+https://github.com/microsoft/vcpkg@ac3b8821cf486e45dd543bef2a4ba1d1ba230258 - * vcpkg-cmake:x64-linux@2024-04-23 -- git+https://github.com/microsoft/vcpkg@e74aa1e8f93278a8e71372f1fa08c3df420eb840 - * vcpkg-cmake-config:x64-linux@2024-05-23 -- git+https://github.com/microsoft/vcpkg@97a63e4bc1a17422ffe4eff71da53b4b561a7841 -cereal provides CMake targets: - - # this is heuristically generated, and may not be correct - find_package(cereal CONFIG REQUIRED) - target_link_libraries(main PRIVATE cereal::cereal) - -The package nlohmann-json provides CMake targets: - - find_package(nlohmann_json CONFIG REQUIRED) - target_link_libraries(main PRIVATE nlohmann_json::nlohmann_json) - -The package nlohmann-json can be configured to not provide implicit conversions via a custom triplet file: - - set(nlohmann-json_IMPLICIT_CONVERSIONS OFF) - -For more information, see the docs here: - - https://json.nlohmann.me/api/macros/json_use_implicit_conversions/ - -All requested installations completed successfully in: 198 us -CXX=clang++ meson setup build --buildtype=debug --cmake-prefix-path "$(realpath vcpkg_installed/x64-linux)" -The Meson build system -Version: 1.10.2 -Source dir: /home/manuel/projects/zane/compiler -Build dir: /home/manuel/projects/zane/compiler/build -Build type: native build -Project name: zane -Project version: 0.1.0 -C++ compiler for the host machine: clang++ (clang 21.1.8 "clang version 21.1.8") -C++ linker for the host machine: clang++ ld.bfd 2.46 -Host machine cpu family: x86_64 -Host machine cpu: x86_64 -Program re2c found: YES (/home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/re2c) -Program bison found: YES (/home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/bison) -Build targets in project: 3 - -zane 0.1.0 - - User defined options - buildtype : debug - cmake_prefix_path: /home/manuel/projects/zane/compiler/vcpkg_installed/x64-linux - -Found ninja-1.13.1 at /home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/ninja -meson compile -C build -INFO: autodetecting backend as ninja -INFO: calculating backend command to run: /home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/ninja -C /home/man -uel/projects/zane/compiler/build -ninja: Entering directory `/home/manuel/projects/zane/compiler/build' -[1/6] Generating parser with a custom command -FAILED: [code=1] parser.cc parser.tab.h -/home/manuel/projects/zane/compiler/.devbox/nix/profile/default/bin/bison -d -o parser.cc --defines=parser.tab.h ../src/grammar/ -parser.y -../src/grammar/parser.y:33.24-25: error: $1 of ‘expr’ has no declared type - 33 | $$ = std::move($1); // $1 is already unique_ptr - | ^~ -[2/6] Compiling C++ object zane.p/src_main.cpp.o -FAILED: [code=1] zane.p/src_main.cpp.o -clang++ -Izane.p -I. -I.. -I../src -fdiagnostics-color=always -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wextra -Wpedantic -std -=c++20 -O0 -g -Wall -Wextra -MD -MQ zane.p/src_main.cpp.o -MF zane.p/src_main.cpp.o.d -o zane.p/src_main.cpp.o -c ../src/main.cp -p -In file included from ../src/main.cpp:1: -In file included from ../src/ast/nodes.hpp:2: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/memory:65: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/bits/memoryfwd.h:50: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-linux-gnu/bits/c+ -+config.h:727: -In file included from /nix/store/sanx9fg8mry8mq92zhlm5qvb83qlxrlx-gcc-15.2.0/include/c++/15.2.0/x86_64-unknown-linux-gnu/bits/os -_defines.h:39: -/nix/store/fbbw928argckfii0j322346ihmllg7a7-glibc-2.42-61-dev/include/features.h:435:4: warning: _FORTIFY_SOURCE requires compil -ing with optimization (-O) [-W#warnings] - 435 | # warning _FORTIFY_SOURCE requires compiling with optimization (-O) - | ^ -../src/main.cpp:2:10: fatal error: 'parser.tab.h' file not found - 2 | #include "parser.tab.h" - | ^~~~~~~~~~~~~~ -1 warning and 1 error generated. -ninja: build stopped: subcommand failed. -error: Recipe `test-parser` failed on line 12 with exit code 1 - manuel on  ~/projects/zane/compiler essential/parser -# diff --git a/notes.txt b/notes.txt deleted file mode 100644 index ba6c5992..00000000 --- a/notes.txt +++ /dev/null @@ -1,7 +0,0 @@ -loseHp (this Player, x Int)! Void { - -} - -sqrt (x Float) Float?ArithmeticError { - -} From b144f7c5395b46e4018b4ef81c033655652d73bd Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 2 Jun 2026 17:50:25 +0200 Subject: [PATCH 069/154] getting ready for ocaml --- CMakeFiles/CMakeSystem.cmake | 15 - devbox.json | 4 +- devbox.lock | 48 -- justfile | 20 - meson.build | 30 -- nix/elkhound/flake.lock | 27 - nix/elkhound/flake.nix | 35 -- src/ast/.hpp | 4 - src/ast/evaluators/.hpp | 3 - src/ast/evaluators/to-graph.hpp | 196 ------- src/ast/nodes.hpp | 231 -------- src/grammar/lexer.hpp | 69 --- src/grammar/lexer.re | 273 ---------- src/grammar/parser.gr | 494 ------------------ src/main.cpp | 42 -- src/treegraph/.hpp | 5 - src/treegraph/build.hpp | 26 - src/treegraph/evaluator.hpp | 165 ------ src/treegraph/structure.hpp | 50 -- src/types/primitives.hpp | 18 - src/types/stack.hpp | 23 - src/types/variant.hpp | 239 --------- vcpkg-configuration.json | 17 - vcpkg-ports/elkhound-runtime/CMakeLists.txt | 88 ---- .../elkhound_runtimeConfig.cmake.in | 3 - vcpkg-ports/elkhound-runtime/portfile.cmake | 22 - vcpkg-ports/elkhound-runtime/vcpkg.json | 7 - vcpkg.json | 7 - 28 files changed, 1 insertion(+), 2160 deletions(-) delete mode 100644 CMakeFiles/CMakeSystem.cmake delete mode 100644 justfile delete mode 100644 meson.build delete mode 100644 nix/elkhound/flake.lock delete mode 100644 nix/elkhound/flake.nix delete mode 100644 src/ast/.hpp delete mode 100644 src/ast/evaluators/.hpp delete mode 100644 src/ast/evaluators/to-graph.hpp delete mode 100644 src/ast/nodes.hpp delete mode 100644 src/grammar/lexer.hpp delete mode 100644 src/grammar/lexer.re delete mode 100644 src/grammar/parser.gr delete mode 100644 src/main.cpp delete mode 100644 src/treegraph/.hpp delete mode 100644 src/treegraph/build.hpp delete mode 100644 src/treegraph/evaluator.hpp delete mode 100644 src/treegraph/structure.hpp delete mode 100644 src/types/primitives.hpp delete mode 100644 src/types/stack.hpp delete mode 100644 src/types/variant.hpp delete mode 100644 vcpkg-configuration.json delete mode 100644 vcpkg-ports/elkhound-runtime/CMakeLists.txt delete mode 100644 vcpkg-ports/elkhound-runtime/elkhound_runtimeConfig.cmake.in delete mode 100644 vcpkg-ports/elkhound-runtime/portfile.cmake delete mode 100644 vcpkg-ports/elkhound-runtime/vcpkg.json delete mode 100644 vcpkg.json diff --git a/CMakeFiles/CMakeSystem.cmake b/CMakeFiles/CMakeSystem.cmake deleted file mode 100644 index 2f7ed46e..00000000 --- a/CMakeFiles/CMakeSystem.cmake +++ /dev/null @@ -1,15 +0,0 @@ -set(CMAKE_HOST_SYSTEM "Linux-6.6.87.2-microsoft-standard-WSL2") -set(CMAKE_HOST_SYSTEM_NAME "Linux") -set(CMAKE_HOST_SYSTEM_VERSION "6.6.87.2-microsoft-standard-WSL2") -set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64") - - - -set(CMAKE_SYSTEM "Linux-6.6.87.2-microsoft-standard-WSL2") -set(CMAKE_SYSTEM_NAME "Linux") -set(CMAKE_SYSTEM_VERSION "6.6.87.2-microsoft-standard-WSL2") -set(CMAKE_SYSTEM_PROCESSOR "x86_64") - -set(CMAKE_CROSSCOMPILING "FALSE") - -set(CMAKE_SYSTEM_LOADED 1) diff --git a/devbox.json b/devbox.json index 79e575a0..80917c8f 100644 --- a/devbox.json +++ b/devbox.json @@ -9,9 +9,7 @@ "upx@latest", "ninja@latest", "zig@latest", - "clang-tools@latest", - "path:nix/elkhound#default", - "re2c@latest" + "clang-tools@latest" ], "shell": { "init_hook": [ diff --git a/devbox.lock b/devbox.lock index 26e56d1b..93e968bc 100644 --- a/devbox.lock +++ b/devbox.lock @@ -413,54 +413,6 @@ } } }, - "re2c@latest": { - "last_modified": "2026-04-23T13:07:47Z", - "resolved": "github:NixOS/nixpkgs/01fbdeef22b76df85ea168fbfe1bfd9e63681b30#re2c", - "source": "devbox-search", - "version": "4.5.1", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/qbdjjl5qqrhls3ld8x8dlmsz8ddkazib-re2c-4.5.1", - "default": true - } - ], - "store_path": "/nix/store/qbdjjl5qqrhls3ld8x8dlmsz8ddkazib-re2c-4.5.1" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/b8dp3yrgky5ira1yqwjda0xa5ykf11qh-re2c-4.5.1", - "default": true - } - ], - "store_path": "/nix/store/b8dp3yrgky5ira1yqwjda0xa5ykf11qh-re2c-4.5.1" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/3n0qpxbjhw2yziynjjg5pg0zbm2w5ka0-re2c-4.5.1", - "default": true - } - ], - "store_path": "/nix/store/3n0qpxbjhw2yziynjjg5pg0zbm2w5ka0-re2c-4.5.1" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/zkmywqm90m1wlmjs9x1ibr7hqlvy0rxk-re2c-4.5.1", - "default": true - } - ], - "store_path": "/nix/store/zkmywqm90m1wlmjs9x1ibr7hqlvy0rxk-re2c-4.5.1" - } - } - }, "upx@latest": { "last_modified": "2026-04-23T13:07:47Z", "resolved": "github:NixOS/nixpkgs/01fbdeef22b76df85ea168fbfe1bfd9e63681b30#upx", diff --git a/justfile b/justfile deleted file mode 100644 index c2225e50..00000000 --- a/justfile +++ /dev/null @@ -1,20 +0,0 @@ -debug: - rm -rf build - vcpkg install - CXX=clang++ meson setup build --buildtype=debug --cmake-prefix-path "$(realpath vcpkg_installed/x64-linux)" - -release: - rm -rf build - vcpkg install - CXX=clang++ meson setup build --buildtype=release --cmake-prefix-path "$(realpath vcpkg_installed/x64-linux)" - -test-parser: - meson compile -C build - ./build/zane - -glr-stats: - meson compile -C build - ELKHOUND_DEBUG=1 ./build/zane 2>/dev/null - -grammar-conflicts: - elkhound -v -tr conflict,prec -o build/zane_parser src/grammar/parser.gr diff --git a/meson.build b/meson.build deleted file mode 100644 index 9db6f812..00000000 --- a/meson.build +++ /dev/null @@ -1,30 +0,0 @@ -project('zane', 'cpp', - version: '0.1.0', - default_options: ['cpp_std=c++20', 'warning_level=3']) - -re2c = find_program('re2c', required: true) -elkhound = find_program('elkhound', required: true) - -elkhound_runtime = dependency('elkhound_runtime', method: 'cmake', required: true) - -parser_gen = custom_target('parser', - input: 'src/grammar/parser.gr', - output: ['zane_parser.cc', 'zane_parser.h'], - command: [elkhound, '-o', '@OUTDIR@/zane_parser', '@INPUT@'], - build_by_default: true, -) - -lexer_gen = custom_target('lexer', - input: 'src/grammar/lexer.re', - output: 'lexer.cc', - command: [re2c, '-o', '@OUTPUT@', '@INPUT@'], - build_by_default: true, -) - -executable('zane', - 'src/main.cpp', - parser_gen[0], # parser.cc - lexer_gen, # lexer.cc - include_directories: include_directories('src'), - dependencies: [elkhound_runtime], -) diff --git a/nix/elkhound/flake.lock b/nix/elkhound/flake.lock deleted file mode 100644 index 62ede088..00000000 --- a/nix/elkhound/flake.lock +++ /dev/null @@ -1,27 +0,0 @@ -{ - "nodes": { - "nixpkgs": { - "locked": { - "lastModified": 1776949667, - "narHash": "sha256-GMSVw35Q+294GlrTUKlx087E31z7KurReQ1YHSKp5iw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "01fbdeef22b76df85ea168fbfe1bfd9e63681b30", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "01fbdeef22b76df85ea168fbfe1bfd9e63681b30", - "type": "github" - } - }, - "root": { - "inputs": { - "nixpkgs": "nixpkgs" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/nix/elkhound/flake.nix b/nix/elkhound/flake.nix deleted file mode 100644 index 6bad0a9b..00000000 --- a/nix/elkhound/flake.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ - description = "elkhound parser generator - WeiDUorg/elkhound at pinned commit"; - - # Pinned to the same nixpkgs commit devbox uses, so no second download is needed. - # To update: bump the rev, then run `nix flake update` and update devbox.json. - inputs.nixpkgs.url = "github:NixOS/nixpkgs/01fbdeef22b76df85ea168fbfe1bfd9e63681b30"; - - outputs = { self, nixpkgs }: - let - # The exact same commit that vcpkg-ports/elkhound-runtime/portfile.cmake pins. - # Both must be kept in sync when upgrading. - src = { - owner = "WeiDUorg"; - repo = "elkhound"; - rev = "b8f5589de119c89b36b1fc21d2f51c4a942ee3a8"; - hash = "sha256-8kktKhGY71zsNDAPKxUPBhy39N7m+P4tWmpbWxK7HhI="; - }; - - supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; - - forAllSystems = nixpkgs.lib.genAttrs supportedSystems; - in - { - packages = forAllSystems (system: - let - pkgs = nixpkgs.legacyPackages.${system}; - in - { - default = pkgs.elkhound.overrideAttrs (_old: { - src = pkgs.fetchFromGitHub src; - }); - } - ); - }; -} diff --git a/src/ast/.hpp b/src/ast/.hpp deleted file mode 100644 index 13c93e2e..00000000 --- a/src/ast/.hpp +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -#include "ast/nodes.hpp" -#include "ast/evaluators/.hpp" diff --git a/src/ast/evaluators/.hpp b/src/ast/evaluators/.hpp deleted file mode 100644 index 6093a430..00000000 --- a/src/ast/evaluators/.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include "ast/evaluators/to-graph.hpp" diff --git a/src/ast/evaluators/to-graph.hpp b/src/ast/evaluators/to-graph.hpp deleted file mode 100644 index 128c84a2..00000000 --- a/src/ast/evaluators/to-graph.hpp +++ /dev/null @@ -1,196 +0,0 @@ -#pragma once - -#include "ast/nodes.hpp" -#include "treegraph/.hpp" -#include -#include - -namespace ast::evaluators { - -struct ToGraph { - - treegraph::Node operator()(const nodes::IntLiteral& literal) const { - return treegraph::Node("\"" + literal.data + "\""); - } - - treegraph::Node operator()(const nodes::FloatLiteral& literal) const { - return treegraph::Node("\"" + literal.data + "\""); - } - - treegraph::Node operator()(const nodes::StringLiteral& literal) const { - return treegraph::Node("\"" + literal.data + "\""); - } - - treegraph::Node operator()(const nodes::IntrinsicValueSymbol& symbol) const { - return treegraph::Node("@" + symbol.package + "$" + symbol.name); - } - - treegraph::Node operator()(const nodes::PackageValueSymbol& symbol) const { - return treegraph::Node(symbol.package + "$" + symbol.name); - } - - treegraph::Node operator()(const nodes::ValueSymbol& symbol) const { - return treegraph::Node(symbol.name); - } - - treegraph::Node operator()(const nodes::OperatorFlipCall& call) const { - treegraph::Table table; - if (call.value != nullptr) - table.insert("Value", treegraph::ptr((*this)(*call.value))); - return treegraph::Node(std::move(table)); - } - - treegraph::Node operator()(const nodes::OperatorCall& call) const { - treegraph::Table table; - table.insert("Operator", treegraph::string(call.op)); - if (call.left != nullptr) - table.insert("Left", treegraph::ptr((*this)(*call.left))); - if (call.right != nullptr) - table.insert("Right", treegraph::ptr((*this)(*call.right))); - return treegraph::Node(std::move(table)); - } - - treegraph::Node operator()(const nodes::FunctionCall& call) const { - treegraph::Table table; - if (call.callee != nullptr) - table.insert("Callee", treegraph::ptr((*this)(*call.callee))); - treegraph::List arguments; - for (const auto& argument : call.arguments) - if (argument != nullptr) - arguments.push({}, treegraph::ptr((*this)(*argument))); - if (!arguments.children.empty()) - table.insert("Arguments", treegraph::list(std::move(arguments))); - return treegraph::Node(std::move(table)); - } - - treegraph::Node operator()(const nodes::NameType& type) const { - treegraph::Table table; - table.insert("Name", treegraph::string(type.name)); - treegraph::List generics; - for (const auto& generic : type.generics) - if (generic != nullptr) - generics.push({}, treegraph::ptr((*this)(*generic))); - if (!generics.children.empty()) - table.insert("Generics", treegraph::list(std::move(generics))); - return treegraph::Node(std::move(table)); - } - - treegraph::Node operator()(const nodes::FunctionType& type) const { - treegraph::Table table; - treegraph::List parameters; - for (const auto& parameter : type.parameters) - if (parameter != nullptr) - parameters.push({}, treegraph::ptr(std::visit(*this, parameter->data))); - if (!parameters.children.empty()) - table.insert("Parameters", treegraph::list(std::move(parameters))); - if (type.returnType != nullptr) - table.insert("ReturnType", treegraph::ptr((*this)(*type.returnType))); - return treegraph::Node(std::move(table)); - } - - treegraph::Node operator()(const nodes::MethodType& type) const { - treegraph::Table table; - treegraph::List parameters; - for (const auto& parameter : type.parameters) - if (parameter != nullptr) - parameters.push({}, treegraph::ptr(std::visit(*this, parameter->data))); - if (!parameters.children.empty()) - table.insert("Parameters", treegraph::list(std::move(parameters))); - if (type.returnType != nullptr) - table.insert("ReturnType", treegraph::ptr((*this)(*type.returnType))); - table.insert("IsMutating", treegraph::string(type.isMutating ? "true" : "false")); - return treegraph::Node(std::move(table)); - } - - treegraph::Node operator()(const nodes::TypeExpression& expression) const { - treegraph::Table table; - table.insert("ArrowBody", treegraph::ptr(std::visit(*this, expression.data))); - return treegraph::Node(std::move(table)); - } - - treegraph::Node operator()(const nodes::Parameter& parameter) const { - treegraph::Table table; - table.insert("Name", treegraph::string(parameter.name)); - if (parameter.type != nullptr) - table.insert("Type", treegraph::ptr((*this)(*parameter.type))); - return treegraph::Node(std::move(table)); - } - - treegraph::Node operator()(const nodes::Statement& statement) const { - return std::visit(*this, statement.data); - } - - treegraph::Node operator()(const nodes::Scope& scope) const { - treegraph::Table table; - treegraph::List statements; - for (const auto& statement : scope.statements) - if (statement != nullptr) - statements.push({}, treegraph::ptr((*this)(*statement))); - if (!statements.children.empty()) - table.insert("Statements", treegraph::list(std::move(statements))); - return treegraph::Node(std::move(table)); - } - - treegraph::Node operator()(const nodes::VariableDecl& declaration) const { - treegraph::Table table; - table.insert("Name", treegraph::string(declaration.name)); - table.insert("Type", treegraph::ptr((*this)(declaration.type))); - table.insert("Value", treegraph::ptr((*this)(*declaration.value))); - return treegraph::Node(std::move(table)); - } - - treegraph::Node operator()(const nodes::ArrowBody& body) const { - return (*this)(*body.returnValue); - } - - treegraph::Node operator()(const nodes::FunctionDecl& declaration) const { - treegraph::Table table; - table.insert("Name", treegraph::string(declaration.name)); - treegraph::List parameters; - for (const auto& parameter : declaration.parameters) - parameters.push({}, treegraph::ptr((*this)(parameter))); - if (!parameters.children.empty()) - table.insert("Parameters", treegraph::list(std::move(parameters))); - table.insert("ReturnType", treegraph::ptr((*this)(declaration.returnType))); - table.insert("FunctionBody", treegraph::ptr(std::visit(*this, declaration.functionBody))); - return treegraph::Node{std::move(table)}; - } - - treegraph::Node operator()(const nodes::MethodDecl& declaration) const { - treegraph::Table table; - table.insert("Name", treegraph::string(declaration.name)); - table.insert("IsMutating", treegraph::string(declaration.isMutating ? "true" : "false")); - treegraph::List parameters; - for (const auto& parameter : declaration.parameters) - parameters.push({}, treegraph::ptr((*this)(parameter))); - if (!parameters.children.empty()) - table.insert("Parameters", treegraph::list(std::move(parameters))); - table.insert("ReturnType", treegraph::ptr((*this)(declaration.returnType))); - table.insert("FunctionBody", treegraph::ptr(std::visit(*this, declaration.functionBody))); - return treegraph::Node{std::move(table)}; - } - - treegraph::Node operator()(const nodes::Declaration& declaration) const { - return std::visit(*this, declaration); - } - - treegraph::Node operator()(const nodes::Package& package) const { - treegraph::Table table; - treegraph::List declarations; - for (const auto& declaration : package.declarations) - declarations.push({}, treegraph::ptr((*this)(declaration))); - if (!declarations.children.empty()) - table.insert("Declarations", treegraph::list(std::move(declarations))); - return treegraph::Node{std::move(table)}; - } - - treegraph::Node operator()(const nodes::ParenthizedValue& expression) const { - return (*this)(*expression.data); - } - - treegraph::Node operator()(const nodes::ValueExpr& expression) const { - return std::visit(*this, expression.data); - } -}; - -} // namespace ast::evaluators diff --git a/src/ast/nodes.hpp b/src/ast/nodes.hpp deleted file mode 100644 index 70dfdd0c..00000000 --- a/src/ast/nodes.hpp +++ /dev/null @@ -1,231 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace ast::nodes { - -struct TypeExpression; -struct ValueExpr; -struct Statement; - -#define NODE(name, ...) \ -struct name { \ - __VA_ARGS__ \ - name() = default; \ - name(name&&) = default; \ - name& operator=(name&&) = default; \ -} - -NODE(NameType, - std::string name; - std::vector> generics; - - NameType(std::string name, std::vector> generics) - : name(std::move(name)), generics(std::move(generics)) {} -); - -NODE(Parameter, - std::unique_ptr type; - std::string name; - - Parameter(std::unique_ptr type, std::string name) - : type(std::move(type)), name(std::move(name)) {} -); - -NODE(FunctionType, - std::vector> parameters; - std::unique_ptr returnType; - - FunctionType( - std::vector> parameters, - std::unique_ptr returnType - ) - : parameters(std::move(parameters)), returnType(std::move(returnType)) {} -); - -NODE(MethodType, - std::vector> parameters; - std::unique_ptr returnType; - bool isMutating; - - MethodType( - std::vector> parameters, - std::unique_ptr returnType, - bool isMutating - ) - : parameters(std::move(parameters)), returnType(std::move(returnType)), isMutating(isMutating) {} -); - -NODE(TypeExpression, - std::variant data; - - template - explicit TypeExpression(T value) : data(std::move(value)) {} -); - -NODE(Scope, - std::vector> statements; - - explicit Scope(std::vector> statements) - : statements(std::move(statements)) {} -); - -NODE(VariableDecl, - std::string name; - TypeExpression type; - std::unique_ptr value; - - VariableDecl( - std::string name, - TypeExpression type, - std::unique_ptr value - ) - : name(std::move(name)), - type(std::move(type)), - value(std::move(value)) {} -); - -NODE(ArrowBody, - std::unique_ptr returnValue; - - ArrowBody(std::unique_ptr returnValue) : returnValue(std::move(returnValue)) {} -); - -NODE(FunctionDecl, - std::string name; - std::vector parameters; - TypeExpression returnType; - std::variant functionBody; - - FunctionDecl( - std::string name, - std::vector parameters, - TypeExpression returnType, - std::variant functionBody - ) - : name(std::move(name)), - parameters(std::move(parameters)), - returnType(std::move(returnType)), - functionBody(std::move(functionBody)) {} -); - -NODE(MethodDecl, - std::string name; - std::vector parameters; - TypeExpression returnType; - std::variant functionBody; - bool isMutating; - - MethodDecl( - std::string name, - std::vector parameters, - TypeExpression returnType, - std::variant functionBody, - bool isMutating - ) - : name(std::move(name)), - parameters(std::move(parameters)), - returnType(std::move(returnType)), - functionBody(std::move(functionBody)), - isMutating(isMutating) {} -); - -/// The only unary operator -NODE(OperatorFlipCall, - std::unique_ptr value; - - OperatorFlipCall(std::unique_ptr value) - : value(std::move(value)) {} -); - -NODE(OperatorCall, - std::string op; - std::unique_ptr left; - std::unique_ptr right; - - OperatorCall(std::string op, std::unique_ptr left, std::unique_ptr right) - : op(std::move(op)), left(std::move(left)), right(std::move(right)) {} -); - -NODE(FunctionCall, - std::unique_ptr callee; - std::vector> arguments; - - FunctionCall(std::unique_ptr callee, std::vector> arguments) - : callee(std::move(callee)), arguments(std::move(arguments)) {} -); - -NODE(StringLiteral, - std::string data; - - explicit StringLiteral(std::string data) : data(std::move(data)) {} -); - -NODE(IntLiteral, - std::string data; - - explicit IntLiteral(std::string data) : data(data) {} -); - -NODE(FloatLiteral, - std::string data; - - explicit FloatLiteral(std::string data) : data(std::move(data)) {} -); - -NODE(IntrinsicValueSymbol, - std::string name; - std::string package; - - explicit IntrinsicValueSymbol(std::string name, std::string package) : name(std::move(name)), package(std::move(package)) {} -); - -NODE(PackageValueSymbol, - std::string name; - std::string package; - - explicit PackageValueSymbol(std::string name, std::string package) : name(std::move(name)), package(std::move(package)) {} -); - -NODE(ValueSymbol, - std::string name; - - explicit ValueSymbol(std::string name) : name(std::move(name)) {} -); - -NODE(ParenthizedValue, - std::unique_ptr data; - - explicit ParenthizedValue(std::unique_ptr value) : data(std::move(value)) {} -); - -NODE(ValueExpr, - std::variant data; - - template - explicit ValueExpr(T value) : data(std::move(value)) {} -); - -NODE(Statement, - std::variant data; - - template - explicit Statement(T value) : data(std::move(value)) {} -); - -using Declaration = std::variant; - -NODE(Package, - std::vector declarations; - - explicit Package(std::vector declarations) - : declarations(std::move(declarations)) {} -); - -#undef NODE - -} // namespace ast::nodes diff --git a/src/grammar/lexer.hpp b/src/grammar/lexer.hpp deleted file mode 100644 index 318ac090..00000000 --- a/src/grammar/lexer.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include "lexerint.h" -#include "str.h" -#include - -enum TokenCode { - TOK_EOF = 0, - TOK_LPAREN, - TOK_RPAREN, - TOK_LCURLY, - TOK_RCURLY, - TOK_COMMA, - TOK_COLON, - TOK_EQUAL, - TOK_DOLLAR, - TOK_THIN_ARROW, - TOK_THICK_ARROW, - TOK_AT, - TOK_EXCL, - TOK_THIS, - TOK_STRING, - TOK_IDENT, - TOK_INT, - TOK_FLOAT, - TOK_PLUS, - TOK_MINUS, - TOK_STAR, - TOK_SLASH, - TOK_TILDE, - TOK_LINEBREAK, - TOK_ERROR, -}; - -class Lexer : public LexerInterface { -public: - Lexer(const std::string& sourcePath, const std::string& source); - - static void nextToken(LexerInterface* lex); - virtual NextTokenFunc getTokenFunc() const override; - virtual string tokenDesc() const override; - virtual string tokenKindDesc(int kind) const override; - - void reportParseError() const; - - const std::string& sourcePath() const { return sourcePath_; } - int tokenLine() const { return tokenLine_; } - int tokenColumn() const { return tokenColumn_; } - int tokenEndColumn() const { return tokenEndColumn_; } - -private: - std::string sourcePath_; - const std::string& source_; - const char* cursor_; - const char* marker_; - const char* limit_; - const char* lineStart_; - int line_; - int tokenLine_; - int tokenColumn_; - int tokenEndColumn_; - std::string currentLexeme_; - - int columnFor(const char* ptr) const; - void updateLocation(const char* begin, const char* end); - void setCurrentToken(int token, SemanticValue value, const char* begin, const char* end, int startLine, int startColumn); - std::string describeToken(int token, SemanticValue value, const char* begin, const char* end) const; - static const char* tokenName(int token); -}; diff --git a/src/grammar/lexer.re b/src/grammar/lexer.re deleted file mode 100644 index 9eba971d..00000000 --- a/src/grammar/lexer.re +++ /dev/null @@ -1,273 +0,0 @@ -#include "grammar/lexer.hpp" -#include "useract.h" -#include -#include - -static std::string toStr(const char* b, const char* e) { - return std::string(b, static_cast(e - b)); -} - -static std::string unescape(const char* b, const char* e) { - std::string out; - out.reserve(static_cast(e - b)); - while (b < e) { - if (*b == '\\' && b + 1 < e) { - ++b; - switch (*b) { - case '"': out += '"'; break; - case '\\': out += '\\'; break; - case 'n': out += '\n'; break; - case 't': out += '\t'; break; - default: out += '\\'; out += *b; break; - } - } else { - out += *b; - } - ++b; - } - return out; -} - -static std::string findLine(const std::string& source, int lineNumber) { - int currentLine = 1; - size_t lineStart = 0; - - while (lineStart <= source.size()) { - size_t lineEnd = source.find('\n', lineStart); - if (lineEnd == std::string::npos) - lineEnd = source.size(); - - if (currentLine == lineNumber) - return source.substr(lineStart, lineEnd - lineStart); - - if (lineEnd == source.size()) - break; - - lineStart = lineEnd + 1; - ++currentLine; - } - - return std::string(); -} - -Lexer::Lexer(const std::string& sourcePath, const std::string& source) - : sourcePath_(sourcePath), - source_(source), - cursor_(source.c_str()), - marker_(source.c_str()), - limit_(source.c_str() + source.size()), - lineStart_(source.c_str()), - line_(1), - tokenLine_(1), - tokenColumn_(1), - tokenEndColumn_(1) { - type = TOK_EOF; - sval = NULL_SVAL; - loc = SL_UNKNOWN; -} - -LexerInterface::NextTokenFunc Lexer::getTokenFunc() const { - return &Lexer::nextToken; -} - -int Lexer::columnFor(const char* ptr) const { - return static_cast(ptr - lineStart_) + 1; -} - -void Lexer::updateLocation(const char* begin, const char* end) { - for (const char* cursor = begin; cursor < end; ++cursor) { - if (*cursor == '\n') { - ++line_; - lineStart_ = cursor + 1; - } - } -} - -void Lexer::setCurrentToken(int token, SemanticValue value, const char* begin, const char* end, int startLine, int startColumn) { - updateLocation(begin, end); - type = token; - sval = value; - loc = SL_UNKNOWN; - tokenLine_ = startLine; - tokenColumn_ = startColumn; - tokenEndColumn_ = columnFor(end); - currentLexeme_ = describeToken(token, value, begin, end); -} - -std::string Lexer::describeToken(int token, SemanticValue value, const char* begin, const char* end) const { - if (token == TOK_STRING || token == TOK_IDENT || token == TOK_INT || token == TOK_FLOAT) { - const auto* text = reinterpret_cast(value); - return text != nullptr ? *text : std::string(); - } - - if (token == TOK_EOF) - return std::string(); - - return toStr(begin, end); -} - -const char* Lexer::tokenName(int token) { - switch (token) { - case TOK_EOF: return "end of file"; - case TOK_LPAREN: return "("; - case TOK_RPAREN: return ")"; - case TOK_LCURLY: return "{"; - case TOK_RCURLY: return "}"; - case TOK_COMMA: return ","; - case TOK_COLON: return ":"; - case TOK_EQUAL: return "="; - case TOK_DOLLAR: return "$"; - case TOK_THIN_ARROW: return "->"; - case TOK_THICK_ARROW: return "=>"; - case TOK_AT: return "@"; - case TOK_EXCL: return "!"; - case TOK_THIS: return "this"; - case TOK_STRING: return "string"; - case TOK_IDENT: return "identifier"; - case TOK_INT: return "int"; - case TOK_FLOAT: return "float"; - case TOK_PLUS: return "+"; - case TOK_MINUS: return "-"; - case TOK_STAR: return "*"; - case TOK_SLASH: return "/"; - case TOK_TILDE: return "~"; - case TOK_LINEBREAK: return "\\n"; - case TOK_ERROR: return "invalid token"; - default: return "unknown token"; - } -} - -string Lexer::tokenDesc() const { - if (type == TOK_EOF) - return string("end of file"); - - if (type == TOK_STRING || type == TOK_IDENT || type == TOK_INT || type == TOK_FLOAT) - return string(currentLexeme_.c_str()); - - return string(tokenName(type)); -} - -string Lexer::tokenKindDesc(int kind) const { - return string(tokenName(kind)); -} - -void Lexer::reportParseError() const { - std::cerr << sourcePath_ << ":" << tokenLine_ << ":" << tokenColumn_ << ": error: unexpected " - << (type == TOK_EOF ? "end of file" : currentLexeme_) << "\n"; - - const std::string line = findLine(source_, tokenLine_); - if (line.empty()) - return; - - const std::string lineNumber = std::to_string(tokenLine_); - std::cerr << lineNumber << " | " << line << "\n"; - - std::string caretLine; - caretLine.reserve(lineNumber.size() + 3 + line.size()); - caretLine.append(lineNumber.size(), ' '); - caretLine += " | "; - for (int column = 1; column < tokenColumn_; ++column) - caretLine += static_cast(column - 1) < line.size() && line[static_cast(column - 1)] == '\t' ? '\t' : ' '; - - const int highlightWidth = std::max(1, tokenEndColumn_ - tokenColumn_); - caretLine.append(static_cast(highlightWidth), '^'); - std::cerr << caretLine << "\n"; -} - -void Lexer::nextToken(LexerInterface* base) { - auto* lexer = static_cast(base); - for (;;) { - if (lexer->cursor_ >= lexer->limit_) { - lexer->type = TOK_EOF; - lexer->sval = NULL_SVAL; - lexer->loc = SL_UNKNOWN; - lexer->tokenLine_ = lexer->line_; - lexer->tokenColumn_ = lexer->columnFor(lexer->cursor_); - lexer->tokenEndColumn_ = lexer->tokenColumn_; - lexer->currentLexeme_.clear(); - return; - } - - const char* start = lexer->cursor_; - const int startLine = lexer->line_; - const int startColumn = lexer->columnFor(start); - int tok = TOK_ERROR; - SemanticValue sval = NULL_SVAL; - - #define cursor lexer->cursor_ - #define marker lexer->marker_ - #define limit lexer->limit_ - - /*!re2c - re2c:flags:utf-8 = 1; - re2c:define:YYCTYPE = "char"; - re2c:define:YYCURSOR = cursor; - re2c:define:YYLIMIT = limit; - re2c:define:YYMARKER = marker; - re2c:yyfill:enable = 0; - - nonascii = [\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]; - ident = [a-zA-Z_] | nonascii; - str_char = [^"\\] | "\\" [^]; - digit = [0-9]; - digits = digit+; - sw_digits = digit{1,3} ("'" digit{3})*; - int_lit = sw_digits | digits; - float_lit = sw_digits "." digits | digits "." digits; - - [ \t]+ { - lexer->updateLocation(start, cursor); - continue; - } - [\r\n]+ { tok = TOK_LINEBREAK; goto done; } - "=" { tok = TOK_EQUAL; goto done; } - "(" { tok = TOK_LPAREN; goto done; } - ")" { tok = TOK_RPAREN; goto done; } - "{" { tok = TOK_LCURLY; goto done; } - "}" { tok = TOK_RCURLY; goto done; } - "," { tok = TOK_COMMA; goto done; } - ":" { tok = TOK_COLON; goto done; } - "!" { tok = TOK_EXCL; goto done; } - "~" { tok = TOK_TILDE; goto done; } - "+" { tok = TOK_PLUS; goto done; } - "-" { tok = TOK_MINUS; goto done; } - "*" { tok = TOK_STAR; goto done; } - "/" { tok = TOK_SLASH; goto done; } - - "$" { tok = TOK_DOLLAR; goto done; } - "@" { tok = TOK_AT; goto done; } - "->" { tok = TOK_THIN_ARROW; goto done; } - "=>" { tok = TOK_THICK_ARROW; goto done; } - - float_lit { - sval = reinterpret_cast(new std::string(toStr(start, cursor))); - tok = TOK_FLOAT; goto done; - } - int_lit { - sval = reinterpret_cast(new std::string(toStr(start, cursor))); - tok = TOK_INT; goto done; - } - ["] str_char* ["] { - sval = reinterpret_cast(new std::string(unescape(start + 1, cursor - 1))); - tok = TOK_STRING; goto done; - } - "this" { tok = TOK_THIS; goto done; } - ident+ { - sval = reinterpret_cast(new std::string(toStr(start, cursor))); - tok = TOK_IDENT; goto done; - } - * { - tok = TOK_ERROR; - goto done; - } - */ - - done: - #undef cursor - #undef marker - #undef limit - - lexer->setCurrentToken(tok, sval, start, lexer->cursor_, startLine, startColumn); - return; - } -} diff --git a/src/grammar/parser.gr b/src/grammar/parser.gr deleted file mode 100644 index 5dcac17f..00000000 --- a/src/grammar/parser.gr +++ /dev/null @@ -1,494 +0,0 @@ -verbatim { - #include "ast/.hpp" - #include - #include - #include - #include - #include - - namespace grammarSupport { - - using FunctionBody = std::variant; - - template - T takeValue(T* ptr) { - T value = std::move(*ptr); - delete ptr; - return value; - } - - template - std::unique_ptr takePtr(T* ptr) { - return std::unique_ptr(ptr); - } - - inline std::string takeString(std::string* ptr) { - std::string value = std::move(*ptr); - delete ptr; - return value; - } - - inline ast::nodes::ValueExpr* makeBinary( - std::string op, - ast::nodes::ValueExpr* left, - ast::nodes::ValueExpr* right - ) { - return new ast::nodes::ValueExpr( - ast::nodes::OperatorCall( - std::move(op), - takePtr(left), - takePtr(right) - ) - ); - } - - inline ast::nodes::ValueExpr* makeFlip(ast::nodes::ValueExpr* value) { - return new ast::nodes::ValueExpr(ast::nodes::OperatorFlipCall(takePtr(value))); - } - - inline ast::nodes::ValueExpr* wrapCall(ast::nodes::FunctionCall* call) { - return new ast::nodes::ValueExpr(takeValue(call)); - } - - } // namespace grammarSupport -} - -option defaultMergeAborts; - -context_class ZaneParser : public UserActions { -public: - // generated parser hooks are added by Elkhound -}; - -terminals { - 0 : TOK_EOF; - 1 : TOK_LPAREN "("; - 2 : TOK_RPAREN ")"; - 3 : TOK_LCURLY "{"; - 4 : TOK_RCURLY "}"; - 5 : TOK_COMMA ","; - 6 : TOK_COLON ":"; - 7 : TOK_EQUAL "="; - 8 : TOK_DOLLAR "$"; - 9 : TOK_THIN_ARROW "->"; - 10 : TOK_THICK_ARROW "=>"; - 11 : TOK_AT "@"; - 12 : TOK_EXCL "!"; - 13 : TOK_THIS "this"; - 14 : TOK_STRING; - 15 : TOK_IDENT; - 16 : TOK_INT; - 17 : TOK_FLOAT; - 18 : TOK_PLUS "+"; - 19 : TOK_MINUS "-"; - 20 : TOK_STAR "*"; - 21 : TOK_SLASH "/"; - 22 : TOK_TILDE "~"; - 23 : TOK_LINEBREAK; - 24 : TOK_ERROR; - - token(std::string*) TOK_STRING { - fun dup(s) [return new std::string(*s);] - fun del(s) [delete s;] - } - token(std::string*) TOK_IDENT { - fun dup(s) [return new std::string(*s);] - fun del(s) [delete s;] - } - token(std::string*) TOK_INT { - fun dup(s) [return new std::string(*s);] - fun del(s) [delete s;] - } - token(std::string*) TOK_FLOAT { - fun dup(s) [return new std::string(*s);] - fun del(s) [delete s;] - } - - precedence { - left 20 "*" "/"; - left 10 "+" "-"; - right 30 "~"; - } -} - -nonterm(ast::nodes::Package*) package { - fun dup(p) [return p;] - fun del(p) [] - -> may_break declarations:global_scope may_break { - return new ast::nodes::Package(grammarSupport::takeValue(declarations)); - } -} - -nonterm(int) may_break { - fun dup(p) [return p;] - fun del(p) [] - -> { return 0; } - -> TOK_LINEBREAK { return 0; } -} - -nonterm(std::vector*) global_scope { - fun dup(p) [return p;] - fun del(p) [] - -> { - return new std::vector(); - } - -> declaration:declaration { - auto* list = new std::vector(); - list->push_back(grammarSupport::takeValue(declaration)); - return list; - } - -> declarations:global_scope TOK_LINEBREAK declaration:declaration { - declarations->push_back(grammarSupport::takeValue(declaration)); - return declarations; - } -} - -nonterm(ast::nodes::Declaration*) declaration { - fun dup(p) [return p;] - fun del(p) [] - -> function:function_decl { - return new ast::nodes::Declaration(grammarSupport::takeValue(function)); - } - -> method:method_decl { - return new ast::nodes::Declaration(grammarSupport::takeValue(method)); - } -} - -nonterm(ast::nodes::VariableDecl*) variable_decl { - fun dup(p) [return p;] - fun del(p) [] - -> name:TOK_IDENT type:type_expr "=" value:value_expr { - return new ast::nodes::VariableDecl( - grammarSupport::takeString(name), - grammarSupport::takeValue(type), - grammarSupport::takePtr(value) - ); - } -} - -nonterm(ast::nodes::FunctionDecl*) function_decl { - fun dup(p) [return p;] - fun del(p) [] - -> name:TOK_IDENT "(" params:parameters ")" return_type:type_expr body:function_body { - return new ast::nodes::FunctionDecl( - grammarSupport::takeString(name), - grammarSupport::takeValue(params), - grammarSupport::takeValue(return_type), - grammarSupport::takeValue(body) - ); - } -} - -nonterm(ast::nodes::MethodDecl*) method_decl { - fun dup(p) [return p;] - fun del(p) [] - -> name:TOK_IDENT "(" params:method_parameters ")" return_type:type_expr body:function_body { - return new ast::nodes::MethodDecl( - grammarSupport::takeString(name), - grammarSupport::takeValue(params), - grammarSupport::takeValue(return_type), - grammarSupport::takeValue(body), - false - ); - } - -> name:TOK_IDENT "(" params:method_parameters ")" "!" return_type:type_expr body:function_body { - return new ast::nodes::MethodDecl( - grammarSupport::takeString(name), - grammarSupport::takeValue(params), - grammarSupport::takeValue(return_type), - grammarSupport::takeValue(body), - true - ); - } -} - -nonterm(std::vector*) parameters { - fun dup(p) [return p;] - fun del(p) [] - -> { - return new std::vector(); - } - -> list:parameter_list { - return list; - } -} - -nonterm(std::vector*) parameter_list { - fun dup(p) [return p;] - fun del(p) [] - -> parameter:parameter { - auto* list = new std::vector(); - list->push_back(grammarSupport::takeValue(parameter)); - return list; - } - -> list:parameter_list "," parameter:parameter { - list->push_back(grammarSupport::takeValue(parameter)); - return list; - } -} - -nonterm(std::vector*) method_parameters { - fun dup(p) [return p;] - fun del(p) [] - -> list:method_parameter_seq { - return list; - } -} - -nonterm(std::vector*) method_parameter_seq { - fun dup(p) [return p;] - fun del(p) [] - -> "this" type:type_expr { - auto* list = new std::vector(); - list->push_back(ast::nodes::Parameter(grammarSupport::takePtr(type), "this")); - return list; - } - -> list:method_parameter_seq "," parameter:parameter { - list->push_back(grammarSupport::takeValue(parameter)); - return list; - } -} - -nonterm(ast::nodes::Parameter*) parameter { - fun dup(p) [return p;] - fun del(p) [] - -> name:TOK_IDENT type:type_expr { - return new ast::nodes::Parameter( - grammarSupport::takePtr(type), - grammarSupport::takeString(name) - ); - } -} - -nonterm(std::vector>*) type_list { - fun dup(p) [return p;] - fun del(p) [] - -> { - return new std::vector>(); - } - -> list:type_list_ne { - return list; - } -} - -nonterm(std::vector>*) type_list_ne { - fun dup(p) [return p;] - fun del(p) [] - -> expr:type_expr { - auto* list = new std::vector>(); - list->push_back(grammarSupport::takePtr(expr)); - return list; - } - -> list:type_list_ne "," expr:type_expr { - list->push_back(grammarSupport::takePtr(expr)); - return list; - } -} - -nonterm(ast::nodes::TypeExpression*) type_expr { - fun dup(p) [return p;] - fun del(p) [] - -> name:name_type { - return new ast::nodes::TypeExpression(grammarSupport::takeValue(name)); - } - -> function:function_type { - return new ast::nodes::TypeExpression(grammarSupport::takeValue(function)); - } - -> method:method_type { - return new ast::nodes::TypeExpression(grammarSupport::takeValue(method)); - } -} - -nonterm(ast::nodes::NameType*) name_type { - fun dup(p) [return p;] - fun del(p) [] - -> identifier:TOK_IDENT { - return new ast::nodes::NameType( - grammarSupport::takeString(identifier), - std::vector>() - ); - } -} - -nonterm(ast::nodes::FunctionType*) function_type { - fun dup(p) [return p;] - fun del(p) [] - -> "(" params:type_list ")" "->" return_type:type_expr { - return new ast::nodes::FunctionType( - grammarSupport::takeValue(params), - grammarSupport::takePtr(return_type) - ); - } -} - -nonterm(ast::nodes::MethodType*) method_type { - fun dup(p) [return p;] - fun del(p) [] - -> "(" "this" params:type_list_ne ")" "->" return_type:type_expr { - return new ast::nodes::MethodType( - grammarSupport::takeValue(params), - grammarSupport::takePtr(return_type), - false - ); - } - -> "(" "this" params:type_list_ne ")" "!" "->" return_type:type_expr { - return new ast::nodes::MethodType( - grammarSupport::takeValue(params), - grammarSupport::takePtr(return_type), - true - ); - } -} - -nonterm(ast::nodes::ArrowBody*) arrow_body { - fun dup(p) [return p;] - fun del(p) [] - -> "=>" value:value_expr { - return new ast::nodes::ArrowBody(grammarSupport::takePtr(value)); - } -} - -nonterm(grammarSupport::FunctionBody*) function_body { - fun dup(p) [return p;] - fun del(p) [] - -> body:arrow_body { - return new grammarSupport::FunctionBody(grammarSupport::takeValue(body)); - } - -> body:scope { - return new grammarSupport::FunctionBody(grammarSupport::takeValue(body)); - } -} - -nonterm(ast::nodes::Scope*) scope { - fun dup(p) [return p;] - fun del(p) [] - -> "{" TOK_LINEBREAK statements:statements TOK_LINEBREAK "}" { - return new ast::nodes::Scope(grammarSupport::takeValue(statements)); - } -} - -nonterm(std::vector>*) statements { - fun dup(p) [return p;] - fun del(p) [] - -> { - return new std::vector>(); - } - -> statement:statement { - auto* list = new std::vector>(); - list->push_back(grammarSupport::takePtr(statement)); - return list; - } - -> list:statements TOK_LINEBREAK statement:statement { - list->push_back(grammarSupport::takePtr(statement)); - return list; - } -} - -nonterm(ast::nodes::FunctionCall*) function_call { - fun dup(p) [return p;] - fun del(p) [] - -> callee:value_expr "(" args: arguments ")" { - return new ast::nodes::FunctionCall( - std::make_unique(grammarSupport::takeValue(callee)), - grammarSupport::takeValue(args) - ); - } -} - -nonterm(ast::nodes::Statement*) statement { - fun dup(p) [return p;] - fun del(p) [] - -> call:function_call { - return new ast::nodes::Statement(grammarSupport::takeValue(call)); - } - -> declaration:variable_decl { - return new ast::nodes::Statement(grammarSupport::takeValue(declaration)); - } -} - -nonterm(ast::nodes::ValueExpr*) value_expr { - fun dup(p) [return p;] - fun del(p) [] - -> identifier:TOK_IDENT { - return new ast::nodes::ValueExpr(ast::nodes::ValueSymbol(grammarSupport::takeString(identifier))); - } - -> package:TOK_IDENT "$" identifier:TOK_IDENT { - return new ast::nodes::ValueExpr( - ast::nodes::PackageValueSymbol( - grammarSupport::takeString(identifier), - grammarSupport::takeString(package) - ) - ); - } - -> "@" package:TOK_IDENT "$" identifier:TOK_IDENT { - return new ast::nodes::ValueExpr( - ast::nodes::IntrinsicValueSymbol( - grammarSupport::takeString(identifier), - grammarSupport::takeString(package) - ) - ); - } - -> integer:TOK_INT { - return new ast::nodes::ValueExpr(ast::nodes::IntLiteral(grammarSupport::takeString(integer))); - } - -> number:TOK_FLOAT { - return new ast::nodes::ValueExpr(ast::nodes::FloatLiteral(grammarSupport::takeString(number))); - } - -> text:TOK_STRING { - return new ast::nodes::ValueExpr(ast::nodes::StringLiteral(grammarSupport::takeString(text))); - } - -> value:parenthized_value { - return new ast::nodes::ValueExpr(grammarSupport::takeValue(value)); - } - -> call:function_call { - return new ast::nodes::ValueExpr(grammarSupport::takeValue(call)); - } - -> "~" expr:value_expr precedence("~") { - return grammarSupport::makeFlip(expr); - } - -> left:value_expr "*" right:value_expr { - return grammarSupport::makeBinary("*", left, right); - } - -> left:value_expr "/" right:value_expr { - return grammarSupport::makeBinary("/", left, right); - } - -> left:value_expr "+" right:value_expr { - return grammarSupport::makeBinary("+", left, right); - } - -> left:value_expr "-" right:value_expr { - return grammarSupport::makeBinary("-", left, right); - } -} - -nonterm(ast::nodes::ParenthizedValue*) parenthized_value { - fun dup(p) [return p;] - fun del(p) [] - -> "(" value:value_expr ")" { - return new ast::nodes::ParenthizedValue(grammarSupport::takePtr(value)); - } -} - -nonterm(std::vector>*) arguments { - fun dup(p) [return p;] - fun del(p) [] - -> { - return new std::vector>(); - } - -> list:argument_list { - return list; - } -} - -nonterm(std::vector>*) argument_list { - fun dup(p) [return p;] - fun del(p) [] - -> value:value_expr { - auto* list = new std::vector>(); - list->push_back(grammarSupport::takePtr(value)); - return list; - } - -> list:argument_list "," value:value_expr { - list->push_back(grammarSupport::takePtr(value)); - return list; - } -} diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 0505348c..00000000 --- a/src/main.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "ast/.hpp" -#include "glr.h" -#include "grammar/lexer.hpp" -#include "zane_parser.h" -#include -#include -#include - -std::string readFile(const std::string& path) { - std::ifstream file(path); - if (!file.is_open()) - throw std::runtime_error("Could not open file: " + path); - return std::string((std::istreambuf_iterator(file)), - std::istreambuf_iterator()); -} - -int main() { - const std::string inputPath = "test-parser/main.zn"; - std::string input = readFile(inputPath); - Lexer lexer(inputPath, input); - Lexer::nextToken(&lexer); - - ZaneParser parser; - GLR glr(&parser, parser.makeTables()); - glr.noisyFailedParse = false; - - SemanticValue result = NULL_SVAL; - const bool success = glr.glrParse(lexer, result); - if (!success) { - lexer.reportParseError(); - return 1; - } - - auto* ast = reinterpret_cast(result); - - if (ast != nullptr) { - std::cout << (ast::evaluators::ToGraph {}(*ast)).render(); - delete ast; - } - - return 0; -} diff --git a/src/treegraph/.hpp b/src/treegraph/.hpp deleted file mode 100644 index 766afa4c..00000000 --- a/src/treegraph/.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "treegraph/evaluator.hpp" -#include "treegraph/build.hpp" -#include "treegraph/structure.hpp" diff --git a/src/treegraph/build.hpp b/src/treegraph/build.hpp deleted file mode 100644 index d5cf588b..00000000 --- a/src/treegraph/build.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include "treegraph/structure.hpp" -#include -#include -#include - -namespace treegraph { - -inline std::unique_ptr ptr(Node node) { - return std::make_unique(std::move(node)); -} - -inline std::unique_ptr string(std::string value) { - return ptr(Node{std::move(value)}); -} - -inline std::unique_ptr table(Table table) { - return ptr(Node{std::move(table)}); -} - -inline std::unique_ptr list(List list) { - return ptr(Node{std::move(list)}); -} - -} // namespace treegraph diff --git a/src/treegraph/evaluator.hpp b/src/treegraph/evaluator.hpp deleted file mode 100644 index 646af9c8..00000000 --- a/src/treegraph/evaluator.hpp +++ /dev/null @@ -1,165 +0,0 @@ -#pragma once - -#include "treegraph/structure.hpp" -#include -#include -#include - -namespace treegraph { - -namespace detail { - -inline std::vector splitLines(const std::string& text) { - std::istringstream ss(text); - std::vector lines; - std::string line; - while (std::getline(ss, line)) - lines.push_back(line); - return lines; -} - -// Indents every line after the first with `prefix`. -inline std::string indent(const std::string& text, const std::string& prefix) { - const auto lines = splitLines(text); - if (lines.empty()) return {}; - std::string result = lines.front(); - for (std::size_t i = 1; i < lines.size(); ++i) - result += "\n" + prefix + lines[i]; - return result; -} - -// Renders a single named branch: "label: firstLine\n continuation..." -inline std::string branch(const std::string& label, const std::string& subtree) { - const auto lines = splitLines(subtree); - if (lines.empty()) return label; - std::string result = label + ": " + lines.front(); - for (std::size_t i = 1; i < lines.size(); ++i) - result += "\n " + lines[i]; - return result; -} - -// Renders a labelled node with ├──/└── children. -inline std::string node(const std::string& label, const std::vector& children) { - if (children.empty()) return label; - std::string result = label; - for (std::size_t i = 0; i < children.size(); ++i) { - const bool last = (i + 1 == children.size()); - result += "\n"; - result += last ? "└── " : "├── "; - result += indent(children[i], last ? " " : "│ "); - } - return result; -} - -} // namespace detail - -struct Evaluator { - std::string render(const Node& node) const { - return std::visit([&](const auto& data) { - return (*this)(data); - }, node.data); - } - - std::string render(const std::string& key, const Node& node) const { - return std::visit([&](const auto& data) { - return renderWith(key, data); - }, node.data); - } - - std::string operator()(const Node& node) const { return render(node); } - - std::string operator()(const std::string& key, const Node& node) const { return render(key, node); } - - std::string operator()(const Table& table) const { - std::vector rows; - for (const auto& [key, child] : table.children) - appendRenderedChild(rows, key, *child); - return joinLines(rows); - } - - std::string operator()(const List& list) const { - std::vector items; - for (const auto& [key, child] : list.children) - items.push_back(render(key, *child)); - return joinLines(items); - } - - std::string operator()(const std::string& str) const { return str; } - -private: - void appendRenderedChild(std::vector& rows, const std::string& key, const Node& node) const { - if (const auto* list = std::get_if(&node.data)) { - const auto items = renderListEntries(key, *list); - rows.insert(rows.end(), items.begin(), items.end()); - return; - } - rows.push_back(render(key, node)); - } - - std::vector renderListEntries(const std::string& key, const List& list) const { - std::vector children; - for (std::size_t i = 0; i < list.children.size(); ++i) { - const auto& [itemKey, child] = list.children[i]; - children.push_back(render(key + "[" + std::to_string(i) + "]", itemKey, *child)); - } - return children; - } - - std::string render(const std::string& indexedKey, const std::string& itemKey, const Node& node) const { - return std::visit([&](const auto& data) { - return renderIndexed(indexedKey, itemKey, data); - }, node.data); - } - - std::string renderWith(const std::string& key, const std::string& value) const { - return value.empty() ? key : key + ": " + value; - } - - std::string renderWith(const std::string& key, const Table& table) const { - std::vector children; - for (const auto& [childKey, child] : table.children) - appendRenderedChild(children, childKey, *child); - return detail::node(key, children); - } - - std::string renderWith(const std::string& key, const List& list) const { - return detail::node(key, renderListEntries(key, list)); - } - - std::string renderIndexed(const std::string& indexedKey, const std::string& itemKey, const std::string& value) const { - if (itemKey.empty()) - return value.empty() ? indexedKey : indexedKey + ": " + value; - const auto label = value.empty() ? itemKey : itemKey + ": " + value; - return detail::node(indexedKey, {label}); - } - - std::string renderIndexed(const std::string& indexedKey, const std::string& itemKey, const Table& table) const { - std::vector children; - for (const auto& [childKey, child] : table.children) - appendRenderedChild(children, childKey, *child); - if (itemKey.empty()) - return detail::node(indexedKey, children); - return detail::node(indexedKey, {detail::node(itemKey, children)}); - } - - std::string renderIndexed(const std::string& indexedKey, const std::string& itemKey, const List& list) const { - if (itemKey.empty()) - return detail::node(indexedKey, renderListEntries(indexedKey, list)); - return detail::node(indexedKey, {detail::node(itemKey, renderListEntries(indexedKey, list))}); - } - - static std::string joinLines(const std::vector& parts) { - std::string result; - for (std::size_t i = 0; i < parts.size(); ++i) { - if (i > 0) result += "\n"; - result += parts[i]; - } - return result; - } -}; - -inline std::string Node::render() const { - return Evaluator{}.render(*this); -} - -} // namespace treegraph diff --git a/src/treegraph/structure.hpp b/src/treegraph/structure.hpp deleted file mode 100644 index 3da46509..00000000 --- a/src/treegraph/structure.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -namespace treegraph { - -struct Node; - -struct Table { - std::map> children; - - Table() = default; - explicit Table(std::map> children) - : children(std::move(children)) {} - - Table& insert(std::string key, std::unique_ptr node) { - children.insert_or_assign(std::move(key), std::move(node)); - return *this; - } -}; - -struct List { - std::vector>> children; - - List() = default; - explicit List(std::vector>> children) - : children(std::move(children)) {} - - List& push(std::string key, std::unique_ptr node) { - children.emplace_back(std::move(key), std::move(node)); - return *this; - } -}; - -struct Node { - std::variant data; - - Node() = default; - explicit Node(Table data) : data(std::move(data)) {} - explicit Node(List data) : data(std::move(data)) {} - explicit Node(std::string data) : data(std::move(data)) {} - - std::string render() const; -}; - -} // namespace treegraph diff --git a/src/types/primitives.hpp b/src/types/primitives.hpp deleted file mode 100644 index aabeee5a..00000000 --- a/src/types/primitives.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include -#include - -using i64 = std::int64_t; -using f64 = double; - -inline bool try_build_i64(std::string_view s, i64& out) { - auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), out); - return ec == std::errc{} && ptr == s.data() + s.size(); -} - -inline bool try_build_f64(std::string_view s, f64& out) { - auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), out); - return ec == std::errc{} && ptr == s.data() + s.size(); -} diff --git a/src/types/stack.hpp b/src/types/stack.hpp deleted file mode 100644 index e7f5a8b6..00000000 --- a/src/types/stack.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include -template -class Stack { - std::vector stack; -public: - Stack() = default; - void push(T element) { stack.push_back(element); } - bool empty() const { return stack.empty(); } - T& top() { return stack.back(); } - T top() const { return stack.back(); } - T pop() { - if (stack.empty()) return {}; - auto value = stack.back(); - stack.pop_back(); - return value; - } - auto rbegin() { return stack.rbegin(); } - auto rend() { return stack.rend(); } - auto begin() { return stack.begin(); } - auto end() { return stack.end(); } -}; diff --git a/src/types/variant.hpp b/src/types/variant.hpp deleted file mode 100644 index 1108fd9d..00000000 --- a/src/types/variant.hpp +++ /dev/null @@ -1,239 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -// Helper for overloading lambdas -template -struct overloaded : Ts... { - using Ts::operator()...; -}; - -template -overloaded(Ts...) -> overloaded; - -// Helper function to load a variant at a specific index -template -void loadVariantAt(std::size_t idx, std::variant& var, Archive& ar) { - if constexpr (I < sizeof...(Types)) { - if (I == idx) { - std::variant_alternative_t> val; - ar(val); - var = std::move(val); - } else { - loadVariantAt(idx, var, ar); - } - } -} - -// Returns invoke_result_t if invocable, otherwise void. -// Used by match() to probe what return type each callback produces. -template -struct safe_invoke_result { using type = void; }; -template -struct safe_invoke_result>> { - using type = std::invoke_result_t; -}; - -// Walks a type list and picks the first non-void type, or Default if all are void. -// Lets match() find the real return type even when some alternatives are unhandled. -template -struct first_non_void_or { using type = Default; }; -template -struct first_non_void_or { - using type = std::conditional_t, T, - typename first_non_void_or::type>; -}; - -template -struct Variant { - std::variant value; - - Variant() = default; - Variant(std::variant value) - : value(std::move(value)) {} - - template, Types> || ...)>> - Variant(T&& val) : value(std::forward(val)) {} - - template, Types> || ...)>> - Variant& operator=(T&& val) { - value = std::forward(val); - return *this; - } - - // visit: accepts a single callable (use match for multiple lambdas) - template - decltype(auto) visit(Callback&& callback) { - return std::visit(std::forward(callback), value); - } - - template - decltype(auto) visit(Callback&& callback) const { - return std::visit(std::forward(callback), value); - } - - template - bool is() const { - return (std::holds_alternative(value) || ...); - } - - template - T* getIf() { - return std::get_if(&value); - } - - template - const T* getIf() const { - return std::get_if(&value); - } - - // match: handles a subset of types; unhandled alternatives return R{} (or void). - // The catch-all return type is deduced from the provided callbacks so that - // returning a value (e.g. std::string) works without an explicit default case. - template - decltype(auto) match(Callbacks&&... callbacks) { - using Visitor = overloaded...>; - using R = typename first_non_void_or::type... - >::type; - - if constexpr (std::is_void_v) { - return std::visit( - overloaded{ std::forward(callbacks)..., [](auto&&) {} }, - value - ); - } else { - return std::visit( - overloaded{ std::forward(callbacks)..., [](auto&&) -> R { return R{}; } }, - value - ); - } - } - - template - decltype(auto) match(Callbacks&&... callbacks) const { - using Visitor = overloaded...>; - using R = typename first_non_void_or::type... - >::type; - - if constexpr (std::is_void_v) { - return std::visit( - overloaded{ std::forward(callbacks)..., [](auto&&) {} }, - value - ); - } else { - return std::visit( - overloaded{ std::forward(callbacks)..., [](auto&&) -> R { return R{}; } }, - value - ); - } - } - - template - void save(Archive& ar) const { - ar(value.index()); - std::visit([&ar](const auto& v) { ar(v); }, value); - } - - template - void load(Archive& ar) { - std::size_t idx; - ar(idx); - loadVariantAt<0>(idx, value, ar); - } - - bool operator==(const Variant&) const = default; -}; - -template class Wrapper, typename... Types> -struct WrappingVariant { - std::variant...> value; - - WrappingVariant() = default; - WrappingVariant(std::variant...> value) - : value(std::move(value)) {} - - template, Wrapper> || ...)>> - WrappingVariant(T&& val) : value(std::forward(val)) {} - - template, Wrapper> || ...)>> - WrappingVariant& operator=(T&& val) { - value = std::forward(val); - return *this; - } - - // visit: accepts a single callable (use match for multiple lambdas) - template - decltype(auto) visit(Callback&& callback) { - return std::visit(std::forward(callback), value); - } - - template - decltype(auto) visit(Callback&& callback) const { - return std::visit(std::forward(callback), value); - } - - // match: handles a subset of types; unhandled alternatives return R{} (or void). - template - decltype(auto) match(Callbacks&&... callbacks) { - using Visitor = overloaded...>; - using R = typename first_non_void_or&>::type... - >::type; - - if constexpr (std::is_void_v) { - return std::visit( - overloaded{ std::forward(callbacks)..., [](auto&&) {} }, - value - ); - } else { - return std::visit( - overloaded{ std::forward(callbacks)..., [](auto&&) -> R { return R{}; } }, - value - ); - } - } - - template - decltype(auto) match(Callbacks&&... callbacks) const { - using Visitor = overloaded...>; - using R = typename first_non_void_or&>::type... - >::type; - - if constexpr (std::is_void_v) { - return std::visit( - overloaded{ std::forward(callbacks)..., [](auto&&) {} }, - value - ); - } else { - return std::visit( - overloaded{ std::forward(callbacks)..., [](auto&&) -> R { return R{}; } }, - value - ); - } - } - - template - void save(Archive& ar) const { - ar(value.index()); - std::visit([&ar](const auto& v) { ar(v); }, value); - } - - template - void load(Archive& ar) { - std::size_t idx; - ar(idx); - loadVariantAt<0>(idx, value, ar); - } - - bool operator==(const WrappingVariant&) const = default; -}; diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json deleted file mode 100644 index 01e44599..00000000 --- a/vcpkg-configuration.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "default-registry": { - "kind": "git", - "baseline": "4e39a8622e56a113c89228e4e13944dce8654da7", - "repository": "https://github.com/microsoft/vcpkg" - }, - "registries": [ - { - "kind": "artifact", - "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", - "name": "microsoft" - } - ], - "overlay-ports": [ - "vcpkg-ports" - ] -} diff --git a/vcpkg-ports/elkhound-runtime/CMakeLists.txt b/vcpkg-ports/elkhound-runtime/CMakeLists.txt deleted file mode 100644 index e1afcb14..00000000 --- a/vcpkg-ports/elkhound-runtime/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -cmake_minimum_required(VERSION 3.20) - -project(elkhound_runtime LANGUAGES C CXX) - -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -include(CMakePackageConfigHelpers) - -set(ELKHOUND_RUNTIME_SOURCES - src/elkhound/cyctimer.cc - src/elkhound/emitcode.cc - src/elkhound/glr.cc - src/elkhound/parsetables.cc - src/elkhound/ptreeact.cc - src/elkhound/ptreenode.cc - src/elkhound/useract.cc - src/smbase/autofile.cc - src/smbase/bflatten.cc - src/smbase/bit2d.cc - src/smbase/bitarray.cc - src/smbase/breaker.cpp - src/smbase/crc.cpp - src/smbase/cycles.c - src/smbase/datablok.cpp - src/smbase/exc.cpp - src/smbase/flatten.cc - src/smbase/gprintf.c - src/smbase/growbuf.cc - src/smbase/hashline.cc - src/smbase/hashtbl.cc - src/smbase/malloc_stub.c - src/smbase/mysig.cc - src/smbase/nonport.cpp - src/smbase/point.cc - src/smbase/srcloc.cc - src/smbase/str.cpp - src/smbase/strdict.cc - src/smbase/strhash.cc - src/smbase/stringset.cc - src/smbase/strtokp.cpp - src/smbase/strutil.cc - src/smbase/svdict.cc - src/smbase/syserr.cpp - src/smbase/trace.cc - src/smbase/trdelete.cc - src/smbase/vdtllist.cc - src/smbase/voidlist.cc - src/smbase/vptrmap.cc -) - -file(GLOB ELKHOUND_RUNTIME_HEADERS CONFIGURE_DEPENDS - "${CMAKE_CURRENT_SOURCE_DIR}/src/elkhound/*.h" - "${CMAKE_CURRENT_SOURCE_DIR}/src/smbase/*.h" -) - -add_library(elkhound_runtime STATIC ${ELKHOUND_RUNTIME_SOURCES}) -add_library(elkhound_runtime::elkhound_runtime ALIAS elkhound_runtime) - -target_compile_definitions(elkhound_runtime PRIVATE __UNIX__) -target_include_directories(elkhound_runtime - PUBLIC - $ - $ - $ -) - -install(TARGETS elkhound_runtime EXPORT elkhound_runtimeTargets ARCHIVE DESTINATION lib LIBRARY DESTINATION lib RUNTIME DESTINATION bin) -install(FILES ${ELKHOUND_RUNTIME_HEADERS} DESTINATION include/elkhound_runtime) - -write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/elkhound_runtimeConfigVersion.cmake" - VERSION 1.0.0 - COMPATIBILITY SameMajorVersion -) - -configure_package_config_file( - "${CMAKE_CURRENT_SOURCE_DIR}/elkhound_runtimeConfig.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/elkhound_runtimeConfig.cmake" - INSTALL_DESTINATION share/elkhound_runtime -) - -install(EXPORT elkhound_runtimeTargets NAMESPACE elkhound_runtime:: DESTINATION share/elkhound_runtime) -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/elkhound_runtimeConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/elkhound_runtimeConfigVersion.cmake" - DESTINATION share/elkhound_runtime -) diff --git a/vcpkg-ports/elkhound-runtime/elkhound_runtimeConfig.cmake.in b/vcpkg-ports/elkhound-runtime/elkhound_runtimeConfig.cmake.in deleted file mode 100644 index eeb14081..00000000 --- a/vcpkg-ports/elkhound-runtime/elkhound_runtimeConfig.cmake.in +++ /dev/null @@ -1,3 +0,0 @@ -@PACKAGE_INIT@ - -include("${CMAKE_CURRENT_LIST_DIR}/elkhound_runtimeTargets.cmake") diff --git a/vcpkg-ports/elkhound-runtime/portfile.cmake b/vcpkg-ports/elkhound-runtime/portfile.cmake deleted file mode 100644 index 175176d6..00000000 --- a/vcpkg-ports/elkhound-runtime/portfile.cmake +++ /dev/null @@ -1,22 +0,0 @@ -# Source: WeiDUorg/elkhound (https://github.com/WeiDUorg/elkhound) -# The REF below must match the rev in nix/elkhound/flake.nix. -vcpkg_from_github( - OUT_SOURCE_PATH SOURCE_PATH - REPO WeiDUorg/elkhound - REF b8f5589de119c89b36b1fc21d2f51c4a942ee3a8 - SHA512 f284e6750adda2a9795503cc2dff21cabba89e65d3c2e0e638f5393b09f84d16f8ef005c9ca937f93b50456a6f197b8bfaec8ce40863d59c77108d34bb74c54c - HEAD_REF master -) - -file(COPY "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt" DESTINATION "${SOURCE_PATH}") -file(COPY "${CMAKE_CURRENT_LIST_DIR}/elkhound_runtimeConfig.cmake.in" DESTINATION "${SOURCE_PATH}") - -vcpkg_configure_cmake( - SOURCE_PATH "${SOURCE_PATH}" -) - -vcpkg_install_cmake() -vcpkg_fixup_cmake_targets(CONFIG_PATH share/elkhound_runtime TARGET_PATH share/elkhound_runtime) - -file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") -file(INSTALL "${SOURCE_PATH}/license.txt" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright) diff --git a/vcpkg-ports/elkhound-runtime/vcpkg.json b/vcpkg-ports/elkhound-runtime/vcpkg.json deleted file mode 100644 index 0cc45f9d..00000000 --- a/vcpkg-ports/elkhound-runtime/vcpkg.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "elkhound-runtime", - "version-string": "2026-05-28", - "description": "Elkhound parser runtime library bundled with smbase", - "homepage": "https://github.com/WeiDUorg/elkhound", - "license": "BSD-3-Clause" -} diff --git a/vcpkg.json b/vcpkg.json deleted file mode 100644 index 66ae5cda..00000000 --- a/vcpkg.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "dependencies": [ - "nlohmann-json", - "cereal", - "elkhound-runtime" - ] -} From 304eab9d0d5b071a2129d3f66ad407a6fffcec14 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 2 Jun 2026 18:28:04 +0200 Subject: [PATCH 070/154] initialize dune proj --- bin/dune | 4 + bin/main.ml | 1 + devbox.json | 13 +- devbox.lock | 458 +++++++++++++++++++++++++++++++++++++ dune-project | 26 +++ lib/dune | 2 + test/dune | 3 + test/test_zane_compiler.ml | 0 zane-compiler.opam | 0 9 files changed, 505 insertions(+), 2 deletions(-) create mode 100644 bin/dune create mode 100644 bin/main.ml create mode 100644 dune-project create mode 100644 lib/dune create mode 100644 test/dune create mode 100644 test/test_zane_compiler.ml create mode 100644 zane-compiler.opam diff --git a/bin/dune b/bin/dune new file mode 100644 index 00000000..27437529 --- /dev/null +++ b/bin/dune @@ -0,0 +1,4 @@ +(executable + (public_name zane-compiler) + (name main) + (libraries zane_compiler)) diff --git a/bin/main.ml b/bin/main.ml new file mode 100644 index 00000000..7bf6048f --- /dev/null +++ b/bin/main.ml @@ -0,0 +1 @@ +let () = print_endline "Hello, World!" diff --git a/devbox.json b/devbox.json index 80917c8f..ee5e554e 100644 --- a/devbox.json +++ b/devbox.json @@ -9,13 +9,22 @@ "upx@latest", "ninja@latest", "zig@latest", - "clang-tools@latest" + "clang-tools@latest", + "dune@latest", + "opam@latest", + "ocaml@latest", + "gnumake@latest", + "pkg-config@latest", + "m4@latest", + "zstd@latest" ], "shell": { "init_hook": [ "echo 'Welcome to devbox!'", "export PATH=$(realpath $DEVBOX_PROJECT_ROOT/bin):$PATH", - "export LLVM_CONFIG=$(realpath $DEVBOX_PROJECT_ROOT/.devbox/nix/profile/default/bin/llvm-config)" + "export LLVM_CONFIG=$(realpath $DEVBOX_PROJECT_ROOT/.devbox/nix/profile/default/bin/llvm-config)", + "export LD_LIBRARY_PATH=$(dirname $(find /nix/store -name 'libzstd.so.1' | head -n 1)):$LD_LIBRARY_PATH", + "eval $(opam env)" ], "scripts": { "test": [ diff --git a/devbox.lock b/devbox.lock index 93e968bc..ca87f49a 100644 --- a/devbox.lock +++ b/devbox.lock @@ -153,10 +153,166 @@ } } }, + "dune@latest": { + "last_modified": "2026-05-21T08:15:18Z", + "resolved": "github:NixOS/nixpkgs/4a29d733e8a7d5b824c3d8c958a946a9867b3eb2#dune", + "source": "devbox-search", + "version": "3.21.1", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/i62ga7dgh2zx0wkwq5bhp7r0aq5l1qic-dune-3.21.1", + "default": true + } + ], + "store_path": "/nix/store/i62ga7dgh2zx0wkwq5bhp7r0aq5l1qic-dune-3.21.1" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/x7srvl1r3fxqlwrgic8xci2xw4vs4fpd-dune-3.21.1", + "default": true + } + ], + "store_path": "/nix/store/x7srvl1r3fxqlwrgic8xci2xw4vs4fpd-dune-3.21.1" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/cwcy3w2hlik0xa6qirq7v7p3qpngqvcr-dune-3.21.1", + "default": true + } + ], + "store_path": "/nix/store/cwcy3w2hlik0xa6qirq7v7p3qpngqvcr-dune-3.21.1" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/3g9c7bq560gc93cjya06cgx3df0sl5yw-dune-3.21.1", + "default": true + } + ], + "store_path": "/nix/store/3g9c7bq560gc93cjya06cgx3df0sl5yw-dune-3.21.1" + } + } + }, "github:NixOS/nixpkgs/nixpkgs-unstable": { "last_modified": "2026-05-27T10:28:13Z", "resolved": "github:NixOS/nixpkgs/4100e830e085863741bc69b156ec4ccd53ab5be0?lastModified=1779877693&narHash=sha256-NOF9NAREhxr50bbBfVcVOq%2BArCMSoe8dP79Pk2uyARk%3D" }, + "gnumake@latest": { + "last_modified": "2026-05-23T11:35:32Z", + "resolved": "github:NixOS/nixpkgs/3d8f0f3f72a6cd4d93d0ad13203f2ea1cb7e1456#gnumake", + "source": "devbox-search", + "version": "4.4.1", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/8wwiw8pwyhrkzyq28hqzxfl4z84lks81-gnumake-4.4.1", + "default": true + }, + { + "name": "man", + "path": "/nix/store/wdm9prq35jlgwq6rjyhqxy4jzy833sfr-gnumake-4.4.1-man", + "default": true + }, + { + "name": "info", + "path": "/nix/store/6dbp1ysgxsrrn7xgjgf523faqrm605a5-gnumake-4.4.1-info" + }, + { + "name": "doc", + "path": "/nix/store/sl2ygvgjg4ml8dhyfxj5kh84x2bs1mhc-gnumake-4.4.1-doc" + } + ], + "store_path": "/nix/store/8wwiw8pwyhrkzyq28hqzxfl4z84lks81-gnumake-4.4.1" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/9ngw1ippk25jjj5fjxv36xbp6iq7rxdx-gnumake-4.4.1", + "default": true + }, + { + "name": "man", + "path": "/nix/store/dg3aa71vii59scbfhi02cdxnps64x6ql-gnumake-4.4.1-man", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/mdv67w2xvchbs76zjdzppdkk64z5avki-gnumake-4.4.1-debug" + }, + { + "name": "doc", + "path": "/nix/store/bybbj9avk3g107mwhgvkzkpm6mkbl8gv-gnumake-4.4.1-doc" + }, + { + "name": "info", + "path": "/nix/store/bxdqxx2q13sj15ss8z5l33jd31x55j5l-gnumake-4.4.1-info" + } + ], + "store_path": "/nix/store/9ngw1ippk25jjj5fjxv36xbp6iq7rxdx-gnumake-4.4.1" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/60y2hs45l18g56ykw9789b5vhhi2ls5q-gnumake-4.4.1", + "default": true + }, + { + "name": "man", + "path": "/nix/store/m2ba4bwmfgh994xbg1iqm6zj1mdrq8h7-gnumake-4.4.1-man", + "default": true + }, + { + "name": "info", + "path": "/nix/store/apljbm6plyajbfrnwif0a2d4nx6w0cpf-gnumake-4.4.1-info" + }, + { + "name": "doc", + "path": "/nix/store/s9y438l347nky6rkl1wfk2y3b0d9i636-gnumake-4.4.1-doc" + } + ], + "store_path": "/nix/store/60y2hs45l18g56ykw9789b5vhhi2ls5q-gnumake-4.4.1" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/d3bwqm6bymhy3pdgbvf7vxjqfp31m3j1-gnumake-4.4.1", + "default": true + }, + { + "name": "man", + "path": "/nix/store/bmvqa5ym318mymhxlwwmxq8wxal958p4-gnumake-4.4.1-man", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/q683z843wi7xs96pngh1kinnx88vn2if-gnumake-4.4.1-debug" + }, + { + "name": "doc", + "path": "/nix/store/wxg27bzsljjw4k72m9b2v6a0fx5a68s0-gnumake-4.4.1-doc" + }, + { + "name": "info", + "path": "/nix/store/03d41qgjsrhcr3fzq2z99ry07rahnj0v-gnumake-4.4.1-info" + } + ], + "store_path": "/nix/store/d3bwqm6bymhy3pdgbvf7vxjqfp31m3j1-gnumake-4.4.1" + } + } + }, "just@latest": { "last_modified": "2026-05-12T01:56:55Z", "resolved": "github:NixOS/nixpkgs/0a0bf409f3593f415d0a554f33acc63dc7dccb43#just", @@ -301,6 +457,12 @@ } } }, + "m4@latest": { + "last_modified": "2023-02-24T09:01:09Z", + "resolved": "github:NixOS/nixpkgs/7d0ed7f2e5aea07ab22ccb338d27fbe347ed2f11#m4", + "source": "devbox-search", + "version": "1.4.19" + }, "meson@latest": { "last_modified": "2026-04-23T13:07:47Z", "resolved": "github:NixOS/nixpkgs/01fbdeef22b76df85ea168fbfe1bfd9e63681b30#meson", @@ -413,6 +575,202 @@ } } }, + "ocaml@latest": { + "last_modified": "2026-05-21T08:15:18Z", + "resolved": "github:NixOS/nixpkgs/4a29d733e8a7d5b824c3d8c958a946a9867b3eb2#ocaml", + "source": "devbox-search", + "version": "5.4.1", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/81yy39njdh1d5796qn84inbqq56fh71v-ocaml-5.4.1", + "default": true + } + ], + "store_path": "/nix/store/81yy39njdh1d5796qn84inbqq56fh71v-ocaml-5.4.1" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/zrdg31hnnr0lv3xndwvh74fd160483di-ocaml-5.4.1", + "default": true + } + ], + "store_path": "/nix/store/zrdg31hnnr0lv3xndwvh74fd160483di-ocaml-5.4.1" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/2hrwc25yrvlwz6gmar9cd8zdsy89rfpa-ocaml-5.4.1", + "default": true + } + ], + "store_path": "/nix/store/2hrwc25yrvlwz6gmar9cd8zdsy89rfpa-ocaml-5.4.1" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ryj2xb3cla5jvx41pxlk8vqm0z93g5cs-ocaml-5.4.1", + "default": true + } + ], + "store_path": "/nix/store/ryj2xb3cla5jvx41pxlk8vqm0z93g5cs-ocaml-5.4.1" + } + } + }, + "opam@latest": { + "last_modified": "2026-05-21T08:15:18Z", + "resolved": "github:NixOS/nixpkgs/4a29d733e8a7d5b824c3d8c958a946a9867b3eb2#opam", + "source": "devbox-search", + "version": "2.5.1", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/6cji9in2mij7z9545lyx035vshsi9cag-opam-2.5.1", + "default": true + }, + { + "name": "installer", + "path": "/nix/store/c7gjr0dmq98scqkd5i8gpbjhlphb1gk4-opam-2.5.1-installer" + } + ], + "store_path": "/nix/store/6cji9in2mij7z9545lyx035vshsi9cag-opam-2.5.1" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ci7lqvh196kbhc8lxgd04gz7pz0mm2yq-opam-2.5.1", + "default": true + }, + { + "name": "installer", + "path": "/nix/store/1v9bx0wdr2nkfwlwddldi7gscls7qcjm-opam-2.5.1-installer" + } + ], + "store_path": "/nix/store/ci7lqvh196kbhc8lxgd04gz7pz0mm2yq-opam-2.5.1" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/3k4k7yyla8cxj8r8l688gmwd81346wsz-opam-2.5.1", + "default": true + }, + { + "name": "installer", + "path": "/nix/store/2m62nyma8h6f37vcr235f9xa560jyii0-opam-2.5.1-installer" + } + ], + "store_path": "/nix/store/3k4k7yyla8cxj8r8l688gmwd81346wsz-opam-2.5.1" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/nd0n31sr87n8n6j34ybr30v9h1z8l34l-opam-2.5.1", + "default": true + }, + { + "name": "installer", + "path": "/nix/store/xhbyql390bnwyg1if8kssdylp6y3bni9-opam-2.5.1-installer" + } + ], + "store_path": "/nix/store/nd0n31sr87n8n6j34ybr30v9h1z8l34l-opam-2.5.1" + } + } + }, + "pkg-config@latest": { + "last_modified": "2025-11-23T21:50:36Z", + "resolved": "github:NixOS/nixpkgs/ee09932cedcef15aaf476f9343d1dea2cb77e261#pkg-config", + "source": "devbox-search", + "version": "0.29.2", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/hygaaqwk9ylklp0ybwppqhw75nz8ya41-pkg-config-wrapper-0.29.2", + "default": true + }, + { + "name": "man", + "path": "/nix/store/9px0sji43x3r2w4zxl3j3idwsql7lwxx-pkg-config-wrapper-0.29.2-man", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/hqk44ra6qxw7iixardl6c3hdgb9kq6ns-pkg-config-wrapper-0.29.2-doc" + } + ], + "store_path": "/nix/store/hygaaqwk9ylklp0ybwppqhw75nz8ya41-pkg-config-wrapper-0.29.2" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/lbiigi8qbp7mzf1lpr7p982l1kyf01ql-pkg-config-wrapper-0.29.2", + "default": true + }, + { + "name": "man", + "path": "/nix/store/10060k24qggqyzlwdsfmni9y32zxcg0j-pkg-config-wrapper-0.29.2-man", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/0y4v51ndpyvkj09hwlfqkz0c3h17zfmc-pkg-config-wrapper-0.29.2-doc" + } + ], + "store_path": "/nix/store/lbiigi8qbp7mzf1lpr7p982l1kyf01ql-pkg-config-wrapper-0.29.2" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/vknadizq0q5kffvx6y4379p9gdry9zq3-pkg-config-wrapper-0.29.2", + "default": true + }, + { + "name": "man", + "path": "/nix/store/1nyspra675q22gfhf7hn2nmfpi6rgim5-pkg-config-wrapper-0.29.2-man", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/7lq1axxwrafwljs06n88bzyz9w523rkc-pkg-config-wrapper-0.29.2-doc" + } + ], + "store_path": "/nix/store/vknadizq0q5kffvx6y4379p9gdry9zq3-pkg-config-wrapper-0.29.2" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/8vdiwpbh0g4avsd6x5v4s0di32vcl3dp-pkg-config-wrapper-0.29.2", + "default": true + }, + { + "name": "man", + "path": "/nix/store/j9xfpnrygg3v37svc5pfin9q5bm49r94-pkg-config-wrapper-0.29.2-man", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/x3bypxdxaq20kykybhkf21x4jczsiy8y-pkg-config-wrapper-0.29.2-doc" + } + ], + "store_path": "/nix/store/8vdiwpbh0g4avsd6x5v4s0di32vcl3dp-pkg-config-wrapper-0.29.2" + } + } + }, "upx@latest": { "last_modified": "2026-04-23T13:07:47Z", "resolved": "github:NixOS/nixpkgs/01fbdeef22b76df85ea168fbfe1bfd9e63681b30#upx", @@ -524,6 +882,106 @@ "store_path": "/nix/store/5x5y75rc3l43ic0lwal6wzk7wi1ga3m1-zig-0.16.0" } } + }, + "zstd@latest": { + "last_modified": "2026-05-27T10:28:13Z", + "resolved": "github:NixOS/nixpkgs/4100e830e085863741bc69b156ec4ccd53ab5be0#zstd", + "source": "devbox-search", + "version": "1.5.7", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/lj773k1dkd7rrnrf0f05v43kwwbzlv4j-zstd-1.5.7-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/053fzmw9v3cc6j8j32jyp3lk1017mla5-zstd-1.5.7-man", + "default": true + }, + { + "name": "out", + "path": "/nix/store/ym2h5axmyxqkwmrrrz570gmkbmdlwvbv-zstd-1.5.7" + }, + { + "name": "dev", + "path": "/nix/store/jg2ki5fvwby45jdv5qmwmn6808gfvvks-zstd-1.5.7-dev" + } + ], + "store_path": "/nix/store/lj773k1dkd7rrnrf0f05v43kwwbzlv4j-zstd-1.5.7-bin" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/37j8jm7q19xgccgz4lawfg7hr0vf79zl-zstd-1.5.7-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/h47ihn6ksn6378j64ya87sci4lxq66mc-zstd-1.5.7-man", + "default": true + }, + { + "name": "out", + "path": "/nix/store/g3vxv9qmkd89xw1ya9ii9gpps78z4q2m-zstd-1.5.7" + }, + { + "name": "dev", + "path": "/nix/store/55aldi2c0mzgqkya8i9ssn76shz0vqp8-zstd-1.5.7-dev" + } + ], + "store_path": "/nix/store/37j8jm7q19xgccgz4lawfg7hr0vf79zl-zstd-1.5.7-bin" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/fb8skywpvnjdmwz37azp9r4dvwxwvq76-zstd-1.5.7-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/wv4by27faql80s9q8y6xkqcx3ssalvr7-zstd-1.5.7-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/g5r73l3qx4pjz4f3g0bx1nq6cihqa629-zstd-1.5.7-dev" + }, + { + "name": "out", + "path": "/nix/store/9db35k8dl5rxk3kk6kzkqwm5732s6ag6-zstd-1.5.7" + } + ], + "store_path": "/nix/store/fb8skywpvnjdmwz37azp9r4dvwxwvq76-zstd-1.5.7-bin" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/cwj48a5jfy5srxgq45p4dg37zqdlhzba-zstd-1.5.7-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/qb1yjn4gp5g2pqgqy0ywjwv3ms987n5a-zstd-1.5.7-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/cbzpsvdi282yhw702d7s42lirqnr0i0g-zstd-1.5.7-dev" + }, + { + "name": "out", + "path": "/nix/store/gd74vdpqzq0qmmikvmrf3r3kghhhnf50-zstd-1.5.7" + } + ], + "store_path": "/nix/store/cwj48a5jfy5srxgq45p4dg37zqdlhzba-zstd-1.5.7-bin" + } + } } } } diff --git a/dune-project b/dune-project new file mode 100644 index 00000000..b3d83bfa --- /dev/null +++ b/dune-project @@ -0,0 +1,26 @@ +(lang dune 3.22) + +(name zane-compiler) + +(generate_opam_files true) + +(source + (github username/reponame)) + +(authors "Author Name ") + +(maintainers "Maintainer Name ") + +(license LICENSE) + +(documentation https://url/to/documentation) + +(package + (name zane-compiler) + (synopsis "A short synopsis") + (description "A longer description") + (depends ocaml) + (tags + ("add topics" "to describe" your project))) + +; See the complete stanza docs at https://dune.readthedocs.io/en/stable/reference/dune-project/index.html diff --git a/lib/dune b/lib/dune new file mode 100644 index 00000000..dac18a94 --- /dev/null +++ b/lib/dune @@ -0,0 +1,2 @@ +(library + (name zane_compiler)) diff --git a/test/dune b/test/dune new file mode 100644 index 00000000..53619c46 --- /dev/null +++ b/test/dune @@ -0,0 +1,3 @@ +(test + (name test_zane_compiler) + (libraries zane_compiler)) diff --git a/test/test_zane_compiler.ml b/test/test_zane_compiler.ml new file mode 100644 index 00000000..e69de29b diff --git a/zane-compiler.opam b/zane-compiler.opam new file mode 100644 index 00000000..e69de29b From 104468b9d0e77ed66543f0ad63e8b6a3e13553f9 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 2 Jun 2026 18:43:32 +0200 Subject: [PATCH 071/154] update --- .gitignore | 1 + devbox.json | 4 +--- justfile | 8 ++++++++ lib/dune | 2 -- {bin => src}/dune | 2 +- {bin => src}/main.ml | 0 test/dune | 3 --- test/test_zane_compiler.ml | 0 zane-compiler.opam | 32 ++++++++++++++++++++++++++++++++ 9 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 justfile delete mode 100644 lib/dune rename {bin => src}/dune (63%) rename {bin => src}/main.ml (100%) delete mode 100644 test/dune delete mode 100644 test/test_zane_compiler.ml diff --git a/.gitignore b/.gitignore index f8abb004..49d8e3ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/ +_build/ parser/ .cache/ vcpkg_installed/ diff --git a/devbox.json b/devbox.json index ee5e554e..23b74a4c 100644 --- a/devbox.json +++ b/devbox.json @@ -22,9 +22,7 @@ "init_hook": [ "echo 'Welcome to devbox!'", "export PATH=$(realpath $DEVBOX_PROJECT_ROOT/bin):$PATH", - "export LLVM_CONFIG=$(realpath $DEVBOX_PROJECT_ROOT/.devbox/nix/profile/default/bin/llvm-config)", - "export LD_LIBRARY_PATH=$(dirname $(find /nix/store -name 'libzstd.so.1' | head -n 1)):$LD_LIBRARY_PATH", - "eval $(opam env)" + "export LLVM_CONFIG=$(realpath $DEVBOX_PROJECT_ROOT/.devbox/nix/profile/default/bin/llvm-config)" ], "scripts": { "test": [ diff --git a/justfile b/justfile new file mode 100644 index 00000000..aeb4b933 --- /dev/null +++ b/justfile @@ -0,0 +1,8 @@ +default: + just -l + +projectName := "zane-compiler" + +run: + dune build + dune exec {{projectName}} diff --git a/lib/dune b/lib/dune deleted file mode 100644 index dac18a94..00000000 --- a/lib/dune +++ /dev/null @@ -1,2 +0,0 @@ -(library - (name zane_compiler)) diff --git a/bin/dune b/src/dune similarity index 63% rename from bin/dune rename to src/dune index 27437529..44c12dc5 100644 --- a/bin/dune +++ b/src/dune @@ -1,4 +1,4 @@ (executable (public_name zane-compiler) (name main) - (libraries zane_compiler)) + (libraries menhirLib sedlex)) diff --git a/bin/main.ml b/src/main.ml similarity index 100% rename from bin/main.ml rename to src/main.ml diff --git a/test/dune b/test/dune deleted file mode 100644 index 53619c46..00000000 --- a/test/dune +++ /dev/null @@ -1,3 +0,0 @@ -(test - (name test_zane_compiler) - (libraries zane_compiler)) diff --git a/test/test_zane_compiler.ml b/test/test_zane_compiler.ml deleted file mode 100644 index e69de29b..00000000 diff --git a/zane-compiler.opam b/zane-compiler.opam index e69de29b..fcacbb10 100644 --- a/zane-compiler.opam +++ b/zane-compiler.opam @@ -0,0 +1,32 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "A short synopsis" +description: "A longer description" +maintainer: ["Maintainer Name "] +authors: ["Author Name "] +license: "LICENSE" +tags: ["add topics" "to describe" "your" "project"] +homepage: "https://github.com/username/reponame" +doc: "https://url/to/documentation" +bug-reports: "https://github.com/username/reponame/issues" +depends: [ + "dune" {>= "3.22"} + "ocaml" + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/username/reponame.git" +x-maintenance-intent: ["(latest)"] From 28ea0e309c0c2136891417565d58e556735a736c Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 2 Jun 2026 20:33:50 +0200 Subject: [PATCH 072/154] first success --- devbox.json | 5 +++-- devbox.lock | 48 ---------------------------------------------- dune-project | 14 +++----------- src/ast.ml | 6 ++++++ src/dune | 7 ++++++- src/lexer.ml | 15 +++++++++++++++ src/main.ml | 20 ++++++++++++++++++- src/parser.mly | 18 +++++++++++++++++ zane-compiler.opam | 12 ++++-------- 9 files changed, 74 insertions(+), 71 deletions(-) create mode 100644 src/ast.ml create mode 100644 src/lexer.ml create mode 100644 src/parser.mly diff --git a/devbox.json b/devbox.json index 23b74a4c..62e57162 100644 --- a/devbox.json +++ b/devbox.json @@ -10,7 +10,6 @@ "ninja@latest", "zig@latest", "clang-tools@latest", - "dune@latest", "opam@latest", "ocaml@latest", "gnumake@latest", @@ -21,8 +20,10 @@ "shell": { "init_hook": [ "echo 'Welcome to devbox!'", + "eval $(opam env)", "export PATH=$(realpath $DEVBOX_PROJECT_ROOT/bin):$PATH", - "export LLVM_CONFIG=$(realpath $DEVBOX_PROJECT_ROOT/.devbox/nix/profile/default/bin/llvm-config)" + "export LLVM_CONFIG=$(realpath $DEVBOX_PROJECT_ROOT/.devbox/nix/profile/default/bin/llvm-config)", + "export LD_LIBRARY_PATH=/nix/store/s7vmxmhkq439cjb7ag9w198p6dk7kl0w-zstd-1.5.7/lib:$LD_LIBRARY_PATH" ], "scripts": { "test": [ diff --git a/devbox.lock b/devbox.lock index ca87f49a..1d603860 100644 --- a/devbox.lock +++ b/devbox.lock @@ -153,54 +153,6 @@ } } }, - "dune@latest": { - "last_modified": "2026-05-21T08:15:18Z", - "resolved": "github:NixOS/nixpkgs/4a29d733e8a7d5b824c3d8c958a946a9867b3eb2#dune", - "source": "devbox-search", - "version": "3.21.1", - "systems": { - "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/i62ga7dgh2zx0wkwq5bhp7r0aq5l1qic-dune-3.21.1", - "default": true - } - ], - "store_path": "/nix/store/i62ga7dgh2zx0wkwq5bhp7r0aq5l1qic-dune-3.21.1" - }, - "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/x7srvl1r3fxqlwrgic8xci2xw4vs4fpd-dune-3.21.1", - "default": true - } - ], - "store_path": "/nix/store/x7srvl1r3fxqlwrgic8xci2xw4vs4fpd-dune-3.21.1" - }, - "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/cwcy3w2hlik0xa6qirq7v7p3qpngqvcr-dune-3.21.1", - "default": true - } - ], - "store_path": "/nix/store/cwcy3w2hlik0xa6qirq7v7p3qpngqvcr-dune-3.21.1" - }, - "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/3g9c7bq560gc93cjya06cgx3df0sl5yw-dune-3.21.1", - "default": true - } - ], - "store_path": "/nix/store/3g9c7bq560gc93cjya06cgx3df0sl5yw-dune-3.21.1" - } - } - }, "github:NixOS/nixpkgs/nixpkgs-unstable": { "last_modified": "2026-05-27T10:28:13Z", "resolved": "github:NixOS/nixpkgs/4100e830e085863741bc69b156ec4ccd53ab5be0?lastModified=1779877693&narHash=sha256-NOF9NAREhxr50bbBfVcVOq%2BArCMSoe8dP79Pk2uyARk%3D" diff --git a/dune-project b/dune-project index b3d83bfa..44ca369b 100644 --- a/dune-project +++ b/dune-project @@ -1,19 +1,11 @@ -(lang dune 3.22) - +(lang dune 3.21) (name zane-compiler) - (generate_opam_files true) (source - (github username/reponame)) - -(authors "Author Name ") - -(maintainers "Maintainer Name ") - -(license LICENSE) + (github zane-lang/compiler)) -(documentation https://url/to/documentation) +(using menhir 3.0) (package (name zane-compiler) diff --git a/src/ast.ml b/src/ast.ml new file mode 100644 index 00000000..c1787669 --- /dev/null +++ b/src/ast.ml @@ -0,0 +1,6 @@ +type expr = + | Int of int + | Add of expr * expr + | Sub of expr * expr + | Mul of expr * expr + | Div of expr * expr diff --git a/src/dune b/src/dune index 44c12dc5..a2e47cbd 100644 --- a/src/dune +++ b/src/dune @@ -1,4 +1,9 @@ (executable (public_name zane-compiler) (name main) - (libraries menhirLib sedlex)) + (modules main ast lexer parser) + (libraries menhirLib sedlex) + (preprocess (pps sedlex.ppx))) + +(menhir + (modules parser)) diff --git a/src/lexer.ml b/src/lexer.ml new file mode 100644 index 00000000..6feb9380 --- /dev/null +++ b/src/lexer.ml @@ -0,0 +1,15 @@ +open Sedlexing +open Parser (* use Parser.token instead of defining our own *) + +let rec token buf = + match%sedlex buf with + | '+' -> PLUS + | '-' -> MINUS + | '*' -> MUL + | '/' -> DIV + | '(' -> LPAREN + | ')' -> RPAREN + | Plus ('0'..'9') -> INT (int_of_string (Utf8.lexeme buf)) + | Plus (' ' | '\t' | '\n' | '\r') -> token buf + | eof -> EOF + | _ -> failwith ("Unexpected character: " ^ Utf8.lexeme buf) diff --git a/src/main.ml b/src/main.ml index 7bf6048f..e482064c 100644 --- a/src/main.ml +++ b/src/main.ml @@ -1 +1,19 @@ -let () = print_endline "Hello, World!" +let rec string_of_expr = function + | Ast.Int n -> string_of_int n + | Ast.Add (e1, e2) -> "(" ^ string_of_expr e1 ^ " + " ^ string_of_expr e2 ^ ")" + | Ast.Sub (e1, e2) -> "(" ^ string_of_expr e1 ^ " - " ^ string_of_expr e2 ^ ")" + | Ast.Mul (e1, e2) -> "(" ^ string_of_expr e1 ^ " * " ^ string_of_expr e2 ^ ")" + | Ast.Div (e1, e2) -> "(" ^ string_of_expr e1 ^ " / " ^ string_of_expr e2 ^ ")" + +let () = + let input = "3 + 4 * (2 - 1)" in + let lexbuf = Sedlexing.Utf8.from_string input in + let tokenizer = Sedlexing.with_tokenizer Lexer.token lexbuf in + try + let result = MenhirLib.Convert.Simplified.traditional2revised Parser.prog tokenizer in + print_endline ("Parsed: " ^ string_of_expr result) + with + | Sedlexing.MalFormed | Sedlexing.InvalidCodepoint _ -> + print_endline "Lexing error: Invalid character" + | Parser.Error -> + print_endline "Parsing error: Invalid syntax" diff --git a/src/parser.mly b/src/parser.mly new file mode 100644 index 00000000..d46a132a --- /dev/null +++ b/src/parser.mly @@ -0,0 +1,18 @@ +%token INT +%token PLUS MINUS MUL DIV LPAREN RPAREN EOF + +%left PLUS MINUS +%left MUL DIV + +%start prog +%% +prog: + | e = expr EOF { e } + +expr: + | i = INT { Ast.Int i } + | LPAREN e = expr RPAREN { e } + | e1 = expr PLUS e2 = expr { Ast.Add (e1, e2) } + | e1 = expr MINUS e2 = expr { Ast.Sub (e1, e2) } + | e1 = expr MUL e2 = expr { Ast.Mul (e1, e2) } + | e1 = expr DIV e2 = expr { Ast.Div (e1, e2) } diff --git a/zane-compiler.opam b/zane-compiler.opam index fcacbb10..1731773f 100644 --- a/zane-compiler.opam +++ b/zane-compiler.opam @@ -2,15 +2,11 @@ opam-version: "2.0" synopsis: "A short synopsis" description: "A longer description" -maintainer: ["Maintainer Name "] -authors: ["Author Name "] -license: "LICENSE" tags: ["add topics" "to describe" "your" "project"] -homepage: "https://github.com/username/reponame" -doc: "https://url/to/documentation" -bug-reports: "https://github.com/username/reponame/issues" +homepage: "https://github.com/zane-lang/compiler" +bug-reports: "https://github.com/zane-lang/compiler/issues" depends: [ - "dune" {>= "3.22"} + "dune" {>= "3.21"} "ocaml" "odoc" {with-doc} ] @@ -28,5 +24,5 @@ build: [ "@doc" {with-doc} ] ] -dev-repo: "git+https://github.com/username/reponame.git" +dev-repo: "git+https://github.com/zane-lang/compiler.git" x-maintenance-intent: ["(latest)"] From 04c68c9b1b24c17709881d6f581ecbc8b77b0f24 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 2 Jun 2026 20:53:15 +0200 Subject: [PATCH 073/154] improve structure --- src/ast/dune | 3 +++ src/{ast.ml => ast/nodes.ml} | 0 src/dune | 8 ++------ src/grammar/dune | 8 ++++++++ src/{ => grammar}/lexer.ml | 0 src/grammar/parser.mly | 18 ++++++++++++++++++ src/main.ml | 16 ++++++++-------- src/parser.mly | 18 ------------------ 8 files changed, 39 insertions(+), 32 deletions(-) create mode 100644 src/ast/dune rename src/{ast.ml => ast/nodes.ml} (100%) create mode 100644 src/grammar/dune rename src/{ => grammar}/lexer.ml (100%) create mode 100644 src/grammar/parser.mly delete mode 100644 src/parser.mly diff --git a/src/ast/dune b/src/ast/dune new file mode 100644 index 00000000..4adfd33d --- /dev/null +++ b/src/ast/dune @@ -0,0 +1,3 @@ +(library + (name ast) + (modules nodes)) diff --git a/src/ast.ml b/src/ast/nodes.ml similarity index 100% rename from src/ast.ml rename to src/ast/nodes.ml diff --git a/src/dune b/src/dune index a2e47cbd..d228125f 100644 --- a/src/dune +++ b/src/dune @@ -1,9 +1,5 @@ (executable (public_name zane-compiler) (name main) - (modules main ast lexer parser) - (libraries menhirLib sedlex) - (preprocess (pps sedlex.ppx))) - -(menhir - (modules parser)) + (libraries ast grammar) + (modules main)) diff --git a/src/grammar/dune b/src/grammar/dune new file mode 100644 index 00000000..d485c1e1 --- /dev/null +++ b/src/grammar/dune @@ -0,0 +1,8 @@ +(library + (name grammar) + (modules parser lexer) + (libraries ast menhirLib sedlex) + (preprocess (pps sedlex.ppx))) + +(menhir + (modules parser)) diff --git a/src/lexer.ml b/src/grammar/lexer.ml similarity index 100% rename from src/lexer.ml rename to src/grammar/lexer.ml diff --git a/src/grammar/parser.mly b/src/grammar/parser.mly new file mode 100644 index 00000000..584740d3 --- /dev/null +++ b/src/grammar/parser.mly @@ -0,0 +1,18 @@ +%token INT +%token PLUS MINUS MUL DIV LPAREN RPAREN EOF + +%left PLUS MINUS +%left MUL DIV + +%start prog +%% +prog: + | e = expr EOF { e } + +expr: + | i = INT { Ast.Nodes.Int i } + | LPAREN e = expr RPAREN { e } + | e1 = expr PLUS e2 = expr { Ast.Nodes.Add (e1, e2) } + | e1 = expr MINUS e2 = expr { Ast.Nodes.Sub (e1, e2) } + | e1 = expr MUL e2 = expr { Ast.Nodes.Mul (e1, e2) } + | e1 = expr DIV e2 = expr { Ast.Nodes.Div (e1, e2) } diff --git a/src/main.ml b/src/main.ml index e482064c..ca15ea2e 100644 --- a/src/main.ml +++ b/src/main.ml @@ -1,19 +1,19 @@ let rec string_of_expr = function - | Ast.Int n -> string_of_int n - | Ast.Add (e1, e2) -> "(" ^ string_of_expr e1 ^ " + " ^ string_of_expr e2 ^ ")" - | Ast.Sub (e1, e2) -> "(" ^ string_of_expr e1 ^ " - " ^ string_of_expr e2 ^ ")" - | Ast.Mul (e1, e2) -> "(" ^ string_of_expr e1 ^ " * " ^ string_of_expr e2 ^ ")" - | Ast.Div (e1, e2) -> "(" ^ string_of_expr e1 ^ " / " ^ string_of_expr e2 ^ ")" + | Ast.Nodes.Int n -> string_of_int n + | Ast.Nodes.Add (e1, e2) -> "(" ^ string_of_expr e1 ^ " + " ^ string_of_expr e2 ^ ")" + | Ast.Nodes.Sub (e1, e2) -> "(" ^ string_of_expr e1 ^ " - " ^ string_of_expr e2 ^ ")" + | Ast.Nodes.Mul (e1, e2) -> "(" ^ string_of_expr e1 ^ " * " ^ string_of_expr e2 ^ ")" + | Ast.Nodes.Div (e1, e2) -> "(" ^ string_of_expr e1 ^ " / " ^ string_of_expr e2 ^ ")" let () = let input = "3 + 4 * (2 - 1)" in let lexbuf = Sedlexing.Utf8.from_string input in - let tokenizer = Sedlexing.with_tokenizer Lexer.token lexbuf in + let tokenizer = Sedlexing.with_tokenizer Grammar.Lexer.token lexbuf in try - let result = MenhirLib.Convert.Simplified.traditional2revised Parser.prog tokenizer in + let result = MenhirLib.Convert.Simplified.traditional2revised Grammar.Parser.prog tokenizer in print_endline ("Parsed: " ^ string_of_expr result) with | Sedlexing.MalFormed | Sedlexing.InvalidCodepoint _ -> print_endline "Lexing error: Invalid character" - | Parser.Error -> + | Grammar.Parser.Error -> print_endline "Parsing error: Invalid syntax" diff --git a/src/parser.mly b/src/parser.mly deleted file mode 100644 index d46a132a..00000000 --- a/src/parser.mly +++ /dev/null @@ -1,18 +0,0 @@ -%token INT -%token PLUS MINUS MUL DIV LPAREN RPAREN EOF - -%left PLUS MINUS -%left MUL DIV - -%start prog -%% -prog: - | e = expr EOF { e } - -expr: - | i = INT { Ast.Int i } - | LPAREN e = expr RPAREN { e } - | e1 = expr PLUS e2 = expr { Ast.Add (e1, e2) } - | e1 = expr MINUS e2 = expr { Ast.Sub (e1, e2) } - | e1 = expr MUL e2 = expr { Ast.Mul (e1, e2) } - | e1 = expr DIV e2 = expr { Ast.Div (e1, e2) } From b8b93670ff794c14c33bd7dd26a49ec685fa4d42 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 2 Jun 2026 21:08:09 +0200 Subject: [PATCH 074/154] better monorepo structure --- {src => bin/compiler}/dune | 2 +- {src => bin/compiler}/main.ml | 10 +++++----- bin/zane | 1 - devbox.json | 1 - docs/stages.md | 4 ++-- {src/ast => lib/cst}/dune | 2 +- {src/ast => lib/cst}/nodes.ml | 0 {src => lib}/grammar/dune | 2 +- {src => lib}/grammar/lexer.ml | 0 lib/grammar/parser.mly | 18 ++++++++++++++++++ src/grammar/parser.mly | 18 ------------------ 11 files changed, 28 insertions(+), 30 deletions(-) rename {src => bin/compiler}/dune (73%) rename {src => bin/compiler}/main.ml (70%) delete mode 120000 bin/zane rename {src/ast => lib/cst}/dune (69%) rename {src/ast => lib/cst}/nodes.ml (100%) rename {src => lib}/grammar/dune (76%) rename {src => lib}/grammar/lexer.ml (100%) create mode 100644 lib/grammar/parser.mly delete mode 100644 src/grammar/parser.mly diff --git a/src/dune b/bin/compiler/dune similarity index 73% rename from src/dune rename to bin/compiler/dune index d228125f..9db40015 100644 --- a/src/dune +++ b/bin/compiler/dune @@ -1,5 +1,5 @@ (executable (public_name zane-compiler) (name main) - (libraries ast grammar) + (libraries cst grammar) (modules main)) diff --git a/src/main.ml b/bin/compiler/main.ml similarity index 70% rename from src/main.ml rename to bin/compiler/main.ml index ca15ea2e..36fffb12 100644 --- a/src/main.ml +++ b/bin/compiler/main.ml @@ -1,9 +1,9 @@ let rec string_of_expr = function - | Ast.Nodes.Int n -> string_of_int n - | Ast.Nodes.Add (e1, e2) -> "(" ^ string_of_expr e1 ^ " + " ^ string_of_expr e2 ^ ")" - | Ast.Nodes.Sub (e1, e2) -> "(" ^ string_of_expr e1 ^ " - " ^ string_of_expr e2 ^ ")" - | Ast.Nodes.Mul (e1, e2) -> "(" ^ string_of_expr e1 ^ " * " ^ string_of_expr e2 ^ ")" - | Ast.Nodes.Div (e1, e2) -> "(" ^ string_of_expr e1 ^ " / " ^ string_of_expr e2 ^ ")" + | Cst.Nodes.Int n -> string_of_int n + | Cst.Nodes.Add (e1, e2) -> "(" ^ string_of_expr e1 ^ " + " ^ string_of_expr e2 ^ ")" + | Cst.Nodes.Sub (e1, e2) -> "(" ^ string_of_expr e1 ^ " - " ^ string_of_expr e2 ^ ")" + | Cst.Nodes.Mul (e1, e2) -> "(" ^ string_of_expr e1 ^ " * " ^ string_of_expr e2 ^ ")" + | Cst.Nodes.Div (e1, e2) -> "(" ^ string_of_expr e1 ^ " / " ^ string_of_expr e2 ^ ")" let () = let input = "3 + 4 * (2 - 1)" in diff --git a/bin/zane b/bin/zane deleted file mode 120000 index 7eb2d9e8..00000000 --- a/bin/zane +++ /dev/null @@ -1 +0,0 @@ -../build/zane \ No newline at end of file diff --git a/devbox.json b/devbox.json index 62e57162..e10e822c 100644 --- a/devbox.json +++ b/devbox.json @@ -21,7 +21,6 @@ "init_hook": [ "echo 'Welcome to devbox!'", "eval $(opam env)", - "export PATH=$(realpath $DEVBOX_PROJECT_ROOT/bin):$PATH", "export LLVM_CONFIG=$(realpath $DEVBOX_PROJECT_ROOT/.devbox/nix/profile/default/bin/llvm-config)", "export LD_LIBRARY_PATH=/nix/store/s7vmxmhkq439cjb7ag9w198p6dk7kl0w-zstd-1.5.7/lib:$LD_LIBRARY_PATH" ], diff --git a/docs/stages.md b/docs/stages.md index a4635b7a..0da2378e 100644 --- a/docs/stages.md +++ b/docs/stages.md @@ -1,6 +1,6 @@ We use 4 stages: -1. parsing: astA -2. semantics: astB +1. parsing: astA (correct terminology: cst, concrete syntax tree) +2. semantics: astB (correct terminology: ast) 3. optimizations: mutate astB 4. codegen: binary diff --git a/src/ast/dune b/lib/cst/dune similarity index 69% rename from src/ast/dune rename to lib/cst/dune index 4adfd33d..124a5576 100644 --- a/src/ast/dune +++ b/lib/cst/dune @@ -1,3 +1,3 @@ (library - (name ast) + (name cst) (modules nodes)) diff --git a/src/ast/nodes.ml b/lib/cst/nodes.ml similarity index 100% rename from src/ast/nodes.ml rename to lib/cst/nodes.ml diff --git a/src/grammar/dune b/lib/grammar/dune similarity index 76% rename from src/grammar/dune rename to lib/grammar/dune index d485c1e1..59dfa9f1 100644 --- a/src/grammar/dune +++ b/lib/grammar/dune @@ -1,7 +1,7 @@ (library (name grammar) (modules parser lexer) - (libraries ast menhirLib sedlex) + (libraries cst menhirLib sedlex) (preprocess (pps sedlex.ppx))) (menhir diff --git a/src/grammar/lexer.ml b/lib/grammar/lexer.ml similarity index 100% rename from src/grammar/lexer.ml rename to lib/grammar/lexer.ml diff --git a/lib/grammar/parser.mly b/lib/grammar/parser.mly new file mode 100644 index 00000000..8f0db5c2 --- /dev/null +++ b/lib/grammar/parser.mly @@ -0,0 +1,18 @@ +%token INT +%token PLUS MINUS MUL DIV LPAREN RPAREN EOF + +%left PLUS MINUS +%left MUL DIV + +%start prog +%% +prog: + | e = expr EOF { e } + +expr: + | i = INT { Cst.Nodes.Int i } + | LPAREN e = expr RPAREN { e } + | e1 = expr PLUS e2 = expr { Cst.Nodes.Add (e1, e2) } + | e1 = expr MINUS e2 = expr { Cst.Nodes.Sub (e1, e2) } + | e1 = expr MUL e2 = expr { Cst.Nodes.Mul (e1, e2) } + | e1 = expr DIV e2 = expr { Cst.Nodes.Div (e1, e2) } diff --git a/src/grammar/parser.mly b/src/grammar/parser.mly deleted file mode 100644 index 584740d3..00000000 --- a/src/grammar/parser.mly +++ /dev/null @@ -1,18 +0,0 @@ -%token INT -%token PLUS MINUS MUL DIV LPAREN RPAREN EOF - -%left PLUS MINUS -%left MUL DIV - -%start prog -%% -prog: - | e = expr EOF { e } - -expr: - | i = INT { Ast.Nodes.Int i } - | LPAREN e = expr RPAREN { e } - | e1 = expr PLUS e2 = expr { Ast.Nodes.Add (e1, e2) } - | e1 = expr MINUS e2 = expr { Ast.Nodes.Sub (e1, e2) } - | e1 = expr MUL e2 = expr { Ast.Nodes.Mul (e1, e2) } - | e1 = expr DIV e2 = expr { Ast.Nodes.Div (e1, e2) } From e84cd81655123d9e7beec7cb73f8d32f091eb9a1 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 2 Jun 2026 21:09:09 +0200 Subject: [PATCH 075/154] update --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 49d8e3ac..bf49ceef 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ parser/ .cache/ vcpkg_installed/ __pycache__/ -test/.dev/ +.devbox/ From f67fd14038a87ee01e99cd07195ededffde1ae8c Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 2 Jun 2026 22:09:27 +0200 Subject: [PATCH 076/154] clean --- bin/compiler/dune | 3 +-- bin/compiler/main.ml | 22 ++++------------------ justfile | 8 ++++---- lib/cst/cst.ml | 9 +++++++++ lib/cst/dune | 6 +++++- lib/{grammar => cst}/lexer.ml | 0 lib/cst/parser.mly | 18 ++++++++++++++++++ lib/cst/to_string.ml | 6 ++++++ lib/grammar/dune | 8 -------- lib/grammar/parser.mly | 18 ------------------ 10 files changed, 47 insertions(+), 51 deletions(-) create mode 100644 lib/cst/cst.ml rename lib/{grammar => cst}/lexer.ml (100%) create mode 100644 lib/cst/parser.mly create mode 100644 lib/cst/to_string.ml delete mode 100644 lib/grammar/dune delete mode 100644 lib/grammar/parser.mly diff --git a/bin/compiler/dune b/bin/compiler/dune index 9db40015..1e63b49e 100644 --- a/bin/compiler/dune +++ b/bin/compiler/dune @@ -1,5 +1,4 @@ (executable - (public_name zane-compiler) (name main) - (libraries cst grammar) + (libraries cst) (modules main)) diff --git a/bin/compiler/main.ml b/bin/compiler/main.ml index 36fffb12..063703ee 100644 --- a/bin/compiler/main.ml +++ b/bin/compiler/main.ml @@ -1,19 +1,5 @@ -let rec string_of_expr = function - | Cst.Nodes.Int n -> string_of_int n - | Cst.Nodes.Add (e1, e2) -> "(" ^ string_of_expr e1 ^ " + " ^ string_of_expr e2 ^ ")" - | Cst.Nodes.Sub (e1, e2) -> "(" ^ string_of_expr e1 ^ " - " ^ string_of_expr e2 ^ ")" - | Cst.Nodes.Mul (e1, e2) -> "(" ^ string_of_expr e1 ^ " * " ^ string_of_expr e2 ^ ")" - | Cst.Nodes.Div (e1, e2) -> "(" ^ string_of_expr e1 ^ " / " ^ string_of_expr e2 ^ ")" - let () = - let input = "3 + 4 * (2 - 1)" in - let lexbuf = Sedlexing.Utf8.from_string input in - let tokenizer = Sedlexing.with_tokenizer Grammar.Lexer.token lexbuf in - try - let result = MenhirLib.Convert.Simplified.traditional2revised Grammar.Parser.prog tokenizer in - print_endline ("Parsed: " ^ string_of_expr result) - with - | Sedlexing.MalFormed | Sedlexing.InvalidCodepoint _ -> - print_endline "Lexing error: Invalid character" - | Grammar.Parser.Error -> - print_endline "Parsing error: Invalid syntax" + let input = "3 + 4 * 2 - 1" in + let cst = Cst.parse input in + let output = Cst.string_of_expr(cst) in + print_endline output diff --git a/justfile b/justfile index aeb4b933..2f523465 100644 --- a/justfile +++ b/justfile @@ -1,8 +1,8 @@ default: just -l -projectName := "zane-compiler" - run: - dune build - dune exec {{projectName}} + dune exec bin/compiler/main.exe + +watch: + dune build --watch diff --git a/lib/cst/cst.ml b/lib/cst/cst.ml new file mode 100644 index 00000000..488cebaa --- /dev/null +++ b/lib/cst/cst.ml @@ -0,0 +1,9 @@ +module Nodes = Nodes +module Parser = Parser +module Lexer = Lexer +include To_string + +let parse input = + let lexbuf = Sedlexing.Utf8.from_string input in + let tokenizer = Sedlexing.with_tokenizer Lexer.token lexbuf in + MenhirLib.Convert.Simplified.traditional2revised Parser.prog tokenizer diff --git a/lib/cst/dune b/lib/cst/dune index 124a5576..9281c372 100644 --- a/lib/cst/dune +++ b/lib/cst/dune @@ -1,3 +1,7 @@ (library (name cst) - (modules nodes)) + (libraries menhirLib sedlex) + (preprocess (pps sedlex.ppx))) + +(menhir + (modules parser)) diff --git a/lib/grammar/lexer.ml b/lib/cst/lexer.ml similarity index 100% rename from lib/grammar/lexer.ml rename to lib/cst/lexer.ml diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly new file mode 100644 index 00000000..0665a0c2 --- /dev/null +++ b/lib/cst/parser.mly @@ -0,0 +1,18 @@ +%token INT +%token PLUS MINUS MUL DIV LPAREN RPAREN EOF + +%left PLUS MINUS +%left MUL DIV + +%start prog +%% +prog: + | e = expr EOF { e } + +expr: + | i = INT { Nodes.Int i } + | LPAREN e = expr RPAREN { e } + | e1 = expr PLUS e2 = expr { Nodes.Add (e1, e2) } + | e1 = expr MINUS e2 = expr { Nodes.Sub (e1, e2) } + | e1 = expr MUL e2 = expr { Nodes.Mul (e1, e2) } + | e1 = expr DIV e2 = expr { Nodes.Div (e1, e2) } diff --git a/lib/cst/to_string.ml b/lib/cst/to_string.ml new file mode 100644 index 00000000..d6738718 --- /dev/null +++ b/lib/cst/to_string.ml @@ -0,0 +1,6 @@ +let rec string_of_expr = function + | Nodes.Int n -> string_of_int n + | Nodes.Add (e1, e2) -> "(" ^ string_of_expr e1 ^ " + " ^ string_of_expr e2 ^ ")" + | Nodes.Sub (e1, e2) -> "(" ^ string_of_expr e1 ^ " - " ^ string_of_expr e2 ^ ")" + | Nodes.Mul (e1, e2) -> "(" ^ string_of_expr e1 ^ " * " ^ string_of_expr e2 ^ ")" + | Nodes.Div (e1, e2) -> "(" ^ string_of_expr e1 ^ " / " ^ string_of_expr e2 ^ ")" diff --git a/lib/grammar/dune b/lib/grammar/dune deleted file mode 100644 index 59dfa9f1..00000000 --- a/lib/grammar/dune +++ /dev/null @@ -1,8 +0,0 @@ -(library - (name grammar) - (modules parser lexer) - (libraries cst menhirLib sedlex) - (preprocess (pps sedlex.ppx))) - -(menhir - (modules parser)) diff --git a/lib/grammar/parser.mly b/lib/grammar/parser.mly deleted file mode 100644 index 8f0db5c2..00000000 --- a/lib/grammar/parser.mly +++ /dev/null @@ -1,18 +0,0 @@ -%token INT -%token PLUS MINUS MUL DIV LPAREN RPAREN EOF - -%left PLUS MINUS -%left MUL DIV - -%start prog -%% -prog: - | e = expr EOF { e } - -expr: - | i = INT { Cst.Nodes.Int i } - | LPAREN e = expr RPAREN { e } - | e1 = expr PLUS e2 = expr { Cst.Nodes.Add (e1, e2) } - | e1 = expr MINUS e2 = expr { Cst.Nodes.Sub (e1, e2) } - | e1 = expr MUL e2 = expr { Cst.Nodes.Mul (e1, e2) } - | e1 = expr DIV e2 = expr { Cst.Nodes.Div (e1, e2) } From dbe2c38c0cffe5702e8ca442e636c44036bdf714 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 2 Jun 2026 22:33:20 +0200 Subject: [PATCH 077/154] update --- bin/compiler/main.ml | 7 +++++-- lib/cst/nodes.ml | 9 +++++++++ lib/cst/to_string.ml | 10 +++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/bin/compiler/main.ml b/bin/compiler/main.ml index 063703ee..f84404a3 100644 --- a/bin/compiler/main.ml +++ b/bin/compiler/main.ml @@ -1,5 +1,8 @@ +let read_file path = + In_channel.with_open_text path In_channel.input_all + let () = - let input = "3 + 4 * 2 - 1" in + let input = read_file "test-parser/main.zn" in let cst = Cst.parse input in - let output = Cst.string_of_expr(cst) in + let output = Cst.to_string cst in print_endline output diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index c1787669..2aa08d50 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -1,3 +1,12 @@ +type type_expr = + | Simple of string + | Generic of { name: string; args: string list } + | Function of { params: type_expr list; ret_type: type_expr } + | Method of { params: type_expr list; ret_type: type_expr; is_mut: bool } + +type decl = + | Function of { name: string; params: type_expr list; ret: type_expr } + type expr = | Int of int | Add of expr * expr diff --git a/lib/cst/to_string.ml b/lib/cst/to_string.ml index d6738718..b28549b2 100644 --- a/lib/cst/to_string.ml +++ b/lib/cst/to_string.ml @@ -1,6 +1,6 @@ -let rec string_of_expr = function +let rec to_string = function | Nodes.Int n -> string_of_int n - | Nodes.Add (e1, e2) -> "(" ^ string_of_expr e1 ^ " + " ^ string_of_expr e2 ^ ")" - | Nodes.Sub (e1, e2) -> "(" ^ string_of_expr e1 ^ " - " ^ string_of_expr e2 ^ ")" - | Nodes.Mul (e1, e2) -> "(" ^ string_of_expr e1 ^ " * " ^ string_of_expr e2 ^ ")" - | Nodes.Div (e1, e2) -> "(" ^ string_of_expr e1 ^ " / " ^ string_of_expr e2 ^ ")" + | Nodes.Add (e1, e2) -> "(" ^ to_string e1 ^ " + " ^ to_string e2 ^ ")" + | Nodes.Sub (e1, e2) -> "(" ^ to_string e1 ^ " - " ^ to_string e2 ^ ")" + | Nodes.Mul (e1, e2) -> "(" ^ to_string e1 ^ " * " ^ to_string e2 ^ ")" + | Nodes.Div (e1, e2) -> "(" ^ to_string e1 ^ " / " ^ to_string e2 ^ ")" From 3b985c4afe31694eab2a18c27771a2f93c04853a Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 3 Jun 2026 10:10:54 +0200 Subject: [PATCH 078/154] update --- lib/cst/nodes.ml | 1 + lib/cst/parser.mly | 2 +- lib/cst/to_string.ml | 9 +++++---- test-parser/main.zn | 12 +----------- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 2aa08d50..4b974f9f 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -13,3 +13,4 @@ type expr = | Sub of expr * expr | Mul of expr * expr | Div of expr * expr + | Parenthized of expr diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 0665a0c2..93a16a93 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -11,7 +11,7 @@ prog: expr: | i = INT { Nodes.Int i } - | LPAREN e = expr RPAREN { e } + | LPAREN e = expr RPAREN { Nodes.Parenthized e } | e1 = expr PLUS e2 = expr { Nodes.Add (e1, e2) } | e1 = expr MINUS e2 = expr { Nodes.Sub (e1, e2) } | e1 = expr MUL e2 = expr { Nodes.Mul (e1, e2) } diff --git a/lib/cst/to_string.ml b/lib/cst/to_string.ml index b28549b2..3d26a8b5 100644 --- a/lib/cst/to_string.ml +++ b/lib/cst/to_string.ml @@ -1,6 +1,7 @@ let rec to_string = function | Nodes.Int n -> string_of_int n - | Nodes.Add (e1, e2) -> "(" ^ to_string e1 ^ " + " ^ to_string e2 ^ ")" - | Nodes.Sub (e1, e2) -> "(" ^ to_string e1 ^ " - " ^ to_string e2 ^ ")" - | Nodes.Mul (e1, e2) -> "(" ^ to_string e1 ^ " * " ^ to_string e2 ^ ")" - | Nodes.Div (e1, e2) -> "(" ^ to_string e1 ^ " / " ^ to_string e2 ^ ")" + | Nodes.Add (e1, e2) -> to_string e1 ^ " + " ^ to_string e2 + | Nodes.Sub (e1, e2) -> to_string e1 ^ " - " ^ to_string e2 + | Nodes.Mul (e1, e2) -> to_string e1 ^ " * " ^ to_string e2 + | Nodes.Div (e1, e2) -> to_string e1 ^ " / " ^ to_string e2 + | Nodes.Parenthized e -> "(" ^ to_string e ^ ")" diff --git a/test-parser/main.zn b/test-parser/main.zn index 42b4197b..82eef531 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,11 +1 @@ -main (this Int, a Bool)! Void { - print(2, 2) - Std$print(1 + 1 + 3 + 4) - @Intrinsics$print("hello") - test Int = 3 - func (this Int) -> Void = 3.0 -} - -getNum () Void { - print() -} +(1 + 1) *(3 + 3) / 3 From c2843bc1484d2a893a02ba6b062cec990b07b73c Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 3 Jun 2026 15:14:16 +0200 Subject: [PATCH 079/154] update --- bin/compiler/main.ml | 10 ++++----- functionSyntax.txt | 3 +++ lib/cst/cst.ml | 13 +++++++++--- lib/cst/lexer.ml | 49 ++++++++++++++++++++++++++++++++++---------- lib/cst/nodes.ml | 30 ++++++++++++++++++--------- lib/cst/parser.mly | 39 +++++++++++++++++++++++------------ lib/cst/to_string.ml | 36 +++++++++++++++++++++++++------- test-parser/main.zn | 2 +- 8 files changed, 132 insertions(+), 50 deletions(-) create mode 100644 functionSyntax.txt diff --git a/bin/compiler/main.ml b/bin/compiler/main.ml index f84404a3..ae33bb4e 100644 --- a/bin/compiler/main.ml +++ b/bin/compiler/main.ml @@ -1,8 +1,8 @@ let read_file path = - In_channel.with_open_text path In_channel.input_all + In_channel.with_open_text path In_channel.input_all let () = - let input = read_file "test-parser/main.zn" in - let cst = Cst.parse input in - let output = Cst.to_string cst in - print_endline output + let input = read_file "test-parser/main.zn" in + let cst = Cst.parse input in + let output = Cst.to_string cst in + print_endline output diff --git a/functionSyntax.txt b/functionSyntax.txt new file mode 100644 index 00000000..d5bc8603 --- /dev/null +++ b/functionSyntax.txt @@ -0,0 +1,3 @@ +main (this Int, a Bool)! Void { + print(2, 2) +} diff --git a/lib/cst/cst.ml b/lib/cst/cst.ml index 488cebaa..97fb2b4c 100644 --- a/lib/cst/cst.ml +++ b/lib/cst/cst.ml @@ -4,6 +4,13 @@ module Lexer = Lexer include To_string let parse input = - let lexbuf = Sedlexing.Utf8.from_string input in - let tokenizer = Sedlexing.with_tokenizer Lexer.token lexbuf in - MenhirLib.Convert.Simplified.traditional2revised Parser.prog tokenizer + let lexbuf = Sedlexing.Utf8.from_string input in + let tokenizer = Sedlexing.with_tokenizer Lexer.token lexbuf in + try + MenhirLib.Convert.Simplified.traditional2revised Parser.package tokenizer + with Parser.Error -> + let (pos, _) = Sedlexing.lexing_positions lexbuf in + Printf.printf "Parse error at line %d, column %d\n" + pos.Lexing.pos_lnum + (pos.Lexing.pos_cnum - pos.Lexing.pos_bol); + raise Parser.Error diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index 6feb9380..eadd72cf 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -1,15 +1,42 @@ open Sedlexing -open Parser (* use Parser.token instead of defining our own *) +open Parser + +let digit = [%sedlex.regexp? '0'..'9'] +let digits = [%sedlex.regexp? Plus digit] +let int_lit = [%sedlex.regexp? digits, Star ('\'', digits)] +let float_lit = [%sedlex.regexp? int_lit, '.', digits] +let nonascii = [%sedlex.regexp? 192 .. 214 | 216 .. 246 | 248 .. 255] +let ident_char = [%sedlex.regexp? 'a'..'z' | 'A'..'Z' | '_' | nonascii] +let str_char = [%sedlex.regexp? Compl ('"' | '\\') | '\\', any] + +let strip_sep s = String.concat "" (String.split_on_char '\'' s) let rec token buf = match%sedlex buf with - | '+' -> PLUS - | '-' -> MINUS - | '*' -> MUL - | '/' -> DIV - | '(' -> LPAREN - | ')' -> RPAREN - | Plus ('0'..'9') -> INT (int_of_string (Utf8.lexeme buf)) - | Plus (' ' | '\t' | '\n' | '\r') -> token buf - | eof -> EOF - | _ -> failwith ("Unexpected character: " ^ Utf8.lexeme buf) + | Plus (' ' | '\t' | '\r' | '\n') -> token buf + | "->" -> THIN_ARROW + | "=>" -> THICK_ARROW + | '=' -> EQUAL + | '(' -> LPAREN + | ')' -> RPAREN + | '{' -> LCURLY + | '}' -> RCURLY + | ',' -> COMMA + | ':' -> COLON + | '!' -> EXCL + | '~' -> TILDE + | '+' -> PLUS + | '-' -> MINUS + | '*' -> STAR + | '/' -> SLASH + | '$' -> DOLLAR + | '@' -> AT + | float_lit -> FLOAT (Utf8.lexeme buf) + | int_lit -> INT (Utf8.lexeme buf) + | '"', Star str_char, '"' -> + let s = Utf8.lexeme buf in + STRING (String.sub s 1 (String.length s - 2)) + | "this" -> THIS + | Plus ident_char -> IDENT (Utf8.lexeme buf) + | eof -> EOF + | _ -> ERROR diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 4b974f9f..0a81a94b 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -1,16 +1,26 @@ -type type_expr = - | Simple of string - | Generic of { name: string; args: string list } - | Function of { params: type_expr list; ret_type: type_expr } - | Method of { params: type_expr list; ret_type: type_expr; is_mut: bool } - -type decl = - | Function of { name: string; params: type_expr list; ret: type_expr } - type expr = - | Int of int + | IntLiteral of string + | FloatLiteral of string + | StringLiteral of string | Add of expr * expr | Sub of expr * expr | Mul of expr * expr | Div of expr * expr | Parenthized of expr + +type type_expr = + | Simple of string + | FunctionType of { params: type_expr list; ret_type: type_expr } + | MethodType of { params: type_expr list; ret_type: type_expr; is_mut: bool } + +type param = { + name: string; + type_: type_expr +} + +type decl = + | FunctionDecl of { name: string; params: param list; ret: type_expr } + +type package = { + decl: decl list +} diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 93a16a93..a19b4c25 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -1,18 +1,31 @@ -%token INT -%token PLUS MINUS MUL DIV LPAREN RPAREN EOF +%token INT FLOAT STRING IDENT +%token EQUAL +%token LPAREN RPAREN +%token LCURLY RCURLY +%token COMMA COLON +%token EXCL TILDE +%token PLUS MINUS STAR SLASH +%token DOLLAR AT +%token THIN_ARROW THICK_ARROW +%token THIS +%token ERROR +%token EOF %left PLUS MINUS -%left MUL DIV +%left STAR SLASH -%start prog +%start package %% -prog: - | e = expr EOF { e } -expr: - | i = INT { Nodes.Int i } - | LPAREN e = expr RPAREN { Nodes.Parenthized e } - | e1 = expr PLUS e2 = expr { Nodes.Add (e1, e2) } - | e1 = expr MINUS e2 = expr { Nodes.Sub (e1, e2) } - | e1 = expr MUL e2 = expr { Nodes.Mul (e1, e2) } - | e1 = expr DIV e2 = expr { Nodes.Div (e1, e2) } +package: + | decls = list(decl) EOF { { Nodes.decl = decls } } + +decl: + | name = IDENT LPAREN params = separated_list(COMMA, param) RPAREN ret = type_expr + { Nodes.FunctionDecl { name; params; ret } } + +param: + | name = IDENT type_ = type_expr { { Nodes.name; type_ } } + +type_expr: + | name = IDENT { Nodes.Simple name } diff --git a/lib/cst/to_string.ml b/lib/cst/to_string.ml index 3d26a8b5..7a3585eb 100644 --- a/lib/cst/to_string.ml +++ b/lib/cst/to_string.ml @@ -1,7 +1,29 @@ -let rec to_string = function - | Nodes.Int n -> string_of_int n - | Nodes.Add (e1, e2) -> to_string e1 ^ " + " ^ to_string e2 - | Nodes.Sub (e1, e2) -> to_string e1 ^ " - " ^ to_string e2 - | Nodes.Mul (e1, e2) -> to_string e1 ^ " * " ^ to_string e2 - | Nodes.Div (e1, e2) -> to_string e1 ^ " / " ^ to_string e2 - | Nodes.Parenthized e -> "(" ^ to_string e ^ ")" +let rec expr_to_string = function + | Nodes.IntLiteral s -> s + | Nodes.FloatLiteral s -> s + | Nodes.StringLiteral s -> "\"" ^ s ^ "\"" + | Nodes.Add (e1, e2) -> expr_to_string e1 ^ " + " ^ expr_to_string e2 + | Nodes.Sub (e1, e2) -> expr_to_string e1 ^ " - " ^ expr_to_string e2 + | Nodes.Mul (e1, e2) -> expr_to_string e1 ^ " * " ^ expr_to_string e2 + | Nodes.Div (e1, e2) -> expr_to_string e1 ^ " / " ^ expr_to_string e2 + | Nodes.Parenthized e -> "(" ^ expr_to_string e ^ ")" + +and type_to_string = function + | Nodes.Simple s -> s + | Nodes.FunctionType { params; ret_type } -> + "(" ^ String.concat ", " (List.map type_to_string params) ^ ") " ^ type_to_string ret_type + | Nodes.MethodType { params; ret_type; is_mut } -> + (if is_mut then "mut " else "") ^ + "(" ^ String.concat ", " (List.map type_to_string params) ^ ") " ^ type_to_string ret_type + +and param_to_string { Nodes.name; type_ } = + name ^ " " ^ type_to_string type_ + +and decl_to_string = function + | Nodes.FunctionDecl { name; params; ret } -> + name ^ " (" + ^ String.concat ", " (List.map param_to_string params) + ^ ") " ^ type_to_string ret + +let to_string { Nodes.decl } = + String.concat "\n" (List.map decl_to_string decl) diff --git a/test-parser/main.zn b/test-parser/main.zn index 82eef531..995a7ebd 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1 +1 @@ -(1 + 1) *(3 + 3) / 3 +main (hi Int, a Bool) Void From 6d4a67b5f7c0492c7261eff4d120cd109194e43b Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 3 Jun 2026 18:02:39 +0200 Subject: [PATCH 080/154] update --- bin/compiler/dune | 4 +++- bin/compiler/main.ml | 15 ++++++++------- justfile | 4 ++++ lib/tree_graph/dune | 2 ++ lib/tree_graph/node.ml | 6 ++++++ lib/tree_graph/render.ml | 19 +++++++++++++++++++ lib/tree_graph/tree_graph.ml | 2 ++ notes.md | 2 ++ 8 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 lib/tree_graph/dune create mode 100644 lib/tree_graph/node.ml create mode 100644 lib/tree_graph/render.ml create mode 100644 lib/tree_graph/tree_graph.ml diff --git a/bin/compiler/dune b/bin/compiler/dune index 1e63b49e..fda35641 100644 --- a/bin/compiler/dune +++ b/bin/compiler/dune @@ -1,4 +1,6 @@ (executable (name main) - (libraries cst) + (public_name main) + (package zane-compiler) + (libraries cst tree_graph) (modules main)) diff --git a/bin/compiler/main.ml b/bin/compiler/main.ml index ae33bb4e..6d7f63ff 100644 --- a/bin/compiler/main.ml +++ b/bin/compiler/main.ml @@ -1,8 +1,9 @@ -let read_file path = - In_channel.with_open_text path In_channel.input_all - let () = - let input = read_file "test-parser/main.zn" in - let cst = Cst.parse input in - let output = Cst.to_string cst in - print_endline output + let tree = Tree_graph.Fields ("hi", Tree_graph.StringMap.of_list [ + ("child1", Tree_graph.Fields ("hi", Tree_graph.StringMap.of_list [ + ("child1", Tree_graph.Leaf "bye"); + ("child2", Tree_graph.Leaf "see ya") + ])); + ("child2", Tree_graph.Children ("hello", [Tree_graph.Leaf "see ya"])) + ]) in + print_endline (Tree_graph.render tree) diff --git a/justfile b/justfile index 2f523465..5e4c606a 100644 --- a/justfile +++ b/justfile @@ -4,5 +4,9 @@ default: run: dune exec bin/compiler/main.exe +rebuild: + dune clean + dune build + watch: dune build --watch diff --git a/lib/tree_graph/dune b/lib/tree_graph/dune new file mode 100644 index 00000000..756b7f6e --- /dev/null +++ b/lib/tree_graph/dune @@ -0,0 +1,2 @@ +(library + (name tree_graph)) diff --git a/lib/tree_graph/node.ml b/lib/tree_graph/node.ml new file mode 100644 index 00000000..ba123ba4 --- /dev/null +++ b/lib/tree_graph/node.ml @@ -0,0 +1,6 @@ +module StringMap = Map.Make(String) [@@deriving map] + +type nodes = + | Leaf of string + | Fields of string * nodes StringMap.t + | Children of string * nodes list diff --git a/lib/tree_graph/render.ml b/lib/tree_graph/render.ml new file mode 100644 index 00000000..8accd961 --- /dev/null +++ b/lib/tree_graph/render.ml @@ -0,0 +1,19 @@ +let indent level = String.make (level * 2) ' ' + + +let rec render indent_level node = + match node with + | Node.Leaf leaf -> + indent indent_level ^ leaf + | Node.Fields (name, fields) -> + indent indent_level ^ name ^ ":\n" ^ render_fields (indent_level + 1) fields + | Node.Children (name, children) -> + indent indent_level ^ name ^ ":\n" ^ + String.concat "\n" (List.map (fun c -> render (indent_level + 1) c) children) + +and render_fields indent_level fields = + Node.StringMap.bindings fields + |> List.map (fun (key, child_node) -> + indent indent_level ^ key ^ ":\n" ^ render (indent_level + 1) child_node + ) + |> String.concat "\n" diff --git a/lib/tree_graph/tree_graph.ml b/lib/tree_graph/tree_graph.ml new file mode 100644 index 00000000..aa4e4fe0 --- /dev/null +++ b/lib/tree_graph/tree_graph.ml @@ -0,0 +1,2 @@ +include Node +let render node = Render.render 0 node diff --git a/notes.md b/notes.md index 25b5f2fd..f2d76684 100644 --- a/notes.md +++ b/notes.md @@ -7,3 +7,5 @@ get to state after issue `sudo apt install libc++-21-dev libc++abi-21-dev` should be fixed on the commit where notes.md is added + +execution bottom to top? From 4f6013590ac1d3cbd480df47affa3a371ffe42f8 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 3 Jun 2026 22:01:15 +0200 Subject: [PATCH 081/154] update --- bin/compiler/main.ml | 13 ++++++---- lib/tree_graph/render.ml | 50 +++++++++++++++++++++++++----------- lib/tree_graph/tree_graph.ml | 2 +- 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/bin/compiler/main.ml b/bin/compiler/main.ml index 6d7f63ff..9f0fc1cf 100644 --- a/bin/compiler/main.ml +++ b/bin/compiler/main.ml @@ -1,9 +1,12 @@ let () = - let tree = Tree_graph.Fields ("hi", Tree_graph.StringMap.of_list [ - ("child1", Tree_graph.Fields ("hi", Tree_graph.StringMap.of_list [ - ("child1", Tree_graph.Leaf "bye"); - ("child2", Tree_graph.Leaf "see ya") + let tree = Tree_graph.Fields ("editors", Tree_graph.StringMap.of_list [ + ("constraints", Tree_graph.Fields ("required languages", Tree_graph.StringMap.of_list [ + ("cpp", Tree_graph.Leaf "full"); + ("yacc", Tree_graph.Leaf "ts only") ])); - ("child2", Tree_graph.Children ("hello", [Tree_graph.Leaf "see ya"])) + ("candidates", Tree_graph.Children ("closest", [Tree_graph.Fields ("required languages", Tree_graph.StringMap.of_list [ + ("cpp", Tree_graph.Leaf "full"); + ("yacc", Tree_graph.Leaf "ts only") + ]); Tree_graph.Leaf "zed"])) ]) in print_endline (Tree_graph.render tree) diff --git a/lib/tree_graph/render.ml b/lib/tree_graph/render.ml index 8accd961..db2ff4cc 100644 --- a/lib/tree_graph/render.ml +++ b/lib/tree_graph/render.ml @@ -1,19 +1,39 @@ -let indent level = String.make (level * 2) ' ' +let render node = + let rec render_fields prefix fields = + let bindings = Node.StringMap.bindings fields in + let len = List.length bindings in + List.mapi (fun i (key, child) -> + render_node prefix (i = len - 1) key child + ) bindings |> String.concat "\n" + and render_children prefix name children = + let len = List.length children in + List.mapi (fun i child -> + let key = name ^ "[" ^ string_of_int i ^ "]" in + render_node prefix (i = len - 1) key child + ) children |> String.concat "\n" -let rec render indent_level node = + and render_node prefix is_last key node = + let connector = if is_last then "└── " else "├── " in + let next_prefix = prefix ^ (if is_last then " " else "│ ") in + match node with + | Node.Leaf v -> + prefix ^ connector ^ key ^ ": " ^ v + | Node.Fields (_, fields) -> + let header = prefix ^ connector ^ key ^ ":" in + if Node.StringMap.is_empty fields then header + else header ^ "\n" ^ render_fields next_prefix fields + | Node.Children (name, children) -> + let header = prefix ^ connector ^ key ^ ":" in + if children = [] then header + else header ^ "\n" ^ render_children next_prefix name children + in match node with - | Node.Leaf leaf -> - indent indent_level ^ leaf - | Node.Fields (name, fields) -> - indent indent_level ^ name ^ ":\n" ^ render_fields (indent_level + 1) fields + | Node.Leaf v -> v + | Node.Fields (name, fields) -> + let header = name ^ ":" in + if Node.StringMap.is_empty fields then header + else header ^ "\n" ^ render_fields "" fields | Node.Children (name, children) -> - indent indent_level ^ name ^ ":\n" ^ - String.concat "\n" (List.map (fun c -> render (indent_level + 1) c) children) - -and render_fields indent_level fields = - Node.StringMap.bindings fields - |> List.map (fun (key, child_node) -> - indent indent_level ^ key ^ ":\n" ^ render (indent_level + 1) child_node - ) - |> String.concat "\n" + if children = [] then name ^ ":" + else render_children "" name children diff --git a/lib/tree_graph/tree_graph.ml b/lib/tree_graph/tree_graph.ml index aa4e4fe0..6db1f99d 100644 --- a/lib/tree_graph/tree_graph.ml +++ b/lib/tree_graph/tree_graph.ml @@ -1,2 +1,2 @@ include Node -let render node = Render.render 0 node +let render node = Render.render node From 8b5e50371ffaf2d3a5c6bee439baed329c67311e Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 3 Jun 2026 23:04:00 +0200 Subject: [PATCH 082/154] improve tree_graph --- lib/tree_graph/node.ml | 7 ++++--- lib/tree_graph/render.ml | 39 ++++++++++++++++++++++++--------------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/lib/tree_graph/node.ml b/lib/tree_graph/node.ml index ba123ba4..578f2d72 100644 --- a/lib/tree_graph/node.ml +++ b/lib/tree_graph/node.ml @@ -1,6 +1,7 @@ module StringMap = Map.Make(String) [@@deriving map] -type nodes = +type node = | Leaf of string - | Fields of string * nodes StringMap.t - | Children of string * nodes list + | Group of { title: string; body: node } + | Fields of node StringMap.t + | Children of node list diff --git a/lib/tree_graph/render.ml b/lib/tree_graph/render.ml index db2ff4cc..73c4cdb8 100644 --- a/lib/tree_graph/render.ml +++ b/lib/tree_graph/render.ml @@ -19,21 +19,30 @@ let render node = match node with | Node.Leaf v -> prefix ^ connector ^ key ^ ": " ^ v - | Node.Fields (_, fields) -> - let header = prefix ^ connector ^ key ^ ":" in - if Node.StringMap.is_empty fields then header - else header ^ "\n" ^ render_fields next_prefix fields - | Node.Children (name, children) -> - let header = prefix ^ connector ^ key ^ ":" in - if children = [] then header - else header ^ "\n" ^ render_children next_prefix name children + | Node.Group { title; body } -> + let header = prefix ^ connector ^ key ^ " (" ^ title ^ "):" in + header ^ "\n" ^ render_node next_prefix true "" body + | Node.Fields fields -> + if Node.StringMap.is_empty fields then + prefix ^ connector ^ key + else + let header = prefix ^ connector ^ key ^ ":" in + header ^ "\n" ^ render_fields next_prefix fields + | Node.Children children -> + if children = [] then + prefix ^ connector ^ key + else + let header = prefix ^ connector ^ key ^ ":" in + header ^ "\n" ^ render_children next_prefix key children in match node with | Node.Leaf v -> v - | Node.Fields (name, fields) -> - let header = name ^ ":" in - if Node.StringMap.is_empty fields then header - else header ^ "\n" ^ render_fields "" fields - | Node.Children (name, children) -> - if children = [] then name ^ ":" - else render_children "" name children + | Node.Group { title; body } -> + let header = "(" ^ title ^ "):" in + header ^ "\n" ^ render_node "" true "" body + | Node.Fields fields -> + if Node.StringMap.is_empty fields then "" + else render_fields "" fields + | Node.Children children -> + if children = [] then "" + else render_children "" "item" children From 794874e6592f933fa0243f0dfa9b14f8b36ecf89 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 4 Jun 2026 13:28:56 +0200 Subject: [PATCH 083/154] update --- bin/compiler/main.ml | 37 +++++++++++------ lib/cst/cst.ml | 2 +- lib/cst/dune | 2 +- lib/cst/nodes.ml | 4 +- lib/cst/parser.mly | 6 +-- lib/cst/to_string.ml | 29 ------------- lib/cst/to_tree_graph.ml | 33 +++++++++++++++ lib/tree_graph/render.ml | 89 ++++++++++++++++++++-------------------- 8 files changed, 109 insertions(+), 93 deletions(-) delete mode 100644 lib/cst/to_string.ml create mode 100644 lib/cst/to_tree_graph.ml diff --git a/bin/compiler/main.ml b/bin/compiler/main.ml index 9f0fc1cf..6bb68e87 100644 --- a/bin/compiler/main.ml +++ b/bin/compiler/main.ml @@ -1,12 +1,25 @@ -let () = - let tree = Tree_graph.Fields ("editors", Tree_graph.StringMap.of_list [ - ("constraints", Tree_graph.Fields ("required languages", Tree_graph.StringMap.of_list [ - ("cpp", Tree_graph.Leaf "full"); - ("yacc", Tree_graph.Leaf "ts only") - ])); - ("candidates", Tree_graph.Children ("closest", [Tree_graph.Fields ("required languages", Tree_graph.StringMap.of_list [ - ("cpp", Tree_graph.Leaf "full"); - ("yacc", Tree_graph.Leaf "ts only") - ]); Tree_graph.Leaf "zed"])) - ]) in - print_endline (Tree_graph.render tree) +let map1 = Tree_graph.StringMap.of_list [ + ("name", Tree_graph.Leaf "hi"); + ("type", Tree_graph.Leaf "Int"); +] in +let map2 = Tree_graph.StringMap.of_list [ + ("name", Tree_graph.Leaf "a"); + ("type", Tree_graph.Leaf "Bool"); +] in + +let root = Tree_graph.Group { + title = "package"; + body = Tree_graph.Fields (Tree_graph.StringMap.of_list [ + ("params", Tree_graph.Children [Tree_graph.Fields map1; Tree_graph.Fields map2]); + ("ret_type", Tree_graph.Leaf "Void"); + ("sub_data", Tree_graph.Group { + title = "package"; + body = Tree_graph.Fields (Tree_graph.StringMap.of_list [ + ("params", Tree_graph.Children [Tree_graph.Fields map1; Tree_graph.Fields map2]); + ("ret_type", Tree_graph.Leaf "Void"); + ]) + }); + ]) +} in + +Tree_graph.render root diff --git a/lib/cst/cst.ml b/lib/cst/cst.ml index 97fb2b4c..6deca1ba 100644 --- a/lib/cst/cst.ml +++ b/lib/cst/cst.ml @@ -1,7 +1,7 @@ module Nodes = Nodes module Parser = Parser module Lexer = Lexer -include To_string +include To_tree_graph let parse input = let lexbuf = Sedlexing.Utf8.from_string input in diff --git a/lib/cst/dune b/lib/cst/dune index 9281c372..cd0a1848 100644 --- a/lib/cst/dune +++ b/lib/cst/dune @@ -1,6 +1,6 @@ (library (name cst) - (libraries menhirLib sedlex) + (libraries menhirLib sedlex tree_graph) (preprocess (pps sedlex.ppx))) (menhir diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 0a81a94b..1b6d4ee6 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -19,8 +19,8 @@ type param = { } type decl = - | FunctionDecl of { name: string; params: param list; ret: type_expr } + | FunctionDecl of { name: string; params: param list; ret_type: type_expr } type package = { - decl: decl list + decls: decl list } diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index a19b4c25..6f8b8722 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -18,11 +18,11 @@ %% package: - | decls = list(decl) EOF { { Nodes.decl = decls } } + | decls = list(decl) EOF { { Nodes.decls = decls } } decl: - | name = IDENT LPAREN params = separated_list(COMMA, param) RPAREN ret = type_expr - { Nodes.FunctionDecl { name; params; ret } } + | name = IDENT LPAREN params = separated_list(COMMA, param) RPAREN ret_type = type_expr + { Nodes.FunctionDecl { name; params; ret_type } } param: | name = IDENT type_ = type_expr { { Nodes.name; type_ } } diff --git a/lib/cst/to_string.ml b/lib/cst/to_string.ml deleted file mode 100644 index 7a3585eb..00000000 --- a/lib/cst/to_string.ml +++ /dev/null @@ -1,29 +0,0 @@ -let rec expr_to_string = function - | Nodes.IntLiteral s -> s - | Nodes.FloatLiteral s -> s - | Nodes.StringLiteral s -> "\"" ^ s ^ "\"" - | Nodes.Add (e1, e2) -> expr_to_string e1 ^ " + " ^ expr_to_string e2 - | Nodes.Sub (e1, e2) -> expr_to_string e1 ^ " - " ^ expr_to_string e2 - | Nodes.Mul (e1, e2) -> expr_to_string e1 ^ " * " ^ expr_to_string e2 - | Nodes.Div (e1, e2) -> expr_to_string e1 ^ " / " ^ expr_to_string e2 - | Nodes.Parenthized e -> "(" ^ expr_to_string e ^ ")" - -and type_to_string = function - | Nodes.Simple s -> s - | Nodes.FunctionType { params; ret_type } -> - "(" ^ String.concat ", " (List.map type_to_string params) ^ ") " ^ type_to_string ret_type - | Nodes.MethodType { params; ret_type; is_mut } -> - (if is_mut then "mut " else "") ^ - "(" ^ String.concat ", " (List.map type_to_string params) ^ ") " ^ type_to_string ret_type - -and param_to_string { Nodes.name; type_ } = - name ^ " " ^ type_to_string type_ - -and decl_to_string = function - | Nodes.FunctionDecl { name; params; ret } -> - name ^ " (" - ^ String.concat ", " (List.map param_to_string params) - ^ ") " ^ type_to_string ret - -let to_string { Nodes.decl } = - String.concat "\n" (List.map decl_to_string decl) diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml new file mode 100644 index 00000000..d979722f --- /dev/null +++ b/lib/cst/to_tree_graph.ml @@ -0,0 +1,33 @@ +let rec type_to_node = function + | Nodes.Simple s -> Tree_graph.Leaf s + | Nodes.FunctionType { params; ret_type } -> + Tree_graph.Fields (Tree_graph.StringMap.of_list [ + ("params", Tree_graph.Children (List.map type_to_node params)); + ("type", type_to_node ret_type); + ]) + | Nodes.MethodType { params; ret_type; is_mut } -> + Tree_graph.Fields (Tree_graph.StringMap.of_list [ + ("params", Tree_graph.Children (List.map type_to_node params)); + ("type", type_to_node ret_type); + ("is_mut", Tree_graph.Leaf (string_of_bool is_mut)); + ]) + +and param_to_node (x : Nodes.param) = + Tree_graph.Fields (Tree_graph.StringMap.of_list [ + ("name", Tree_graph.Leaf x.name); + ("type", type_to_node x.type_); + ]) + +and params_to_node (x: Nodes.param list) = + Tree_graph.Children (List.map param_to_node x) + + +and decl_to_node = function + | Nodes.FunctionDecl { name; params; ret_type } -> + Tree_graph.Fields (Tree_graph.StringMap.of_list [ + ("params", params_to_node params); + ("ret_type", type_to_node ret_type); + ]) + +let to_node ({ Nodes.decls }: Nodes.package) = + Tree_graph.Group { title = "package"; body = Tree_graph.Children (List.map decl_to_node decls) } diff --git a/lib/tree_graph/render.ml b/lib/tree_graph/render.ml index 73c4cdb8..644d8706 100644 --- a/lib/tree_graph/render.ml +++ b/lib/tree_graph/render.ml @@ -1,48 +1,47 @@ -let render node = - let rec render_fields prefix fields = - let bindings = Node.StringMap.bindings fields in - let len = List.length bindings in - List.mapi (fun i (key, child) -> - render_node prefix (i = len - 1) key child - ) bindings |> String.concat "\n" +(* Intermediate representation to flatten Children into their parent's scope *) +type item = + | ILeaf of string * string + | IContainer of string * item list - and render_children prefix name children = - let len = List.length children in - List.mapi (fun i child -> - let key = name ^ "[" ^ string_of_int i ^ "]" in - render_node prefix (i = len - 1) key child - ) children |> String.concat "\n" +let rec collect name = function + | Node.Leaf v -> [ILeaf (name, v)] + | Node.Group { title; body } -> collect title body + | Node.Fields map -> + let children = Node.StringMap.bindings map + |> List.map (fun (k, v) -> collect k v) + |> List.flatten in + [IContainer (name, children)] + | Node.Children list -> + if list = [] then [IContainer (name, [])] + else + (* Flattens the list so elements become direct siblings of other Fields/Children *) + List.mapi (fun i v -> + let child_name = if name = "" then Printf.sprintf "[%d]" i else Printf.sprintf "%s[%d]" name i in + collect child_name v + ) list |> List.flatten - and render_node prefix is_last key node = - let connector = if is_last then "└── " else "├── " in - let next_prefix = prefix ^ (if is_last then " " else "│ ") in - match node with - | Node.Leaf v -> - prefix ^ connector ^ key ^ ": " ^ v - | Node.Group { title; body } -> - let header = prefix ^ connector ^ key ^ " (" ^ title ^ "):" in - header ^ "\n" ^ render_node next_prefix true "" body - | Node.Fields fields -> - if Node.StringMap.is_empty fields then - prefix ^ connector ^ key - else - let header = prefix ^ connector ^ key ^ ":" in - header ^ "\n" ^ render_fields next_prefix fields - | Node.Children children -> - if children = [] then - prefix ^ connector ^ key - else - let header = prefix ^ connector ^ key ^ ":" in - header ^ "\n" ^ render_children next_prefix key children +let render root_node = + let items = collect "" root_node in + let rec print_items prefix items = + let len = List.length items in + List.iteri (fun i item -> + let is_last = (i = len - 1) in + let branch = if is_last then "└── " else "├── " in + let child_prefix = prefix ^ (if is_last then " " else "│ ") in + match item with + | ILeaf (name, value) -> + if name = "" then + Printf.printf "%s%s%s\n" prefix branch value + else + Printf.printf "%s%s%s: %s\n" prefix branch name value + | IContainer (name, children) -> + if name = "" then + (* Unnamed root container just prints its children without a header *) + print_items prefix children + else begin + Printf.printf "%s%s%s:\n" prefix branch name; + print_items child_prefix children + end + ) items in - match node with - | Node.Leaf v -> v - | Node.Group { title; body } -> - let header = "(" ^ title ^ "):" in - header ^ "\n" ^ render_node "" true "" body - | Node.Fields fields -> - if Node.StringMap.is_empty fields then "" - else render_fields "" fields - | Node.Children children -> - if children = [] then "" - else render_children "" "item" children + print_items "" items From 511f775531766ebbc0d92745178e506e0a27042b Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 4 Jun 2026 14:36:16 +0200 Subject: [PATCH 084/154] improve tree graph (more clean) --- bin/compiler/main.ml | 8 +++---- lib/tree_graph/render.ml | 45 ++++++++++++++++++++++++++-------------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/bin/compiler/main.ml b/bin/compiler/main.ml index 6bb68e87..fa051250 100644 --- a/bin/compiler/main.ml +++ b/bin/compiler/main.ml @@ -14,10 +14,10 @@ let root = Tree_graph.Group { ("ret_type", Tree_graph.Leaf "Void"); ("sub_data", Tree_graph.Group { title = "package"; - body = Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("params", Tree_graph.Children [Tree_graph.Fields map1; Tree_graph.Fields map2]); - ("ret_type", Tree_graph.Leaf "Void"); - ]) + body = Tree_graph.Group { + title = "package"; + body = Tree_graph.Leaf "bla" + } }); ]) } in diff --git a/lib/tree_graph/render.ml b/lib/tree_graph/render.ml index 644d8706..3af2308b 100644 --- a/lib/tree_graph/render.ml +++ b/lib/tree_graph/render.ml @@ -1,27 +1,41 @@ -(* Intermediate representation to flatten Children into their parent's scope *) -type item = +type item = | ILeaf of string * string | IContainer of string * item list -let rec collect name = function - | Node.Leaf v -> [ILeaf (name, v)] - | Node.Group { title; body } -> collect title body +let rec collect ~name node = + match node with + | Node.Leaf v -> + [ILeaf (name, v)] + + | Node.Group { title; body } -> + (* Chain group titles with " > " *) + let new_name = if name = "" then title else name ^ " > " ^ title in + collect ~name:new_name body + | Node.Fields map -> - let children = Node.StringMap.bindings map - |> List.map (fun (k, v) -> collect k v) - |> List.flatten in - [IContainer (name, children)] + let children = + Node.StringMap.bindings map + |> List.map (fun (k, v) -> collect ~name:k v) + |> List.flatten + in + (* If it's the unnamed root, just return the children directly *) + if name = "" then children + else [IContainer (name, children)] + | Node.Children list -> - if list = [] then [IContainer (name, [])] + if list = [] then + if name = "" then [] else [IContainer (name, [])] else - (* Flattens the list so elements become direct siblings of other Fields/Children *) List.mapi (fun i v -> - let child_name = if name = "" then Printf.sprintf "[%d]" i else Printf.sprintf "%s[%d]" name i in - collect child_name v + let child_name = + if name = "" then Printf.sprintf "[%d]" i + else Printf.sprintf "%s[%d]" name i + in + collect ~name:child_name v ) list |> List.flatten let render root_node = - let items = collect "" root_node in + let items = collect ~name:"" root_node in let rec print_items prefix items = let len = List.length items in List.iteri (fun i item -> @@ -35,8 +49,7 @@ let render root_node = else Printf.printf "%s%s%s: %s\n" prefix branch name value | IContainer (name, children) -> - if name = "" then - (* Unnamed root container just prints its children without a header *) + if name = "" then print_items prefix children else begin Printf.printf "%s%s%s:\n" prefix branch name; From 59f601b7679873b5cb7d8e9a031fe99a746fb122 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 4 Jun 2026 14:47:27 +0200 Subject: [PATCH 085/154] fix to_tree_graph --- bin/compiler/main.ml | 31 +++++++------------------------ lib/cst/to_tree_graph.ml | 18 +++++++++++++----- 2 files changed, 20 insertions(+), 29 deletions(-) diff --git a/bin/compiler/main.ml b/bin/compiler/main.ml index fa051250..ab2827da 100644 --- a/bin/compiler/main.ml +++ b/bin/compiler/main.ml @@ -1,25 +1,8 @@ -let map1 = Tree_graph.StringMap.of_list [ - ("name", Tree_graph.Leaf "hi"); - ("type", Tree_graph.Leaf "Int"); -] in -let map2 = Tree_graph.StringMap.of_list [ - ("name", Tree_graph.Leaf "a"); - ("type", Tree_graph.Leaf "Bool"); -] in +let read_file path = + In_channel.with_open_text path In_channel.input_all -let root = Tree_graph.Group { - title = "package"; - body = Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("params", Tree_graph.Children [Tree_graph.Fields map1; Tree_graph.Fields map2]); - ("ret_type", Tree_graph.Leaf "Void"); - ("sub_data", Tree_graph.Group { - title = "package"; - body = Tree_graph.Group { - title = "package"; - body = Tree_graph.Leaf "bla" - } - }); - ]) -} in - -Tree_graph.render root +let () = + let input = read_file "test-parser/main.zn" in + let cst = Cst.parse input in + let output = Cst.to_node cst in + Tree_graph.render output diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index d979722f..342a8107 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -24,10 +24,18 @@ and params_to_node (x: Nodes.param list) = and decl_to_node = function | Nodes.FunctionDecl { name; params; ret_type } -> - Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("params", params_to_node params); - ("ret_type", type_to_node ret_type); - ]) + Tree_graph.Group { + title = "function_decl"; + body = Tree_graph.Fields ( + Tree_graph.StringMap.of_list [ + ("params", params_to_node params); + ("ret_type", type_to_node ret_type); + ] + ) + } let to_node ({ Nodes.decls }: Nodes.package) = - Tree_graph.Group { title = "package"; body = Tree_graph.Children (List.map decl_to_node decls) } + Tree_graph.Group { title = "package"; body = Tree_graph.Fields (Tree_graph.StringMap.of_list [ + ("declarations", Tree_graph.Children (List.map decl_to_node decls)) + ]) + } From 035e43870094d3d86db91ec426d5b541ddbd52e7 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 4 Jun 2026 17:48:29 +0200 Subject: [PATCH 086/154] update --- lib/cst/nodes.ml | 14 ++++++---- lib/cst/parser.mly | 59 +++++++++++++++++++++++++++++++--------- lib/cst/to_tree_graph.ml | 48 ++++++++++++++++++++++++++++---- lib/tree_graph/node.ml | 2 +- lib/tree_graph/render.ml | 22 +++++++-------- test-parser/main.zn | 5 +++- 6 files changed, 112 insertions(+), 38 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 1b6d4ee6..c5c2ecc7 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -2,10 +2,8 @@ type expr = | IntLiteral of string | FloatLiteral of string | StringLiteral of string - | Add of expr * expr - | Sub of expr * expr - | Mul of expr * expr - | Div of expr * expr + | Ident of string + | Operator of {left: expr; right: expr; operator: string} | Parenthized of expr type type_expr = @@ -18,8 +16,14 @@ type param = { type_: type_expr } +type statement = + | FunctionCall of { callee: expr; args: expr list; } + +type body = + | Scope of statement list + type decl = - | FunctionDecl of { name: string; params: param list; ret_type: type_expr } + | FunctionDecl of { name: string; params: param list; ret_type: type_expr; body: body } type package = { decls: decl list diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 6f8b8722..18de8b1b 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -1,12 +1,24 @@ +(*****************************) +(* token definitions *) +(*****************************) %token INT FLOAT STRING IDENT -%token EQUAL -%token LPAREN RPAREN -%token LCURLY RCURLY -%token COMMA COLON -%token EXCL TILDE -%token PLUS MINUS STAR SLASH -%token DOLLAR AT -%token THIN_ARROW THICK_ARROW +%token LPAREN "(" +%token RPAREN ")" +%token COMMA "," +%token LCURLY "{" +%token RCURLY "}" +%token COLON ":" +%token EQUAL "=" +%token PLUS "+" +%token MINUS "-" +%token STAR "*" +%token SLASH "/" +%token DOLLAR "$" +%token AT "@" +%token EXCL "!" +%token TILDE "~" +%token THIN_ARROW "->" +%token THICK_ARROW "=>" %token THIS %token ERROR %token EOF @@ -15,17 +27,38 @@ %left STAR SLASH %start package + +(*************************) +(* grammar rules *) +(*************************) %% package: - | decls = list(decl) EOF { { Nodes.decls = decls } } + | decls=list(decl) EOF { { Nodes.decls=decls } } decl: - | name = IDENT LPAREN params = separated_list(COMMA, param) RPAREN ret_type = type_expr - { Nodes.FunctionDecl { name; params; ret_type } } + | name=IDENT "(" params=separated_list(COMMA, param) ")" ret_type=type_expr body=function_body { + Nodes.FunctionDecl { name; params; ret_type; body } + } + +function_body: + | "{" statements=list(statement) "}" { + Nodes.Scope statements + } + +statement: + | callee=expr "(" args=separated_list(COMMA, expr) ")" { + Nodes.FunctionCall { callee; args } + } param: - | name = IDENT type_ = type_expr { { Nodes.name; type_ } } + | name=IDENT type_=type_expr { { Nodes.name; type_ } } type_expr: - | name = IDENT { Nodes.Simple name } + | name=IDENT { Nodes.Simple name } + +expr: + | int=INT { Nodes.IntLiteral int } + | float=FLOAT { Nodes.FloatLiteral float } + | string=STRING { Nodes.StringLiteral string } + | ident=IDENT { Nodes.Ident ident } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 342a8107..44b892ec 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -2,40 +2,76 @@ let rec type_to_node = function | Nodes.Simple s -> Tree_graph.Leaf s | Nodes.FunctionType { params; ret_type } -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("params", Tree_graph.Children (List.map type_to_node params)); + ("params", Tree_graph.Sequence (List.map type_to_node params)); ("type", type_to_node ret_type); ]) | Nodes.MethodType { params; ret_type; is_mut } -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("params", Tree_graph.Children (List.map type_to_node params)); + ("params", Tree_graph.Sequence (List.map type_to_node params)); ("type", type_to_node ret_type); ("is_mut", Tree_graph.Leaf (string_of_bool is_mut)); ]) -and param_to_node (x : Nodes.param) = +and expr_to_node (x: Nodes.expr) = match x with + | Nodes.IntLiteral x -> Tree_graph.Leaf x + | Nodes.FloatLiteral x -> Tree_graph.Leaf x + | Nodes.StringLiteral x -> Tree_graph.Leaf x + | Nodes.Ident x -> Tree_graph.Leaf x + | Nodes.Operator x -> + Tree_graph.Fields (Tree_graph.StringMap.of_list [ + ("left", expr_to_node x.left); + ("right", expr_to_node x.right); + ("op", Tree_graph.Leaf x.operator); + ]) + | Nodes.Parenthized x -> + Tree_graph.Group { + title = "Parenthized"; + body = expr_to_node x + } + +and param_to_node (x: Nodes.param) = Tree_graph.Fields (Tree_graph.StringMap.of_list [ ("name", Tree_graph.Leaf x.name); ("type", type_to_node x.type_); ]) and params_to_node (x: Nodes.param list) = - Tree_graph.Children (List.map param_to_node x) + Tree_graph.Sequence (List.map param_to_node x) + +and statement_to_node (x: Nodes.statement) = match x with + | Nodes.FunctionCall x -> + Tree_graph.Group { + title = "function_call"; + body = Tree_graph.Fields ( + Tree_graph.StringMap.of_list [ + ("callee", expr_to_node x.callee); + ("args", Tree_graph.Sequence (List.map expr_to_node x.args)); + ] + ) + } +and body_to_node (x: Nodes.body) = match x with + | Nodes.Scope scope -> + Tree_graph.Group { + title = "scope"; + body = Tree_graph.Sequence (List.map statement_to_node scope) + } and decl_to_node = function - | Nodes.FunctionDecl { name; params; ret_type } -> + | Nodes.FunctionDecl { name; params; ret_type; body } -> Tree_graph.Group { title = "function_decl"; body = Tree_graph.Fields ( Tree_graph.StringMap.of_list [ ("params", params_to_node params); ("ret_type", type_to_node ret_type); + ("body", body_to_node body); ] ) } let to_node ({ Nodes.decls }: Nodes.package) = Tree_graph.Group { title = "package"; body = Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("declarations", Tree_graph.Children (List.map decl_to_node decls)) + ("declarations", Tree_graph.Sequence (List.map decl_to_node decls)) ]) } diff --git a/lib/tree_graph/node.ml b/lib/tree_graph/node.ml index 578f2d72..7aa7be9d 100644 --- a/lib/tree_graph/node.ml +++ b/lib/tree_graph/node.ml @@ -4,4 +4,4 @@ type node = | Leaf of string | Group of { title: string; body: node } | Fields of node StringMap.t - | Children of node list + | Sequence of node list diff --git a/lib/tree_graph/render.ml b/lib/tree_graph/render.ml index 3af2308b..d6fbff32 100644 --- a/lib/tree_graph/render.ml +++ b/lib/tree_graph/render.ml @@ -8,30 +8,28 @@ let rec collect ~name node = [ILeaf (name, v)] | Node.Group { title; body } -> - (* Chain group titles with " > " *) let new_name = if name = "" then title else name ^ " > " ^ title in collect ~name:new_name body | Node.Fields map -> - let children = + let nested_items = Node.StringMap.bindings map |> List.map (fun (k, v) -> collect ~name:k v) |> List.flatten in - (* If it's the unnamed root, just return the children directly *) - if name = "" then children - else [IContainer (name, children)] + if name = "" then nested_items + else [IContainer (name, nested_items)] - | Node.Children list -> + | Node.Sequence list -> if list = [] then if name = "" then [] else [IContainer (name, [])] else List.mapi (fun i v -> - let child_name = + let element_name = if name = "" then Printf.sprintf "[%d]" i else Printf.sprintf "%s[%d]" name i in - collect ~name:child_name v + collect ~name:element_name v ) list |> List.flatten let render root_node = @@ -41,19 +39,19 @@ let render root_node = List.iteri (fun i item -> let is_last = (i = len - 1) in let branch = if is_last then "└── " else "├── " in - let child_prefix = prefix ^ (if is_last then " " else "│ ") in + let nested_prefix = prefix ^ (if is_last then " " else "│ ") in match item with | ILeaf (name, value) -> if name = "" then Printf.printf "%s%s%s\n" prefix branch value else Printf.printf "%s%s%s: %s\n" prefix branch name value - | IContainer (name, children) -> + | IContainer (name, nested_items) -> if name = "" then - print_items prefix children + print_items prefix nested_items else begin Printf.printf "%s%s%s:\n" prefix branch name; - print_items child_prefix children + print_items nested_prefix nested_items end ) items in diff --git a/test-parser/main.zn b/test-parser/main.zn index 995a7ebd..2bf8bf09 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1 +1,4 @@ -main (hi Int, a Bool) Void +main (hi Int, a Bool) Void { + print("hi") + log("bug") +} From 5d59a9c8e998cdf766826e501461f5415c96e4a9 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 4 Jun 2026 18:28:15 +0200 Subject: [PATCH 087/154] improve naming --- lib/cst/to_tree_graph.ml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 44b892ec..4102d627 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -2,12 +2,12 @@ let rec type_to_node = function | Nodes.Simple s -> Tree_graph.Leaf s | Nodes.FunctionType { params; ret_type } -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("params", Tree_graph.Sequence (List.map type_to_node params)); + ("param", Tree_graph.Sequence (List.map type_to_node params)); ("type", type_to_node ret_type); ]) | Nodes.MethodType { params; ret_type; is_mut } -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("params", Tree_graph.Sequence (List.map type_to_node params)); + ("param", Tree_graph.Sequence (List.map type_to_node params)); ("type", type_to_node ret_type); ("is_mut", Tree_graph.Leaf (string_of_bool is_mut)); ]) @@ -45,7 +45,7 @@ and statement_to_node (x: Nodes.statement) = match x with body = Tree_graph.Fields ( Tree_graph.StringMap.of_list [ ("callee", expr_to_node x.callee); - ("args", Tree_graph.Sequence (List.map expr_to_node x.args)); + ("arg", Tree_graph.Sequence (List.map expr_to_node x.args)); ] ) } @@ -54,7 +54,10 @@ and body_to_node (x: Nodes.body) = match x with | Nodes.Scope scope -> Tree_graph.Group { title = "scope"; - body = Tree_graph.Sequence (List.map statement_to_node scope) + body = Tree_graph.Group { + title = "statement"; + body = Tree_graph.Sequence (List.map statement_to_node scope) + } } and decl_to_node = function @@ -63,7 +66,7 @@ and decl_to_node = function title = "function_decl"; body = Tree_graph.Fields ( Tree_graph.StringMap.of_list [ - ("params", params_to_node params); + ("param", params_to_node params); ("ret_type", type_to_node ret_type); ("body", body_to_node body); ] From a609271d57f5bbff138ce1b82f02bda89c299a40 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 4 Jun 2026 19:08:57 +0200 Subject: [PATCH 088/154] update --- lib/cst/nodes.ml | 14 +++++++++++--- lib/cst/parser.mly | 42 +++++++++++++++++++++++++++++----------- lib/cst/to_tree_graph.ml | 25 +++++++++++++----------- 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index c5c2ecc7..c31df4aa 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -1,13 +1,21 @@ +(* The CST's job is to represent what was parsed, not what's valid. *) + type expr = | IntLiteral of string | FloatLiteral of string | StringLiteral of string | Ident of string - | Operator of {left: expr; right: expr; operator: string} + | Operator of { left: expr; right: expr; operator: string } | Parenthized of expr + | FunctionCall of function_call + +and function_call = { + callee: expr; + args: expr list +} type type_expr = - | Simple of string + | SimpleType of string | FunctionType of { params: type_expr list; ret_type: type_expr } | MethodType of { params: type_expr list; ret_type: type_expr; is_mut: bool } @@ -17,7 +25,7 @@ type param = { } type statement = - | FunctionCall of { callee: expr; args: expr list; } + | ExprStatement of expr type body = | Scope of statement list diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 18de8b1b..0f3c5e4b 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -34,31 +34,51 @@ %% package: - | decls=list(decl) EOF { { Nodes.decls=decls } } + | decls=list(decl) EOF { { Nodes.decls = decls } } decl: - | name=IDENT "(" params=separated_list(COMMA, param) ")" ret_type=type_expr body=function_body { - Nodes.FunctionDecl { name; params; ret_type; body } - } + | name=IDENT LPAREN params=separated_list(COMMA, param) RPAREN + ret_type=type_expr body=function_body { + Nodes.FunctionDecl { name; params; ret_type; body } + } function_body: - | "{" statements=list(statement) "}" { - Nodes.Scope statements - } + | LCURLY statements=list(statement) RCURLY { + Nodes.Scope statements + } statement: - | callee=expr "(" args=separated_list(COMMA, expr) ")" { - Nodes.FunctionCall { callee; args } - } + | expr=expr + { Nodes.ExprStatement expr } param: | name=IDENT type_=type_expr { { Nodes.name; type_ } } type_expr: - | name=IDENT { Nodes.Simple name } + | name=IDENT { Nodes.SimpleType name } + | LPAREN params=separated_list(COMMA, type_expr) RPAREN THIN_ARROW ret=type_expr { + Nodes.FunctionType { params; ret_type=ret } + } + | LPAREN params=separated_list(COMMA, type_expr) RPAREN THICK_ARROW ret=type_expr { + Nodes.MethodType { params; ret_type=ret; is_mut=false } + } + | EXCL LPAREN params=separated_list(COMMA, type_expr) RPAREN THICK_ARROW ret=type_expr { + Nodes.MethodType { params; ret_type=ret; is_mut=true } + } expr: + | e1=expr PLUS e2=expr { Nodes.Operator { left=e1; right=e2; operator="+" } } + | e1=expr MINUS e2=expr { Nodes.Operator { left=e1; right=e2; operator="-" } } + | e1=expr STAR e2=expr { Nodes.Operator { left=e1; right=e2; operator="*" } } + | e1=expr SLASH e2=expr { Nodes.Operator { left=e1; right=e2; operator="/" } } + | p=primary { p } + +primary: | int=INT { Nodes.IntLiteral int } | float=FLOAT { Nodes.FloatLiteral float } | string=STRING { Nodes.StringLiteral string } | ident=IDENT { Nodes.Ident ident } + | LPAREN e=expr RPAREN { Nodes.Parenthized e } + | callee=primary LPAREN args=separated_list(COMMA, expr) RPAREN { + Nodes.FunctionCall { callee; args } + } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 4102d627..e9f3cc69 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -1,5 +1,5 @@ let rec type_to_node = function - | Nodes.Simple s -> Tree_graph.Leaf s + | Nodes.SimpleType s -> Tree_graph.Leaf s | Nodes.FunctionType { params; ret_type } -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ ("param", Tree_graph.Sequence (List.map type_to_node params)); @@ -28,6 +28,18 @@ and expr_to_node (x: Nodes.expr) = match x with title = "Parenthized"; body = expr_to_node x } + | Nodes.FunctionCall x -> function_call_to_node x + +and function_call_to_node x = + Tree_graph.Group { + title = "function_call"; + body = Tree_graph.Fields ( + Tree_graph.StringMap.of_list [ + ("callee", expr_to_node x.callee); + ("arg", Tree_graph.Sequence (List.map expr_to_node x.args)); + ] + ) + } and param_to_node (x: Nodes.param) = Tree_graph.Fields (Tree_graph.StringMap.of_list [ @@ -39,16 +51,7 @@ and params_to_node (x: Nodes.param list) = Tree_graph.Sequence (List.map param_to_node x) and statement_to_node (x: Nodes.statement) = match x with - | Nodes.FunctionCall x -> - Tree_graph.Group { - title = "function_call"; - body = Tree_graph.Fields ( - Tree_graph.StringMap.of_list [ - ("callee", expr_to_node x.callee); - ("arg", Tree_graph.Sequence (List.map expr_to_node x.args)); - ] - ) - } + | Nodes.ExprStatement x -> expr_to_node x and body_to_node (x: Nodes.body) = match x with | Nodes.Scope scope -> From 19d62edd40499108c3407368a33f3e009b979d6b Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 4 Jun 2026 23:41:30 +0200 Subject: [PATCH 089/154] shorten names --- lib/cst/nodes.ml | 24 ++++++++++++------------ lib/cst/parser.mly | 30 +++++++++++++++--------------- lib/cst/to_tree_graph.ml | 20 ++++++++++---------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index c31df4aa..573e2ac7 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -1,37 +1,37 @@ (* The CST's job is to represent what was parsed, not what's valid. *) type expr = - | IntLiteral of string - | FloatLiteral of string - | StringLiteral of string + | IntLit of string + | FloatLit of string + | StrLit of string | Ident of string - | Operator of { left: expr; right: expr; operator: string } + | Op of { left: expr; right: expr; operator: string } | Parenthized of expr - | FunctionCall of function_call + | FuncCall of func_call -and function_call = { +and func_call = { callee: expr; args: expr list } type type_expr = | SimpleType of string - | FunctionType of { params: type_expr list; ret_type: type_expr } - | MethodType of { params: type_expr list; ret_type: type_expr; is_mut: bool } + | FuncType of { params: type_expr list; ret_type: type_expr } + | MethType of { params: type_expr list; ret_type: type_expr; is_mut: bool } type param = { name: string; type_: type_expr } -type statement = - | ExprStatement of expr +type stat = + | ExprStat of expr type body = - | Scope of statement list + | Scope of stat list type decl = - | FunctionDecl of { name: string; params: param list; ret_type: type_expr; body: body } + | FuncDecl of { name: string; params: param list; ret_type: type_expr; body: body } type package = { decls: decl list diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 0f3c5e4b..f768d709 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -38,18 +38,18 @@ package: decl: | name=IDENT LPAREN params=separated_list(COMMA, param) RPAREN - ret_type=type_expr body=function_body { - Nodes.FunctionDecl { name; params; ret_type; body } + ret_type=type_expr body=func_body { + Nodes.FuncDecl { name; params; ret_type; body } } -function_body: +func_body: | LCURLY statements=list(statement) RCURLY { Nodes.Scope statements } statement: | expr=expr - { Nodes.ExprStatement expr } + { Nodes.ExprStat expr } param: | name=IDENT type_=type_expr { { Nodes.name; type_ } } @@ -57,28 +57,28 @@ param: type_expr: | name=IDENT { Nodes.SimpleType name } | LPAREN params=separated_list(COMMA, type_expr) RPAREN THIN_ARROW ret=type_expr { - Nodes.FunctionType { params; ret_type=ret } + Nodes.FuncType { params; ret_type=ret } } | LPAREN params=separated_list(COMMA, type_expr) RPAREN THICK_ARROW ret=type_expr { - Nodes.MethodType { params; ret_type=ret; is_mut=false } + Nodes.MethType { params; ret_type=ret; is_mut=false } } | EXCL LPAREN params=separated_list(COMMA, type_expr) RPAREN THICK_ARROW ret=type_expr { - Nodes.MethodType { params; ret_type=ret; is_mut=true } + Nodes.MethType { params; ret_type=ret; is_mut=true } } expr: - | e1=expr PLUS e2=expr { Nodes.Operator { left=e1; right=e2; operator="+" } } - | e1=expr MINUS e2=expr { Nodes.Operator { left=e1; right=e2; operator="-" } } - | e1=expr STAR e2=expr { Nodes.Operator { left=e1; right=e2; operator="*" } } - | e1=expr SLASH e2=expr { Nodes.Operator { left=e1; right=e2; operator="/" } } + | e1=expr PLUS e2=expr { Nodes.Op { left=e1; right=e2; operator="+" } } + | e1=expr MINUS e2=expr { Nodes.Op { left=e1; right=e2; operator="-" } } + | e1=expr STAR e2=expr { Nodes.Op { left=e1; right=e2; operator="*" } } + | e1=expr SLASH e2=expr { Nodes.Op { left=e1; right=e2; operator="/" } } | p=primary { p } primary: - | int=INT { Nodes.IntLiteral int } - | float=FLOAT { Nodes.FloatLiteral float } - | string=STRING { Nodes.StringLiteral string } + | int=INT { Nodes.IntLit int } + | float=FLOAT { Nodes.FloatLit float } + | string=STRING { Nodes.StrLit string } | ident=IDENT { Nodes.Ident ident } | LPAREN e=expr RPAREN { Nodes.Parenthized e } | callee=primary LPAREN args=separated_list(COMMA, expr) RPAREN { - Nodes.FunctionCall { callee; args } + Nodes.FuncCall { callee; args } } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index e9f3cc69..932775a7 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -1,11 +1,11 @@ let rec type_to_node = function | Nodes.SimpleType s -> Tree_graph.Leaf s - | Nodes.FunctionType { params; ret_type } -> + | Nodes.FuncType { params; ret_type } -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ ("param", Tree_graph.Sequence (List.map type_to_node params)); ("type", type_to_node ret_type); ]) - | Nodes.MethodType { params; ret_type; is_mut } -> + | Nodes.MethType { params; ret_type; is_mut } -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ ("param", Tree_graph.Sequence (List.map type_to_node params)); ("type", type_to_node ret_type); @@ -13,11 +13,11 @@ let rec type_to_node = function ]) and expr_to_node (x: Nodes.expr) = match x with - | Nodes.IntLiteral x -> Tree_graph.Leaf x - | Nodes.FloatLiteral x -> Tree_graph.Leaf x - | Nodes.StringLiteral x -> Tree_graph.Leaf x + | Nodes.IntLit x -> Tree_graph.Leaf x + | Nodes.FloatLit x -> Tree_graph.Leaf x + | Nodes.StrLit x -> Tree_graph.Leaf x | Nodes.Ident x -> Tree_graph.Leaf x - | Nodes.Operator x -> + | Nodes.Op x -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ ("left", expr_to_node x.left); ("right", expr_to_node x.right); @@ -28,7 +28,7 @@ and expr_to_node (x: Nodes.expr) = match x with title = "Parenthized"; body = expr_to_node x } - | Nodes.FunctionCall x -> function_call_to_node x + | Nodes.FuncCall x -> function_call_to_node x and function_call_to_node x = Tree_graph.Group { @@ -50,8 +50,8 @@ and param_to_node (x: Nodes.param) = and params_to_node (x: Nodes.param list) = Tree_graph.Sequence (List.map param_to_node x) -and statement_to_node (x: Nodes.statement) = match x with - | Nodes.ExprStatement x -> expr_to_node x +and statement_to_node (x: Nodes.stat) = match x with + | Nodes.ExprStat x -> expr_to_node x and body_to_node (x: Nodes.body) = match x with | Nodes.Scope scope -> @@ -64,7 +64,7 @@ and body_to_node (x: Nodes.body) = match x with } and decl_to_node = function - | Nodes.FunctionDecl { name; params; ret_type; body } -> + | Nodes.FuncDecl { name; params; ret_type; body } -> Tree_graph.Group { title = "function_decl"; body = Tree_graph.Fields ( From 2a59f17a54e4d8619ca3b15fb7c6ef7dfcc0aad6 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 5 Jun 2026 00:04:37 +0200 Subject: [PATCH 090/154] use new formatting style --- lib/cst/cst.ml | 4 ++-- lib/cst/nodes.ml | 12 ++++++------ lib/cst/to_tree_graph.ml | 30 +++++++++++++++--------------- lib/tree_graph/render.ml | 30 +++++++++++++++--------------- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/lib/cst/cst.ml b/lib/cst/cst.ml index 6deca1ba..a9e626ae 100644 --- a/lib/cst/cst.ml +++ b/lib/cst/cst.ml @@ -8,8 +8,8 @@ let parse input = let tokenizer = Sedlexing.with_tokenizer Lexer.token lexbuf in try MenhirLib.Convert.Simplified.traditional2revised Parser.package tokenizer - with Parser.Error -> - let (pos, _) = Sedlexing.lexing_positions lexbuf in + with Parser.Error + -> let (pos, _) = Sedlexing.lexing_positions lexbuf in Printf.printf "Parse error at line %d, column %d\n" pos.Lexing.pos_lnum (pos.Lexing.pos_cnum - pos.Lexing.pos_bol); diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 573e2ac7..f9fb66f7 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -1,13 +1,13 @@ (* The CST's job is to represent what was parsed, not what's valid. *) type expr = - | IntLit of string - | FloatLit of string - | StrLit of string - | Ident of string - | Op of { left: expr; right: expr; operator: string } + | IntLit of string + | FloatLit of string + | StrLit of string + | Ident of string + | Op of { left: expr; right: expr; operator: string } | Parenthized of expr - | FuncCall of func_call + | FuncCall of func_call and func_call = { callee: expr; diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 932775a7..d04a21e8 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -1,30 +1,30 @@ let rec type_to_node = function | Nodes.SimpleType s -> Tree_graph.Leaf s - | Nodes.FuncType { params; ret_type } -> - Tree_graph.Fields (Tree_graph.StringMap.of_list [ + | Nodes.FuncType { params; ret_type } + -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ ("param", Tree_graph.Sequence (List.map type_to_node params)); ("type", type_to_node ret_type); ]) - | Nodes.MethType { params; ret_type; is_mut } -> - Tree_graph.Fields (Tree_graph.StringMap.of_list [ + | Nodes.MethType { params; ret_type; is_mut } + -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ ("param", Tree_graph.Sequence (List.map type_to_node params)); ("type", type_to_node ret_type); ("is_mut", Tree_graph.Leaf (string_of_bool is_mut)); ]) and expr_to_node (x: Nodes.expr) = match x with - | Nodes.IntLit x -> Tree_graph.Leaf x + | Nodes.IntLit x -> Tree_graph.Leaf x | Nodes.FloatLit x -> Tree_graph.Leaf x - | Nodes.StrLit x -> Tree_graph.Leaf x - | Nodes.Ident x -> Tree_graph.Leaf x - | Nodes.Op x -> - Tree_graph.Fields (Tree_graph.StringMap.of_list [ + | Nodes.StrLit x -> Tree_graph.Leaf x + | Nodes.Ident x -> Tree_graph.Leaf x + | Nodes.Op x + -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ ("left", expr_to_node x.left); ("right", expr_to_node x.right); ("op", Tree_graph.Leaf x.operator); ]) - | Nodes.Parenthized x -> - Tree_graph.Group { + | Nodes.Parenthized x + -> Tree_graph.Group { title = "Parenthized"; body = expr_to_node x } @@ -54,8 +54,8 @@ and statement_to_node (x: Nodes.stat) = match x with | Nodes.ExprStat x -> expr_to_node x and body_to_node (x: Nodes.body) = match x with - | Nodes.Scope scope -> - Tree_graph.Group { + | Nodes.Scope scope + -> Tree_graph.Group { title = "scope"; body = Tree_graph.Group { title = "statement"; @@ -64,8 +64,8 @@ and body_to_node (x: Nodes.body) = match x with } and decl_to_node = function - | Nodes.FuncDecl { name; params; ret_type; body } -> - Tree_graph.Group { + | Nodes.FuncDecl { name; params; ret_type; body } + -> Tree_graph.Group { title = "function_decl"; body = Tree_graph.Fields ( Tree_graph.StringMap.of_list [ diff --git a/lib/tree_graph/render.ml b/lib/tree_graph/render.ml index d6fbff32..fa73ec60 100644 --- a/lib/tree_graph/render.ml +++ b/lib/tree_graph/render.ml @@ -4,28 +4,28 @@ type item = let rec collect ~name node = match node with - | Node.Leaf v -> - [ILeaf (name, v)] - - | Node.Group { title; body } -> - let new_name = if name = "" then title else name ^ " > " ^ title in + | Node.Leaf v + -> [ILeaf (name, v)] + + | Node.Group { title; body } + -> let new_name = if name = "" then title else name ^ " > " ^ title in collect ~name:new_name body - - | Node.Fields map -> - let nested_items = + + | Node.Fields map + -> let nested_items = Node.StringMap.bindings map |> List.map (fun (k, v) -> collect ~name:k v) |> List.flatten in if name = "" then nested_items else [IContainer (name, nested_items)] - - | Node.Sequence list -> - if list = [] then + + | Node.Sequence list + -> if list = [] then if name = "" then [] else [IContainer (name, [])] else - List.mapi (fun i v -> - let element_name = + List.mapi (fun i v + -> let element_name = if name = "" then Printf.sprintf "[%d]" i else Printf.sprintf "%s[%d]" name i in @@ -36,8 +36,8 @@ let render root_node = let items = collect ~name:"" root_node in let rec print_items prefix items = let len = List.length items in - List.iteri (fun i item -> - let is_last = (i = len - 1) in + List.iteri (fun i item + -> let is_last = (i = len - 1) in let branch = if is_last then "└── " else "├── " in let nested_prefix = prefix ^ (if is_last then " " else "│ ") in match item with From 86d8b52bcaf60905cc8717c8506164972956f429 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 5 Jun 2026 10:06:06 +0200 Subject: [PATCH 091/154] update --- lib/cst/nodes.ml | 2 +- lib/cst/parser.mly | 15 ++++++++------- lib/cst/to_tree_graph.ml | 8 ++++---- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index f9fb66f7..c779211e 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -25,7 +25,7 @@ type param = { } type stat = - | ExprStat of expr + | FuncCallStat of func_call type body = | Scope of stat list diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index f768d709..8a06b167 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -48,8 +48,9 @@ func_body: } statement: - | expr=expr - { Nodes.ExprStat expr } + | callee=expr LPAREN args=separated_list(COMMA, expr) RPAREN { + Nodes.FuncCallStat { callee; args } + } param: | name=IDENT type_=type_expr { { Nodes.name; type_ } } @@ -67,18 +68,18 @@ type_expr: } expr: + | p=primary { p } | e1=expr PLUS e2=expr { Nodes.Op { left=e1; right=e2; operator="+" } } | e1=expr MINUS e2=expr { Nodes.Op { left=e1; right=e2; operator="-" } } | e1=expr STAR e2=expr { Nodes.Op { left=e1; right=e2; operator="*" } } | e1=expr SLASH e2=expr { Nodes.Op { left=e1; right=e2; operator="/" } } - | p=primary { p } + | LPAREN e=expr RPAREN { Nodes.Parenthized e } + | callee=expr LPAREN args=separated_list(COMMA, expr) RPAREN { + Nodes.FuncCall { callee; args } + } primary: | int=INT { Nodes.IntLit int } | float=FLOAT { Nodes.FloatLit float } | string=STRING { Nodes.StrLit string } | ident=IDENT { Nodes.Ident ident } - | LPAREN e=expr RPAREN { Nodes.Parenthized e } - | callee=primary LPAREN args=separated_list(COMMA, expr) RPAREN { - Nodes.FuncCall { callee; args } - } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index d04a21e8..867a3e4f 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -28,9 +28,9 @@ and expr_to_node (x: Nodes.expr) = match x with title = "Parenthized"; body = expr_to_node x } - | Nodes.FuncCall x -> function_call_to_node x + | Nodes.FuncCall x -> func_call_to_node x -and function_call_to_node x = +and func_call_to_node x = Tree_graph.Group { title = "function_call"; body = Tree_graph.Fields ( @@ -51,7 +51,7 @@ and params_to_node (x: Nodes.param list) = Tree_graph.Sequence (List.map param_to_node x) and statement_to_node (x: Nodes.stat) = match x with - | Nodes.ExprStat x -> expr_to_node x + | Nodes.FuncCallStat x -> func_call_to_node x and body_to_node (x: Nodes.body) = match x with | Nodes.Scope scope @@ -66,7 +66,7 @@ and body_to_node (x: Nodes.body) = match x with and decl_to_node = function | Nodes.FuncDecl { name; params; ret_type; body } -> Tree_graph.Group { - title = "function_decl"; + title = "func_decl"; body = Tree_graph.Fields ( Tree_graph.StringMap.of_list [ ("param", params_to_node params); From 51e86693556777d416eb58b0cf27e64a91342d31 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 5 Jun 2026 10:41:08 +0200 Subject: [PATCH 092/154] nice parse error --- bin/compiler/main.ml | 2 +- lib/cst/cst.ml | 11 ++++----- lib/cst/nodes.ml | 2 ++ lib/cst/parse_error.ml | 50 ++++++++++++++++++++++++++++++++++++++++ lib/cst/parser.mly | 20 ++++++++++------ lib/cst/to_tree_graph.ml | 22 ++++++++++++++++++ test-parser/main.zn | 4 +++- 7 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 lib/cst/parse_error.ml diff --git a/bin/compiler/main.ml b/bin/compiler/main.ml index ab2827da..699c8c6f 100644 --- a/bin/compiler/main.ml +++ b/bin/compiler/main.ml @@ -3,6 +3,6 @@ let read_file path = let () = let input = read_file "test-parser/main.zn" in - let cst = Cst.parse input in + let cst = Cst.parse "test-parser/main,zn" input in let output = Cst.to_node cst in Tree_graph.render output diff --git a/lib/cst/cst.ml b/lib/cst/cst.ml index a9e626ae..0c99212b 100644 --- a/lib/cst/cst.ml +++ b/lib/cst/cst.ml @@ -3,14 +3,11 @@ module Parser = Parser module Lexer = Lexer include To_tree_graph -let parse input = +let parse filename input = let lexbuf = Sedlexing.Utf8.from_string input in let tokenizer = Sedlexing.with_tokenizer Lexer.token lexbuf in try MenhirLib.Convert.Simplified.traditional2revised Parser.package tokenizer - with Parser.Error - -> let (pos, _) = Sedlexing.lexing_positions lexbuf in - Printf.printf "Parse error at line %d, column %d\n" - pos.Lexing.pos_lnum - (pos.Lexing.pos_cnum - pos.Lexing.pos_bol); - raise Parser.Error + with Parser.Error -> + let (pos_start, pos_end) = Sedlexing.lexing_positions lexbuf in + Parse_error.print_parse_error filename input pos_start pos_end diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index c779211e..576e20a7 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -32,6 +32,8 @@ type body = type decl = | FuncDecl of { name: string; params: param list; ret_type: type_expr; body: body } + | VarDecl of { name: string; type_: type_expr; value: expr } + | ConstructorDecl of { name: string; type_: type_expr; args: expr list } type package = { decls: decl list diff --git a/lib/cst/parse_error.ml b/lib/cst/parse_error.ml new file mode 100644 index 00000000..3de7a2a3 --- /dev/null +++ b/lib/cst/parse_error.ml @@ -0,0 +1,50 @@ +let tab_width = 4 + +let visual_col_of_idx s idx = + let rec aux i vcol = + if i >= idx then vcol + else + let c = s.[i] in + let step = if c = '\t' then tab_width - (vcol mod tab_width) else 1 in + aux (i + 1) (vcol + step) + in + aux 0 0 + +let expand_tabs s = + let buf = Buffer.create (String.length s + 10) in + let rec aux i vcol = + if i >= String.length s then Buffer.contents buf + else + let c = s.[i] in + if c = '\t' then + let spaces = tab_width - (vcol mod tab_width) in + let () = Buffer.add_string buf (String.make spaces ' ') in + aux (i + 1) (vcol + spaces) + else + let () = Buffer.add_char buf c in + aux (i + 1) (vcol + 1) + in + aux 0 0 + +let print_parse_error filename input pos_start pos_end = + let line = pos_start.Lexing.pos_lnum in + let char_start = pos_start.Lexing.pos_cnum - pos_start.Lexing.pos_bol in + let char_end = pos_end.Lexing.pos_cnum - pos_start.Lexing.pos_bol in + let lines = String.split_on_char '\n' input in + let source_line = + match List.nth_opt lines (line - 1) with + | Some l -> + let len = String.length l in + if len > 0 && l.[len - 1] = '\r' then String.sub l 0 (len - 1) else l + | None -> "" + in + + let vcol_start = visual_col_of_idx source_line char_start in + let vcol_end = visual_col_of_idx source_line char_end in + let visual_source_line = expand_tabs source_line in + + let () = Printf.eprintf "File \"%s\", line %d, characters %d-%d:\n" filename line (vcol_start + 1) (vcol_end + 1) in + let () = Printf.eprintf "%d | %s\n" line visual_source_line in + let () = Printf.eprintf " | %s%s\n" (String.make vcol_start ' ') (String.make (max 1 (vcol_end - vcol_start)) '^') in + let () = Printf.eprintf "Error: Parse error\n" in + exit 1 diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 8a06b167..0dab808f 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -37,10 +37,16 @@ package: | decls=list(decl) EOF { { Nodes.decls = decls } } decl: - | name=IDENT LPAREN params=separated_list(COMMA, param) RPAREN + | name=IDENT "(" params=separated_list(COMMA, param) ")" ret_type=type_expr body=func_body { Nodes.FuncDecl { name; params; ret_type; body } } + | name=IDENT type_=type_expr "=" value=expr { + Nodes.VarDecl { name; type_; value } + } + | name=IDENT type_=type_expr "(" args=separated_list(COMMA, expr) ")" { + Nodes.ConstructorDecl { name; type_; args } + } func_body: | LCURLY statements=list(statement) RCURLY { @@ -48,7 +54,7 @@ func_body: } statement: - | callee=expr LPAREN args=separated_list(COMMA, expr) RPAREN { + | callee=expr "(" args=separated_list(COMMA, expr) ")" { Nodes.FuncCallStat { callee; args } } @@ -57,13 +63,13 @@ param: type_expr: | name=IDENT { Nodes.SimpleType name } - | LPAREN params=separated_list(COMMA, type_expr) RPAREN THIN_ARROW ret=type_expr { + | "(" params=separated_list(COMMA, type_expr) ")" THIN_ARROW ret=type_expr { Nodes.FuncType { params; ret_type=ret } } - | LPAREN params=separated_list(COMMA, type_expr) RPAREN THICK_ARROW ret=type_expr { + | "(" THIS params=separated_list(COMMA, type_expr) ")" THIN_ARROW ret=type_expr { Nodes.MethType { params; ret_type=ret; is_mut=false } } - | EXCL LPAREN params=separated_list(COMMA, type_expr) RPAREN THICK_ARROW ret=type_expr { + | "(" THIS params=separated_list(COMMA, type_expr) ")" "!" THIN_ARROW ret=type_expr { Nodes.MethType { params; ret_type=ret; is_mut=true } } @@ -73,8 +79,8 @@ expr: | e1=expr MINUS e2=expr { Nodes.Op { left=e1; right=e2; operator="-" } } | e1=expr STAR e2=expr { Nodes.Op { left=e1; right=e2; operator="*" } } | e1=expr SLASH e2=expr { Nodes.Op { left=e1; right=e2; operator="/" } } - | LPAREN e=expr RPAREN { Nodes.Parenthized e } - | callee=expr LPAREN args=separated_list(COMMA, expr) RPAREN { + | "(" e=expr ")" { Nodes.Parenthized e } + | callee=expr "(" args=separated_list(COMMA, expr) ")" { Nodes.FuncCall { callee; args } } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 867a3e4f..9c794786 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -75,6 +75,28 @@ and decl_to_node = function ] ) } + | Nodes.VarDecl { name; type_; value } + -> Tree_graph.Group { + title = "var_decl"; + body = Tree_graph.Fields ( + Tree_graph.StringMap.of_list [ + ("name", Tree_graph.Leaf name); + ("type", type_to_node type_); + ("value", expr_to_node value); + ] + ) + } + | Nodes.ConstructorDecl { name; type_; args } + -> Tree_graph.Group { + title = "var_decl"; + body = Tree_graph.Fields ( + Tree_graph.StringMap.of_list [ + ("name", Tree_graph.Leaf name); + ("type", type_to_node type_); + ("args", Tree_graph.Sequence (List.map expr_to_node args)); + ] + ) + } let to_node ({ Nodes.decls }: Nodes.package) = Tree_graph.Group { title = "package"; body = Tree_graph.Fields (Tree_graph.StringMap.of_list [ diff --git a/test-parser/main.zn b/test-parser/main.zn index 2bf8bf09..257911db 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,4 +1,6 @@ main (hi Int, a Bool) Void { - print("hi") + x String = "hello" + y String = "world" + print(x, y) log("bug") } From e1b3080d9d471d8a5b65662aa39b124a03adb3f5 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 5 Jun 2026 21:10:33 +0200 Subject: [PATCH 093/154] update --- justfile | 8 +++++++ lib/cst/cst.ml | 2 +- lib/cst/dune | 13 ++++++++-- lib/cst/nodes.ml | 5 ++-- lib/cst/parser.mly | 51 +++++++++++++++++++++++----------------- lib/cst/to_tree_graph.ml | 1 + test-parser/main.zn | 4 ++-- 7 files changed, 56 insertions(+), 28 deletions(-) diff --git a/justfile b/justfile index 5e4c606a..de805efd 100644 --- a/justfile +++ b/justfile @@ -1,3 +1,5 @@ +grammarFile := "lib/cst/parser.mly" + default: just -l @@ -10,3 +12,9 @@ rebuild: watch: dune build --watch + +stats: + menhir {{ grammarFile }} --no-code-generation --infer + +conflicts: + menhir {{ grammarFile }} --random-sentence-concrete package --random-seed 1 --random-sentence-length 16 diff --git a/lib/cst/cst.ml b/lib/cst/cst.ml index 0c99212b..1384f3d7 100644 --- a/lib/cst/cst.ml +++ b/lib/cst/cst.ml @@ -8,6 +8,6 @@ let parse filename input = let tokenizer = Sedlexing.with_tokenizer Lexer.token lexbuf in try MenhirLib.Convert.Simplified.traditional2revised Parser.package tokenizer - with Parser.Error -> + with Parser.Error tokenizer -> let (pos_start, pos_end) = Sedlexing.lexing_positions lexbuf in Parse_error.print_parse_error filename input pos_start pos_end diff --git a/lib/cst/dune b/lib/cst/dune index cd0a1848..5223e60b 100644 --- a/lib/cst/dune +++ b/lib/cst/dune @@ -1,7 +1,16 @@ (library (name cst) - (libraries menhirLib sedlex tree_graph) + (libraries + menhirLib + sedlex + tree_graph + menhirGLR + ) (preprocess (pps sedlex.ppx))) (menhir - (modules parser)) + (modules parser) + (infer true) + + (flags --GLR) +) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 576e20a7..87f28798 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -26,11 +26,12 @@ type param = { type stat = | FuncCallStat of func_call + | DeclStat of decl -type body = +and body = | Scope of stat list -type decl = +and decl = | FuncDecl of { name: string; params: param list; ret_type: type_expr; body: body } | VarDecl of { name: string; type_: type_expr; value: expr } | ConstructorDecl of { name: string; type_: type_expr; args: expr list } diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 0dab808f..76c8fdd8 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -1,13 +1,17 @@ (*****************************) (* token definitions *) (*****************************) -%token INT FLOAT STRING IDENT +%token INT "43" +%token FLOAT "8.647" +%token STRING "\"john\"" +%token IDENT "foo" + %token LPAREN "(" %token RPAREN ")" %token COMMA "," %token LCURLY "{" %token RCURLY "}" -%token COLON ":" +%token COLON %token EQUAL "=" %token PLUS "+" %token MINUS "-" @@ -19,10 +23,11 @@ %token TILDE "~" %token THIN_ARROW "->" %token THICK_ARROW "=>" -%token THIS -%token ERROR -%token EOF +%token THIS "this" +%token ERROR "" +%token EOF "" +%left LPAREN %left PLUS MINUS %left STAR SLASH @@ -37,27 +42,34 @@ package: | decls=list(decl) EOF { { Nodes.decls = decls } } decl: - | name=IDENT "(" params=separated_list(COMMA, param) ")" - ret_type=type_expr body=func_body { - Nodes.FuncDecl { name; params; ret_type; body } - } | name=IDENT type_=type_expr "=" value=expr { Nodes.VarDecl { name; type_; value } } | name=IDENT type_=type_expr "(" args=separated_list(COMMA, expr) ")" { Nodes.ConstructorDecl { name; type_; args } } + | name=IDENT "(" params=separated_list(COMMA, param) ")" + ret_type=type_expr body=func_body { + Nodes.FuncDecl { name; params; ret_type; body } + } func_body: - | LCURLY statements=list(statement) RCURLY { + | LCURLY statements=list(stat) RCURLY { Nodes.Scope statements } -statement: +func_call: | callee=expr "(" args=separated_list(COMMA, expr) ")" { - Nodes.FuncCallStat { callee; args } + { callee=callee; args=args } + } + +stat: + | decl=decl { Nodes.DeclStat decl } + | func_call=func_call { + Nodes.FuncCallStat func_call } + param: | name=IDENT type_=type_expr { { Nodes.name; type_ } } @@ -74,18 +86,15 @@ type_expr: } expr: - | p=primary { p } + | int=INT { Nodes.IntLit int } + | float=FLOAT { Nodes.FloatLit float } + | string=STRING { Nodes.StrLit string } + | ident=IDENT { Nodes.Ident ident } | e1=expr PLUS e2=expr { Nodes.Op { left=e1; right=e2; operator="+" } } | e1=expr MINUS e2=expr { Nodes.Op { left=e1; right=e2; operator="-" } } | e1=expr STAR e2=expr { Nodes.Op { left=e1; right=e2; operator="*" } } | e1=expr SLASH e2=expr { Nodes.Op { left=e1; right=e2; operator="/" } } | "(" e=expr ")" { Nodes.Parenthized e } - | callee=expr "(" args=separated_list(COMMA, expr) ")" { - Nodes.FuncCall { callee; args } + | func_call=func_call { + Nodes.FuncCall func_call } - -primary: - | int=INT { Nodes.IntLit int } - | float=FLOAT { Nodes.FloatLit float } - | string=STRING { Nodes.StrLit string } - | ident=IDENT { Nodes.Ident ident } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 9c794786..c1996ebb 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -52,6 +52,7 @@ and params_to_node (x: Nodes.param list) = and statement_to_node (x: Nodes.stat) = match x with | Nodes.FuncCallStat x -> func_call_to_node x + | Nodes.DeclStat x -> decl_to_node x and body_to_node (x: Nodes.body) = match x with | Nodes.Scope scope diff --git a/test-parser/main.zn b/test-parser/main.zn index 257911db..c0c2c573 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,6 +1,6 @@ main (hi Int, a Bool) Void { x String = "hello" y String = "world" - print(x, y) - log("bug") + print (x, y) + log ("bug") } From 7010b76f838148917ec263a83056ea6d9a13df2c Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 5 Jun 2026 21:20:49 +0200 Subject: [PATCH 094/154] update func type syntax --- functionSyntax.txt | 3 --- lib/cst/lexer.ml | 2 ++ lib/cst/parser.mly | 8 +++++--- notes.md | 2 -- syntax.txt | 7 +++++++ test-parser/main.zn | 6 +++--- 6 files changed, 17 insertions(+), 11 deletions(-) delete mode 100644 functionSyntax.txt create mode 100644 syntax.txt diff --git a/functionSyntax.txt b/functionSyntax.txt deleted file mode 100644 index d5bc8603..00000000 --- a/functionSyntax.txt +++ /dev/null @@ -1,3 +0,0 @@ -main (this Int, a Bool)! Void { - print(2, 2) -} diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index eadd72cf..1bcdbf5e 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -21,6 +21,8 @@ let rec token buf = | ')' -> RPAREN | '{' -> LCURLY | '}' -> RCURLY + | '[' -> LBRACKET + | ']' -> RBRACKET | ',' -> COMMA | ':' -> COLON | '!' -> EXCL diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 76c8fdd8..55743e43 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -11,6 +11,8 @@ %token COMMA "," %token LCURLY "{" %token RCURLY "}" +%token LBRACKET "[" +%token RBRACKET "]" %token COLON %token EQUAL "=" %token PLUS "+" @@ -75,13 +77,13 @@ param: type_expr: | name=IDENT { Nodes.SimpleType name } - | "(" params=separated_list(COMMA, type_expr) ")" THIN_ARROW ret=type_expr { + | "[" params=separated_list(COMMA, type_expr) "]" THIN_ARROW ret=type_expr { Nodes.FuncType { params; ret_type=ret } } - | "(" THIS params=separated_list(COMMA, type_expr) ")" THIN_ARROW ret=type_expr { + | "[" THIS params=separated_list(COMMA, type_expr) "]" THIN_ARROW ret=type_expr { Nodes.MethType { params; ret_type=ret; is_mut=false } } - | "(" THIS params=separated_list(COMMA, type_expr) ")" "!" THIN_ARROW ret=type_expr { + | "[" THIS params=separated_list(COMMA, type_expr) "]" "!" THIN_ARROW ret=type_expr { Nodes.MethType { params; ret_type=ret; is_mut=true } } diff --git a/notes.md b/notes.md index f2d76684..25b5f2fd 100644 --- a/notes.md +++ b/notes.md @@ -7,5 +7,3 @@ get to state after issue `sudo apt install libc++-21-dev libc++abi-21-dev` should be fixed on the commit where notes.md is added - -execution bottom to top? diff --git a/syntax.txt b/syntax.txt new file mode 100644 index 00000000..90ad1214 --- /dev/null +++ b/syntax.txt @@ -0,0 +1,7 @@ +main (this Int, a Bool)! Void { + print(2, 2) +} + +new function type syntax: + +varName [this Player, Weapon]! -> Void diff --git a/test-parser/main.zn b/test-parser/main.zn index c0c2c573..337b02e7 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,6 +1,6 @@ main (hi Int, a Bool) Void { - x String = "hello" + x [this Int]! -> Void = "hello" y String = "world" - print (x, y) - log ("bug") + print(x, y) + log("bug") } From f0f58803a05493a028fec6131134a9a7b3986dce Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 5 Jun 2026 21:38:27 +0200 Subject: [PATCH 095/154] add method decl --- lib/cst/nodes.ml | 1 + lib/cst/parser.mly | 14 +++++++++++++- lib/cst/to_tree_graph.ml | 14 +++++++++++++- test-parser/main.zn | 2 +- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 87f28798..5efd0494 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -33,6 +33,7 @@ and body = and decl = | FuncDecl of { name: string; params: param list; ret_type: type_expr; body: body } + | MethDecl of { name: string; params: param list; ret_type: type_expr; is_mut: bool ; body: body } | VarDecl of { name: string; type_: type_expr; value: expr } | ConstructorDecl of { name: string; type_: type_expr; args: expr list } diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 55743e43..4546912c 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -41,7 +41,7 @@ %% package: - | decls=list(decl) EOF { { Nodes.decls = decls } } + | decls=list(decl) EOF { { Nodes.decls=decls } } decl: | name=IDENT type_=type_expr "=" value=expr { @@ -54,6 +54,18 @@ decl: ret_type=type_expr body=func_body { Nodes.FuncDecl { name; params; ret_type; body } } + | name=IDENT "(" meth_params=meth_params ")" + ret_type=type_expr body=func_body { + Nodes.MethDecl { name; params=meth_params; ret_type; body; is_mut=false } + } + | name=IDENT "(" meth_params=meth_params ")" "!" + ret_type=type_expr body=func_body { + Nodes.MethDecl { name; params=meth_params; ret_type; body; is_mut=true } + } + +meth_params: + | THIS; t=type_expr; rest=loption(preceded(COMMA, separated_nonempty_list(COMMA, param))) + { { Nodes.name="this"; type_=t } :: rest } func_body: | LCURLY statements=list(stat) RCURLY { diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index c1996ebb..ab549443 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -76,6 +76,18 @@ and decl_to_node = function ] ) } + | Nodes.MethDecl { name; params; ret_type; body; is_mut } + -> Tree_graph.Group { + title = "method_decl"; + body = Tree_graph.Fields ( + Tree_graph.StringMap.of_list [ + ("param", params_to_node params); + ("ret_type", type_to_node ret_type); + ("body", body_to_node body); + ("is_mut ", Tree_graph.Leaf (string_of_bool is_mut)); + ] + ) + } | Nodes.VarDecl { name; type_; value } -> Tree_graph.Group { title = "var_decl"; @@ -89,7 +101,7 @@ and decl_to_node = function } | Nodes.ConstructorDecl { name; type_; args } -> Tree_graph.Group { - title = "var_decl"; + title = "constructor_decl"; body = Tree_graph.Fields ( Tree_graph.StringMap.of_list [ ("name", Tree_graph.Leaf name); diff --git a/test-parser/main.zn b/test-parser/main.zn index 337b02e7..b6bf0af3 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,4 +1,4 @@ -main (hi Int, a Bool) Void { +main (this Int, a Bool) Void { x [this Int]! -> Void = "hello" y String = "world" print(x, y) From 73164308e94412fbeebe655447cef700a362adee Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 6 Jun 2026 08:56:33 +0200 Subject: [PATCH 096/154] add aborts --- lib/cst/lexer.ml | 1 + lib/cst/nodes.ml | 8 ++++++-- lib/cst/parser.mly | 15 ++++++++++++--- lib/cst/to_tree_graph.ml | 14 ++++++++++++-- test-parser/main.zn | 2 +- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index 1bcdbf5e..69984fbd 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -26,6 +26,7 @@ let rec token buf = | ',' -> COMMA | ':' -> COLON | '!' -> EXCL + | '?' -> QSTNMARK | '~' -> TILDE | '+' -> PLUS | '-' -> MINUS diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 5efd0494..56d0a0ba 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -31,9 +31,13 @@ type stat = and body = | Scope of stat list +and ret_type = + | SafeRet of type_expr + | AbortRet of type_expr * type_expr + and decl = - | FuncDecl of { name: string; params: param list; ret_type: type_expr; body: body } - | MethDecl of { name: string; params: param list; ret_type: type_expr; is_mut: bool ; body: body } + | FuncDecl of { name: string; params: param list; ret_type: ret_type; body: body } + | MethDecl of { name: string; params: param list; ret_type: ret_type; is_mut: bool ; body: body } | VarDecl of { name: string; type_: type_expr; value: expr } | ConstructorDecl of { name: string; type_: type_expr; args: expr list } diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 4546912c..dcd3f911 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -22,6 +22,7 @@ %token DOLLAR "$" %token AT "@" %token EXCL "!" +%token QSTNMARK "?" %token TILDE "~" %token THIN_ARROW "->" %token THICK_ARROW "=>" @@ -51,18 +52,26 @@ decl: Nodes.ConstructorDecl { name; type_; args } } | name=IDENT "(" params=separated_list(COMMA, param) ")" - ret_type=type_expr body=func_body { + ret_type=ret_type body=func_body { Nodes.FuncDecl { name; params; ret_type; body } } | name=IDENT "(" meth_params=meth_params ")" - ret_type=type_expr body=func_body { + ret_type=ret_type body=func_body { Nodes.MethDecl { name; params=meth_params; ret_type; body; is_mut=false } } | name=IDENT "(" meth_params=meth_params ")" "!" - ret_type=type_expr body=func_body { + ret_type=ret_type body=func_body { Nodes.MethDecl { name; params=meth_params; ret_type; body; is_mut=true } } +ret_type: + | ret_type=type_expr { + Nodes.SafeRet ret_type + } + | safe_type=type_expr "?" abort_type=type_expr { + Nodes.AbortRet (safe_type, abort_type) + } + meth_params: | THIS; t=type_expr; rest=loption(preceded(COMMA, separated_nonempty_list(COMMA, param))) { { Nodes.name="this"; type_=t } :: rest } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index ab549443..4da97fb8 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -64,6 +64,16 @@ and body_to_node (x: Nodes.body) = match x with } } +and ret_to_node (x: Nodes.ret_type) = match x with + | Nodes.SafeRet ret -> type_to_node ret + | Nodes.AbortRet (ret_type, abort_type) + -> Tree_graph.Fields ( + Tree_graph.StringMap.of_list [ + ("safe_type", type_to_node abort_type ); + ("abort_type", type_to_node ret_type); + ] + ) + and decl_to_node = function | Nodes.FuncDecl { name; params; ret_type; body } -> Tree_graph.Group { @@ -71,7 +81,7 @@ and decl_to_node = function body = Tree_graph.Fields ( Tree_graph.StringMap.of_list [ ("param", params_to_node params); - ("ret_type", type_to_node ret_type); + ("ret_type", ret_to_node ret_type); ("body", body_to_node body); ] ) @@ -82,7 +92,7 @@ and decl_to_node = function body = Tree_graph.Fields ( Tree_graph.StringMap.of_list [ ("param", params_to_node params); - ("ret_type", type_to_node ret_type); + ("ret_type", ret_to_node ret_type); ("body", body_to_node body); ("is_mut ", Tree_graph.Leaf (string_of_bool is_mut)); ] diff --git a/test-parser/main.zn b/test-parser/main.zn index b6bf0af3..27e0607c 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,4 +1,4 @@ -main (this Int, a Bool) Void { +main (this Int, a Bool)! Void?String { x [this Int]! -> Void = "hello" y String = "world" print(x, y) From 675064c47df3f7703e76755c6737ade2c950b6f1 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 6 Jun 2026 09:11:59 +0200 Subject: [PATCH 097/154] add abort handling --- lib/cst/nodes.ml | 25 ++++++++++++++++++++----- lib/cst/parser.mly | 2 +- lib/cst/to_tree_graph.ml | 21 +++++++++++---------- 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 56d0a0ba..9467309d 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -9,22 +9,37 @@ type expr = | Parenthized of expr | FuncCall of func_call -and func_call = { +and safe_call = { callee: expr; - args: expr list + args: expr list; } -type type_expr = +and abort_handle = + | AbortBody of body + | AbortShorthand of expr + +and abort_call = { + callee: expr; + args: expr list; + handle_block: abort_handle; +} + +and func_call = + | SafeCall of safe_call + (* | AbortCall of abort_call *) + + +and type_expr = | SimpleType of string | FuncType of { params: type_expr list; ret_type: type_expr } | MethType of { params: type_expr list; ret_type: type_expr; is_mut: bool } -type param = { +and param = { name: string; type_: type_expr } -type stat = +and stat = | FuncCallStat of func_call | DeclStat of decl diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index dcd3f911..632c334e 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -83,7 +83,7 @@ func_body: func_call: | callee=expr "(" args=separated_list(COMMA, expr) ")" { - { callee=callee; args=args } + Nodes.SafeCall { callee=callee; args=args } } stat: diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 4da97fb8..49ed8222 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -30,16 +30,17 @@ and expr_to_node (x: Nodes.expr) = match x with } | Nodes.FuncCall x -> func_call_to_node x -and func_call_to_node x = - Tree_graph.Group { - title = "function_call"; - body = Tree_graph.Fields ( - Tree_graph.StringMap.of_list [ - ("callee", expr_to_node x.callee); - ("arg", Tree_graph.Sequence (List.map expr_to_node x.args)); - ] - ) - } +and func_call_to_node x = match x with + | Nodes.SafeCall x + -> Tree_graph.Group { + title = "function_call"; + body = Tree_graph.Fields ( + Tree_graph.StringMap.of_list [ + ("callee", expr_to_node x.callee); + ("arg", Tree_graph.Sequence (List.map expr_to_node x.args)); + ] + ) + } and param_to_node (x: Nodes.param) = Tree_graph.Fields (Tree_graph.StringMap.of_list [ From d645f358f3fad5348d04680882dffad5bfaff2a4 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 6 Jun 2026 13:01:06 +0200 Subject: [PATCH 098/154] abort handling --- lib/cst/lexer.ml | 1 + lib/cst/nodes.ml | 3 ++- lib/cst/parser.mly | 19 +++++++++++++------ lib/cst/to_tree_graph.ml | 18 ++++++++++++++++++ test-parser/main.zn | 6 ++++-- 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index 69984fbd..e6bc9b15 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -26,6 +26,7 @@ let rec token buf = | ',' -> COMMA | ':' -> COLON | '!' -> EXCL + | "??" -> QSTNQSTN | '?' -> QSTNMARK | '~' -> TILDE | '+' -> PLUS diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 9467309d..7fac8ab9 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -21,12 +21,13 @@ and abort_handle = and abort_call = { callee: expr; args: expr list; + binder: string option; handle_block: abort_handle; } and func_call = | SafeCall of safe_call - (* | AbortCall of abort_call *) + | AbortCall of abort_call and type_expr = diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 632c334e..33ba114b 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -23,6 +23,7 @@ %token AT "@" %token EXCL "!" %token QSTNMARK "?" +%token QSTNQSTN "??" %token TILDE "~" %token THIN_ARROW "->" %token THICK_ARROW "=>" @@ -52,15 +53,15 @@ decl: Nodes.ConstructorDecl { name; type_; args } } | name=IDENT "(" params=separated_list(COMMA, param) ")" - ret_type=ret_type body=func_body { + ret_type=ret_type body=body { Nodes.FuncDecl { name; params; ret_type; body } } | name=IDENT "(" meth_params=meth_params ")" - ret_type=ret_type body=func_body { + ret_type=ret_type body=body { Nodes.MethDecl { name; params=meth_params; ret_type; body; is_mut=false } } | name=IDENT "(" meth_params=meth_params ")" "!" - ret_type=ret_type body=func_body { + ret_type=ret_type body=body { Nodes.MethDecl { name; params=meth_params; ret_type; body; is_mut=true } } @@ -76,14 +77,20 @@ meth_params: | THIS; t=type_expr; rest=loption(preceded(COMMA, separated_nonempty_list(COMMA, param))) { { Nodes.name="this"; type_=t } :: rest } -func_body: - | LCURLY statements=list(stat) RCURLY { +body: + | "{" statements=list(stat) "}" { Nodes.Scope statements } func_call: | callee=expr "(" args=separated_list(COMMA, expr) ")" { - Nodes.SafeCall { callee=callee; args=args } + Nodes.SafeCall { callee; args } + } + | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(IDENT) "?" body=body { + Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortBody body } + } + | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(IDENT) "??" value=expr { + Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortShorthand value } } stat: diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 49ed8222..54cd9295 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -30,6 +30,10 @@ and expr_to_node (x: Nodes.expr) = match x with } | Nodes.FuncCall x -> func_call_to_node x +and abort_handle_to_node (x: Nodes.abort_handle) = match x with + | Nodes.AbortBody x -> body_to_node x + | Nodes.AbortShorthand x -> expr_to_node x + and func_call_to_node x = match x with | Nodes.SafeCall x -> Tree_graph.Group { @@ -41,6 +45,20 @@ and func_call_to_node x = match x with ] ) } + | Nodes.AbortCall x -> + let fields = [ + ("callee", expr_to_node x.callee); + ("args", Tree_graph.Sequence (List.map expr_to_node x.args)); + ("handle_block", abort_handle_to_node x.handle_block) + ] in + let fields = match x.binder with + | Some b -> ("binder", Tree_graph.Leaf b) :: fields + | None -> fields + in + Tree_graph.Group { + title = "function_call"; + body = Tree_graph.Fields (Tree_graph.StringMap.of_list fields) + } and param_to_node (x: Nodes.param) = Tree_graph.Fields (Tree_graph.StringMap.of_list [ diff --git a/test-parser/main.zn b/test-parser/main.zn index 27e0607c..852c26e6 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,6 +1,8 @@ main (this Int, a Bool)! Void?String { x [this Int]! -> Void = "hello" y String = "world" - print(x, y) - log("bug") + content String = read("wordlist.txt") ?? "" + crawl(content) error ? { + print(error) + } } From f85d620e65f12cbe3d50945c90fac4bfe1d3f771 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 6 Jun 2026 13:28:20 +0200 Subject: [PATCH 099/154] resolve and return stats, improve tree graph --- lib/cst/lexer.ml | 2 ++ lib/cst/nodes.ml | 2 ++ lib/cst/parser.mly | 22 +++++++++++++++------- lib/cst/to_tree_graph.ml | 17 +++++++++++++---- test-parser/main.zn | 3 ++- 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index e6bc9b15..ec439999 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -41,6 +41,8 @@ let rec token buf = let s = Utf8.lexeme buf in STRING (String.sub s 1 (String.length s - 2)) | "this" -> THIS + | "return" -> RETURN + | "resolve" -> RESOLVE | Plus ident_char -> IDENT (Utf8.lexeme buf) | eof -> EOF | _ -> ERROR diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 7fac8ab9..b95b5a14 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -43,6 +43,8 @@ and param = { and stat = | FuncCallStat of func_call | DeclStat of decl + | RetStat of expr + | ResolveStat of expr and body = | Scope of stat list diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 33ba114b..b3982196 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -28,6 +28,8 @@ %token THIN_ARROW "->" %token THICK_ARROW "=>" %token THIS "this" +%token RETURN "return" +%token RESOLVE "resolve" %token ERROR "" %token EOF "" @@ -98,6 +100,12 @@ stat: | func_call=func_call { Nodes.FuncCallStat func_call } + | RETURN value=expr { + Nodes.RetStat value + } + | RESOLVE value=expr { + Nodes.ResolveStat value + } param: @@ -105,13 +113,13 @@ param: type_expr: | name=IDENT { Nodes.SimpleType name } - | "[" params=separated_list(COMMA, type_expr) "]" THIN_ARROW ret=type_expr { + | "[" params=separated_list(COMMA, type_expr) "]" "->" ret=type_expr { Nodes.FuncType { params; ret_type=ret } } - | "[" THIS params=separated_list(COMMA, type_expr) "]" THIN_ARROW ret=type_expr { + | "[" THIS params=separated_list(COMMA, type_expr) "]" "->" ret=type_expr { Nodes.MethType { params; ret_type=ret; is_mut=false } } - | "[" THIS params=separated_list(COMMA, type_expr) "]" "!" THIN_ARROW ret=type_expr { + | "[" THIS params=separated_list(COMMA, type_expr) "]" "!" "->" ret=type_expr { Nodes.MethType { params; ret_type=ret; is_mut=true } } @@ -120,10 +128,10 @@ expr: | float=FLOAT { Nodes.FloatLit float } | string=STRING { Nodes.StrLit string } | ident=IDENT { Nodes.Ident ident } - | e1=expr PLUS e2=expr { Nodes.Op { left=e1; right=e2; operator="+" } } - | e1=expr MINUS e2=expr { Nodes.Op { left=e1; right=e2; operator="-" } } - | e1=expr STAR e2=expr { Nodes.Op { left=e1; right=e2; operator="*" } } - | e1=expr SLASH e2=expr { Nodes.Op { left=e1; right=e2; operator="/" } } + | e1=expr "+" e2=expr { Nodes.Op { left=e1; right=e2; operator="+" } } + | e1=expr "-" e2=expr { Nodes.Op { left=e1; right=e2; operator="-" } } + | e1=expr "*" e2=expr { Nodes.Op { left=e1; right=e2; operator="*" } } + | e1=expr "/" e2=expr { Nodes.Op { left=e1; right=e2; operator="/" } } | "(" e=expr ")" { Nodes.Parenthized e } | func_call=func_call { Nodes.FuncCall func_call diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 54cd9295..48e61766 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -72,15 +72,24 @@ and params_to_node (x: Nodes.param list) = and statement_to_node (x: Nodes.stat) = match x with | Nodes.FuncCallStat x -> func_call_to_node x | Nodes.DeclStat x -> decl_to_node x + | Nodes.RetStat x + -> Tree_graph.Group { + title = "ret_stat"; + body = expr_to_node x + } + | Nodes.ResolveStat x + -> Tree_graph.Group { + title = "resolve_stat"; + body = expr_to_node x + } and body_to_node (x: Nodes.body) = match x with | Nodes.Scope scope -> Tree_graph.Group { title = "scope"; - body = Tree_graph.Group { - title = "statement"; - body = Tree_graph.Sequence (List.map statement_to_node scope) - } + body = Tree_graph.Fields (Tree_graph.StringMap.of_list [ + ("stat", Tree_graph.Sequence (List.map statement_to_node scope) ); + ]) } and ret_to_node (x: Nodes.ret_type) = match x with diff --git a/test-parser/main.zn b/test-parser/main.zn index 852c26e6..ca3b93d0 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -2,7 +2,8 @@ main (this Int, a Bool)! Void?String { x [this Int]! -> Void = "hello" y String = "world" content String = read("wordlist.txt") ?? "" - crawl(content) error ? { + results List = crawl(content) error ? { print(error) + resolve "" } } From 90012626bffdec840a2485b321aeff738c0a4545 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 6 Jun 2026 13:33:57 +0200 Subject: [PATCH 100/154] add abort stat --- lib/cst/lexer.ml | 1 + lib/cst/nodes.ml | 1 + lib/cst/parser.mly | 5 ++++- lib/cst/to_tree_graph.ml | 9 +++++++-- syntax.txt | 2 +- test-parser/main.zn | 2 +- 6 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index ec439999..fa04de5e 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -41,6 +41,7 @@ let rec token buf = let s = Utf8.lexeme buf in STRING (String.sub s 1 (String.length s - 2)) | "this" -> THIS + | "abort" -> ABORT | "return" -> RETURN | "resolve" -> RESOLVE | Plus ident_char -> IDENT (Utf8.lexeme buf) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index b95b5a14..159de0aa 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -43,6 +43,7 @@ and param = { and stat = | FuncCallStat of func_call | DeclStat of decl + | AbortStat of expr | RetStat of expr | ResolveStat of expr diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index b3982196..333d587b 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -28,6 +28,7 @@ %token THIN_ARROW "->" %token THICK_ARROW "=>" %token THIS "this" +%token ABORT "abort" %token RETURN "return" %token RESOLVE "resolve" %token ERROR "" @@ -100,6 +101,9 @@ stat: | func_call=func_call { Nodes.FuncCallStat func_call } + | ABORT value=expr { + Nodes.AbortStat value + } | RETURN value=expr { Nodes.RetStat value } @@ -107,7 +111,6 @@ stat: Nodes.ResolveStat value } - param: | name=IDENT type_=type_expr { { Nodes.name; type_ } } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 48e61766..025c90b4 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -69,9 +69,14 @@ and param_to_node (x: Nodes.param) = and params_to_node (x: Nodes.param list) = Tree_graph.Sequence (List.map param_to_node x) -and statement_to_node (x: Nodes.stat) = match x with +and stat_to_node (x: Nodes.stat) = match x with | Nodes.FuncCallStat x -> func_call_to_node x | Nodes.DeclStat x -> decl_to_node x + | Nodes.AbortStat x + -> Tree_graph.Group { + title = "abort_stat"; + body = expr_to_node x + } | Nodes.RetStat x -> Tree_graph.Group { title = "ret_stat"; @@ -88,7 +93,7 @@ and body_to_node (x: Nodes.body) = match x with -> Tree_graph.Group { title = "scope"; body = Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("stat", Tree_graph.Sequence (List.map statement_to_node scope) ); + ("stat", Tree_graph.Sequence (List.map stat_to_node scope) ); ]) } diff --git a/syntax.txt b/syntax.txt index 90ad1214..738fbb05 100644 --- a/syntax.txt +++ b/syntax.txt @@ -2,6 +2,6 @@ main (this Int, a Bool)! Void { print(2, 2) } -new function type syntax: +new function type syntax: varName [this Player, Weapon]! -> Void diff --git a/test-parser/main.zn b/test-parser/main.zn index ca3b93d0..337c368d 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -4,6 +4,6 @@ main (this Int, a Bool)! Void?String { content String = read("wordlist.txt") ?? "" results List = crawl(content) error ? { print(error) - resolve "" + abort error } } From fd0d39eb37d6e64342f12e382700b688058641eb Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 6 Jun 2026 13:43:58 +0200 Subject: [PATCH 101/154] add ret shorthand --- lib/cst/nodes.ml | 1 + lib/cst/parser.mly | 3 +++ lib/cst/to_tree_graph.ml | 5 +++++ test-parser/main.zn | 2 ++ 4 files changed, 11 insertions(+) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 159de0aa..4ad3f869 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -49,6 +49,7 @@ and stat = and body = | Scope of stat list + | RetShorthand of expr and ret_type = | SafeRet of type_expr diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 333d587b..8edd7f71 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -84,6 +84,9 @@ body: | "{" statements=list(stat) "}" { Nodes.Scope statements } + | "=>" value=expr { + Nodes.RetShorthand value + } func_call: | callee=expr "(" args=separated_list(COMMA, expr) ")" { diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 025c90b4..d1fcc5a0 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -96,6 +96,11 @@ and body_to_node (x: Nodes.body) = match x with ("stat", Tree_graph.Sequence (List.map stat_to_node scope) ); ]) } + | Nodes.RetShorthand x + -> Tree_graph.Group { + title = "ret_shorthand"; + body = expr_to_node x + } and ret_to_node (x: Nodes.ret_type) = match x with | Nodes.SafeRet ret -> type_to_node ret diff --git a/test-parser/main.zn b/test-parser/main.zn index 337c368d..5fcf5ece 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -7,3 +7,5 @@ main (this Int, a Bool)! Void?String { abort error } } + +square (x Int, y Int) Int => x * y From 634114b6dc8372b7fc6d1a47664821e54ffad68f Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 6 Jun 2026 14:03:06 +0200 Subject: [PATCH 102/154] improve tree graph api --- lib/cst/to_tree_graph.ml | 200 +++++++++++++++------------------------ lib/tree_graph/node.ml | 12 ++- 2 files changed, 84 insertions(+), 128 deletions(-) diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index d1fcc5a0..3d3b44d7 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -1,166 +1,116 @@ +open Tree_graph + let rec type_to_node = function - | Nodes.SimpleType s -> Tree_graph.Leaf s + | Nodes.SimpleType s -> Leaf s | Nodes.FuncType { params; ret_type } - -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("param", Tree_graph.Sequence (List.map type_to_node params)); - ("type", type_to_node ret_type); - ]) + -> fields [ + ("param", map_seq type_to_node params); + ("type", type_to_node ret_type); + ] | Nodes.MethType { params; ret_type; is_mut } - -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("param", Tree_graph.Sequence (List.map type_to_node params)); - ("type", type_to_node ret_type); - ("is_mut", Tree_graph.Leaf (string_of_bool is_mut)); - ]) + -> fields [ + ("param", map_seq type_to_node params); + ("type", type_to_node ret_type); + ("is_mut", Leaf (string_of_bool is_mut)); + ] and expr_to_node (x: Nodes.expr) = match x with - | Nodes.IntLit x -> Tree_graph.Leaf x - | Nodes.FloatLit x -> Tree_graph.Leaf x - | Nodes.StrLit x -> Tree_graph.Leaf x - | Nodes.Ident x -> Tree_graph.Leaf x + | Nodes.IntLit x -> Leaf x + | Nodes.FloatLit x -> Leaf x + | Nodes.StrLit x -> Leaf x + | Nodes.Ident x -> Leaf x | Nodes.Op x - -> Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("left", expr_to_node x.left); - ("right", expr_to_node x.right); - ("op", Tree_graph.Leaf x.operator); - ]) + -> fields [ + ("left", expr_to_node x.left); + ("right", expr_to_node x.right); + ("op", Leaf x.operator); + ] | Nodes.Parenthized x - -> Tree_graph.Group { - title = "Parenthized"; - body = expr_to_node x - } + -> group "Parenthized" (expr_to_node x) | Nodes.FuncCall x -> func_call_to_node x and abort_handle_to_node (x: Nodes.abort_handle) = match x with - | Nodes.AbortBody x -> body_to_node x + | Nodes.AbortBody x -> body_to_node x | Nodes.AbortShorthand x -> expr_to_node x and func_call_to_node x = match x with | Nodes.SafeCall x - -> Tree_graph.Group { - title = "function_call"; - body = Tree_graph.Fields ( - Tree_graph.StringMap.of_list [ - ("callee", expr_to_node x.callee); - ("arg", Tree_graph.Sequence (List.map expr_to_node x.args)); - ] - ) - } + -> group "function_call" (fields [ + ("callee", expr_to_node x.callee); + ("arg", map_seq expr_to_node x.args); + ]) | Nodes.AbortCall x -> - let fields = [ - ("callee", expr_to_node x.callee); - ("args", Tree_graph.Sequence (List.map expr_to_node x.args)); - ("handle_block", abort_handle_to_node x.handle_block) + let fs = [ + ("callee", expr_to_node x.callee); + ("args", map_seq expr_to_node x.args); + ("handle_block", abort_handle_to_node x.handle_block); ] in - let fields = match x.binder with - | Some b -> ("binder", Tree_graph.Leaf b) :: fields - | None -> fields + let fs = match x.binder with + | Some b -> ("binder", Leaf b) :: fs + | None -> fs in - Tree_graph.Group { - title = "function_call"; - body = Tree_graph.Fields (Tree_graph.StringMap.of_list fields) - } + group "function_call" (fields fs) and param_to_node (x: Nodes.param) = - Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("name", Tree_graph.Leaf x.name); + fields [ + ("name", Leaf x.name); ("type", type_to_node x.type_); - ]) + ] and params_to_node (x: Nodes.param list) = - Tree_graph.Sequence (List.map param_to_node x) + map_seq param_to_node x and stat_to_node (x: Nodes.stat) = match x with | Nodes.FuncCallStat x -> func_call_to_node x - | Nodes.DeclStat x -> decl_to_node x - | Nodes.AbortStat x - -> Tree_graph.Group { - title = "abort_stat"; - body = expr_to_node x - } - | Nodes.RetStat x - -> Tree_graph.Group { - title = "ret_stat"; - body = expr_to_node x - } - | Nodes.ResolveStat x - -> Tree_graph.Group { - title = "resolve_stat"; - body = expr_to_node x - } + | Nodes.DeclStat x -> decl_to_node x + | Nodes.AbortStat x -> group "abort_stat" (expr_to_node x) + | Nodes.RetStat x -> group "ret_stat" (expr_to_node x) + | Nodes.ResolveStat x -> group "resolve_stat" (expr_to_node x) and body_to_node (x: Nodes.body) = match x with | Nodes.Scope scope - -> Tree_graph.Group { - title = "scope"; - body = Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("stat", Tree_graph.Sequence (List.map stat_to_node scope) ); - ]) - } + -> group "scope" (fields [ + ("stat", map_seq stat_to_node scope); + ]) | Nodes.RetShorthand x - -> Tree_graph.Group { - title = "ret_shorthand"; - body = expr_to_node x - } + -> group "ret_shorthand" (expr_to_node x) and ret_to_node (x: Nodes.ret_type) = match x with | Nodes.SafeRet ret -> type_to_node ret | Nodes.AbortRet (ret_type, abort_type) - -> Tree_graph.Fields ( - Tree_graph.StringMap.of_list [ - ("safe_type", type_to_node abort_type ); - ("abort_type", type_to_node ret_type); - ] - ) + -> fields [ + ("safe_type", type_to_node abort_type); + ("abort_type", type_to_node ret_type); + ] and decl_to_node = function | Nodes.FuncDecl { name; params; ret_type; body } - -> Tree_graph.Group { - title = "func_decl"; - body = Tree_graph.Fields ( - Tree_graph.StringMap.of_list [ - ("param", params_to_node params); - ("ret_type", ret_to_node ret_type); - ("body", body_to_node body); - ] - ) - } + -> group "func_decl" (fields [ + ("param", params_to_node params); + ("ret_type", ret_to_node ret_type); + ("body", body_to_node body); + ]) | Nodes.MethDecl { name; params; ret_type; body; is_mut } - -> Tree_graph.Group { - title = "method_decl"; - body = Tree_graph.Fields ( - Tree_graph.StringMap.of_list [ - ("param", params_to_node params); - ("ret_type", ret_to_node ret_type); - ("body", body_to_node body); - ("is_mut ", Tree_graph.Leaf (string_of_bool is_mut)); - ] - ) - } + -> group "method_decl" (fields [ + ("param", params_to_node params); + ("ret_type", ret_to_node ret_type); + ("body", body_to_node body); + ("is_mut", Leaf (string_of_bool is_mut)); + ]) | Nodes.VarDecl { name; type_; value } - -> Tree_graph.Group { - title = "var_decl"; - body = Tree_graph.Fields ( - Tree_graph.StringMap.of_list [ - ("name", Tree_graph.Leaf name); - ("type", type_to_node type_); - ("value", expr_to_node value); - ] - ) - } + -> group "var_decl" (fields [ + ("name", Leaf name); + ("type", type_to_node type_); + ("value", expr_to_node value); + ]) | Nodes.ConstructorDecl { name; type_; args } - -> Tree_graph.Group { - title = "constructor_decl"; - body = Tree_graph.Fields ( - Tree_graph.StringMap.of_list [ - ("name", Tree_graph.Leaf name); - ("type", type_to_node type_); - ("args", Tree_graph.Sequence (List.map expr_to_node args)); - ] - ) - } + -> group "constructor_decl" (fields [ + ("name", Leaf name); + ("type", type_to_node type_); + ("args", map_seq expr_to_node args); + ]) let to_node ({ Nodes.decls }: Nodes.package) = - Tree_graph.Group { title = "package"; body = Tree_graph.Fields (Tree_graph.StringMap.of_list [ - ("declarations", Tree_graph.Sequence (List.map decl_to_node decls)) - ]) - } + group "package" (fields [ + ("declarations", map_seq decl_to_node decls); + ]) diff --git a/lib/tree_graph/node.ml b/lib/tree_graph/node.ml index 7aa7be9d..87ca62aa 100644 --- a/lib/tree_graph/node.ml +++ b/lib/tree_graph/node.ml @@ -1,7 +1,13 @@ module StringMap = Map.Make(String) [@@deriving map] type node = - | Leaf of string - | Group of { title: string; body: node } - | Fields of node StringMap.t + | Leaf of string + | Group of { title: string; body: node } + | Fields of node StringMap.t | Sequence of node list + +(* Smart constructors *) +let group title body = Group { title; body } +let fields pairs = Fields (StringMap.of_list pairs) +let seq xs = Sequence xs +let map_seq f xs = Sequence (List.map f xs) From 46b5216d48bb4de48a5557263615cfec473f7f93 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 6 Jun 2026 19:38:53 +0200 Subject: [PATCH 103/154] improvements --- lib/cst/lexer.ml | 2 + lib/cst/nodes.ml | 56 +++++++++++++++++++++------ lib/cst/parser.mly | 73 +++++++++++++++++++++++------------ lib/cst/to_tree_graph.ml | 82 ++++++++++++++++++++++++++++------------ test-parser/main.zn | 2 + 5 files changed, 153 insertions(+), 62 deletions(-) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index fa04de5e..4ae67b14 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -40,6 +40,8 @@ let rec token buf = | '"', Star str_char, '"' -> let s = Utf8.lexeme buf in STRING (String.sub s 1 (String.length s - 2)) + | "true" -> TRUE + | "false" -> FALSE | "this" -> THIS | "abort" -> ABORT | "return" -> RETURN diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 4ad3f869..fcfc0954 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -1,13 +1,23 @@ (* The CST's job is to represent what was parsed, not what's valid. *) +type operator = + | Add + | Sub + | Mul + | Div + type expr = - | IntLit of string - | FloatLit of string - | StrLit of string - | Ident of string - | Op of { left: expr; right: expr; operator: string } - | Parenthized of expr - | FuncCall of func_call + | IntLit of string + | FloatLit of string + | StrLit of string + | BoolLit of bool + | Ident of string + | QualifiedIdent of string * string + | Op of { left: expr; right: expr; operator: operator } + | Parenthized of expr + | FuncCall of func_call + | FuncLambda of func_lambda + | MethLambda of meth_lambda and safe_call = { callee: expr; @@ -29,11 +39,19 @@ and func_call = | SafeCall of safe_call | AbortCall of abort_call - and type_expr = | SimpleType of string - | FuncType of { params: type_expr list; ret_type: type_expr } - | MethType of { params: type_expr list; ret_type: type_expr; is_mut: bool } + | QualifiedType of string * string + | FuncType of { + params: type_expr list; + ret_type: type_expr + } + | MethType of { + this_type: type_expr; + params: type_expr list; + ret_type: type_expr; + is_mut: bool + } and param = { name: string; @@ -55,9 +73,23 @@ and ret_type = | SafeRet of type_expr | AbortRet of type_expr * type_expr +and func_lambda = { + params: param list; + ret_type: ret_type; + body: body +} + +and meth_lambda = { + this_type: type_expr; + params: param list; + ret_type: ret_type; + is_mut: bool; + body: body +} + and decl = - | FuncDecl of { name: string; params: param list; ret_type: ret_type; body: body } - | MethDecl of { name: string; params: param list; ret_type: ret_type; is_mut: bool ; body: body } + | FuncDecl of { name: string; func: func_lambda } + | MethDecl of { name: string; func: meth_lambda } | VarDecl of { name: string; type_: type_expr; value: expr } | ConstructorDecl of { name: string; type_: type_expr; args: expr list } diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 8edd7f71..a6cc8665 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -27,6 +27,8 @@ %token TILDE "~" %token THIN_ARROW "->" %token THICK_ARROW "=>" +%token TRUE "true" +%token FALSE "false" %token THIS "this" %token ABORT "abort" %token RETURN "return" @@ -48,6 +50,24 @@ package: | decls=list(decl) EOF { { Nodes.decls=decls } } +func_lambda: + | "(" params=separated_list(COMMA, param) ")" + ret_type=ret_type body=body { + { Nodes.params; ret_type; body } + } + +meth_lambda: + | "(" THIS this_type=type_expr + params=loption(preceded(",", separated_nonempty_list(",", param))) + ")" ret_type=ret_type body=body { + { Nodes.this_type; params; ret_type; is_mut=false; body } + } + | "(" THIS this_type=type_expr + params=loption(preceded(",", separated_nonempty_list(",", param))) + ")" "!" ret_type=ret_type body=body { + { Nodes.this_type; params; ret_type; is_mut=true; body } + } + decl: | name=IDENT type_=type_expr "=" value=expr { Nodes.VarDecl { name; type_; value } @@ -55,17 +75,11 @@ decl: | name=IDENT type_=type_expr "(" args=separated_list(COMMA, expr) ")" { Nodes.ConstructorDecl { name; type_; args } } - | name=IDENT "(" params=separated_list(COMMA, param) ")" - ret_type=ret_type body=body { - Nodes.FuncDecl { name; params; ret_type; body } - } - | name=IDENT "(" meth_params=meth_params ")" - ret_type=ret_type body=body { - Nodes.MethDecl { name; params=meth_params; ret_type; body; is_mut=false } + | name=IDENT func_lambda=func_lambda { + Nodes.FuncDecl { name; func=func_lambda } } - | name=IDENT "(" meth_params=meth_params ")" "!" - ret_type=ret_type body=body { - Nodes.MethDecl { name; params=meth_params; ret_type; body; is_mut=true } + | name=IDENT meth_lambda=meth_lambda { + Nodes.MethDecl { name; func=meth_lambda } } ret_type: @@ -73,12 +87,8 @@ ret_type: Nodes.SafeRet ret_type } | safe_type=type_expr "?" abort_type=type_expr { - Nodes.AbortRet (safe_type, abort_type) - } - -meth_params: - | THIS; t=type_expr; rest=loption(preceded(COMMA, separated_nonempty_list(COMMA, param))) - { { Nodes.name="this"; type_=t } :: rest } + Nodes.AbortRet (safe_type, abort_type) + } body: | "{" statements=list(stat) "}" { @@ -119,26 +129,39 @@ param: type_expr: | name=IDENT { Nodes.SimpleType name } - | "[" params=separated_list(COMMA, type_expr) "]" "->" ret=type_expr { + | pkg=IDENT name=IDENT { Nodes.QualifiedType (pkg, name) } + | "[" params=separated_list(",", type_expr) "]" "->" ret=type_expr { Nodes.FuncType { params; ret_type=ret } } - | "[" THIS params=separated_list(COMMA, type_expr) "]" "->" ret=type_expr { - Nodes.MethType { params; ret_type=ret; is_mut=false } + | "[" THIS this_type=type_expr + params=loption(preceded(",", separated_nonempty_list(",", type_expr))) + "]" "->" ret=type_expr { + Nodes.MethType { this_type; params; ret_type=ret; is_mut=false } } - | "[" THIS params=separated_list(COMMA, type_expr) "]" "!" "->" ret=type_expr { - Nodes.MethType { params; ret_type=ret; is_mut=true } + | "[" THIS this_type=type_expr + params=loption(preceded(",", separated_nonempty_list(",", type_expr))) + "]" "!" "->" ret=type_expr { + Nodes.MethType { this_type; params; ret_type=ret; is_mut=true } } expr: | int=INT { Nodes.IntLit int } | float=FLOAT { Nodes.FloatLit float } | string=STRING { Nodes.StrLit string } + | TRUE { Nodes.BoolLit true } + | FALSE { Nodes.BoolLit false } | ident=IDENT { Nodes.Ident ident } - | e1=expr "+" e2=expr { Nodes.Op { left=e1; right=e2; operator="+" } } - | e1=expr "-" e2=expr { Nodes.Op { left=e1; right=e2; operator="-" } } - | e1=expr "*" e2=expr { Nodes.Op { left=e1; right=e2; operator="*" } } - | e1=expr "/" e2=expr { Nodes.Op { left=e1; right=e2; operator="/" } } + | e1=expr "+" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Add } } + | e1=expr "-" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Sub } } + | e1=expr "*" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Mul } } + | e1=expr "/" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Div } } | "(" e=expr ")" { Nodes.Parenthized e } | func_call=func_call { Nodes.FuncCall func_call } + | func_lambda=func_lambda { + Nodes.FuncLambda func_lambda + } + | meth_lambda=meth_lambda { + Nodes.MethLambda meth_lambda + } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 3d3b44d7..950628b4 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -2,32 +2,51 @@ open Tree_graph let rec type_to_node = function | Nodes.SimpleType s -> Leaf s + | Nodes.QualifiedType (pkg, type_) -> Leaf (pkg ^ type_) | Nodes.FuncType { params; ret_type } -> fields [ ("param", map_seq type_to_node params); ("type", type_to_node ret_type); ] - | Nodes.MethType { params; ret_type; is_mut } + | Nodes.MethType { this_type; params; ret_type; is_mut } -> fields [ - ("param", map_seq type_to_node params); - ("type", type_to_node ret_type); - ("is_mut", Leaf (string_of_bool is_mut)); - ] + ("this_type", type_to_node this_type ); + ("param", map_seq type_to_node params); + ("type", type_to_node ret_type); + ("is_mut", Leaf (string_of_bool is_mut)); + ] and expr_to_node (x: Nodes.expr) = match x with - | Nodes.IntLit x -> Leaf x - | Nodes.FloatLit x -> Leaf x - | Nodes.StrLit x -> Leaf x - | Nodes.Ident x -> Leaf x + | Nodes.IntLit x -> Leaf x + | Nodes.FloatLit x -> Leaf x + | Nodes.StrLit x -> Leaf x + | Nodes.BoolLit x -> Leaf (string_of_bool x) + | Nodes.Ident x -> Leaf x + | Nodes.QualifiedIdent (pkg, name) -> Leaf (pkg ^ "$" ^ name) | Nodes.Op x -> fields [ - ("left", expr_to_node x.left); - ("right", expr_to_node x.right); - ("op", Leaf x.operator); - ] + (op_to_name x.operator, fields [ + ("left", expr_to_node x.left); + ("right", expr_to_node x.right); + ]); + ] | Nodes.Parenthized x -> group "Parenthized" (expr_to_node x) | Nodes.FuncCall x -> func_call_to_node x + | Nodes.FuncLambda x + -> group "func_decl" ( + func_lambda_to_node x + ) + | Nodes.MethLambda x + -> group "meth_lambda" ( + meth_lambda_to_node x + ) + +and op_to_name (x: Nodes.operator) = match x with + | Add -> "+" + | Sub -> "-" + | Mul -> "*" + | Div -> "*" and abort_handle_to_node (x: Nodes.abort_handle) = match x with | Nodes.AbortBody x -> body_to_node x @@ -83,20 +102,33 @@ and ret_to_node (x: Nodes.ret_type) = match x with ("abort_type", type_to_node ret_type); ] +and func_lambda_to_node (x: Nodes.func_lambda) = + fields [ + ("param", params_to_node x.params); + ("ret_type", ret_to_node x.ret_type); + ("body", body_to_node x.body); + ] + +and meth_lambda_to_node (x: Nodes.meth_lambda) = + fields [ + ("this_type", type_to_node x.this_type); + ("param", params_to_node x.params); + ("ret_type", ret_to_node x.ret_type); + ("body", body_to_node x.body); + ("is_mut", Leaf (string_of_bool x.is_mut)); + ] + and decl_to_node = function - | Nodes.FuncDecl { name; params; ret_type; body } + | Nodes.FuncDecl x -> group "func_decl" (fields [ - ("param", params_to_node params); - ("ret_type", ret_to_node ret_type); - ("body", body_to_node body); - ]) - | Nodes.MethDecl { name; params; ret_type; body; is_mut } - -> group "method_decl" (fields [ - ("param", params_to_node params); - ("ret_type", ret_to_node ret_type); - ("body", body_to_node body); - ("is_mut", Leaf (string_of_bool is_mut)); - ]) + ("name", Leaf x.name); + ("func", func_lambda_to_node x.func); + ]) + | Nodes.MethDecl x + -> group "func_decl" (fields [ + ("name", Leaf x.name); + ("func", meth_lambda_to_node x.func); + ]) | Nodes.VarDecl { name; type_; value } -> group "var_decl" (fields [ ("name", Leaf name); diff --git a/test-parser/main.zn b/test-parser/main.zn index 5fcf5ece..cd18bdbf 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -6,6 +6,8 @@ main (this Int, a Bool)! Void?String { print(error) abort error } + + rifle Weapon("rifle", 20) } square (x Int, y Int) Int => x * y From ae6342dd11662da2579b8029475ee7f52c2a7f65 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 6 Jun 2026 19:49:01 +0200 Subject: [PATCH 104/154] format --- lib/cst/to_tree_graph.ml | 163 +++++++++++++++++++-------------------- lib/tree_graph/render.ml | 24 +++--- 2 files changed, 92 insertions(+), 95 deletions(-) diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 950628b4..bcabcbab 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -1,68 +1,65 @@ open Tree_graph let rec type_to_node = function - | Nodes.SimpleType s -> Leaf s + | Nodes.SimpleType s -> Leaf s | Nodes.QualifiedType (pkg, type_) -> Leaf (pkg ^ type_) - | Nodes.FuncType { params; ret_type } - -> fields [ - ("param", map_seq type_to_node params); - ("type", type_to_node ret_type); - ] - | Nodes.MethType { this_type; params; ret_type; is_mut } - -> fields [ - ("this_type", type_to_node this_type ); - ("param", map_seq type_to_node params); - ("type", type_to_node ret_type); - ("is_mut", Leaf (string_of_bool is_mut)); - ] + | Nodes.FuncType { params; ret_type } -> + fields [ + ("param", map_seq type_to_node params); + ("type", type_to_node ret_type); + ] + | Nodes.MethType { this_type; params; ret_type; is_mut } -> + fields [ + ("this_type", type_to_node this_type); + ("param", map_seq type_to_node params); + ("type", type_to_node ret_type); + ("is_mut", Leaf (string_of_bool is_mut)); + ] -and expr_to_node (x: Nodes.expr) = match x with - | Nodes.IntLit x -> Leaf x - | Nodes.FloatLit x -> Leaf x - | Nodes.StrLit x -> Leaf x - | Nodes.BoolLit x -> Leaf (string_of_bool x) - | Nodes.Ident x -> Leaf x - | Nodes.QualifiedIdent (pkg, name) -> Leaf (pkg ^ "$" ^ name) - | Nodes.Op x - -> fields [ +and expr_to_node (x : Nodes.expr) = match x with + | Nodes.IntLit x -> Leaf x + | Nodes.FloatLit x -> Leaf x + | Nodes.StrLit x -> Leaf x + | Nodes.BoolLit x -> Leaf (string_of_bool x) + | Nodes.Ident x -> Leaf x + | Nodes.QualifiedIdent (pkg, name) -> Leaf (pkg ^ "$" ^ name) + | Nodes.Op x -> + fields [ (op_to_name x.operator, fields [ ("left", expr_to_node x.left); ("right", expr_to_node x.right); ]); ] - | Nodes.Parenthized x - -> group "Parenthized" (expr_to_node x) - | Nodes.FuncCall x -> func_call_to_node x - | Nodes.FuncLambda x - -> group "func_decl" ( - func_lambda_to_node x - ) - | Nodes.MethLambda x - -> group "meth_lambda" ( - meth_lambda_to_node x - ) + | Nodes.Parenthized x -> + group "Parenthized" (expr_to_node x) + | Nodes.FuncCall x -> + func_call_to_node x + | Nodes.FuncLambda x -> + group "func_decl" (func_lambda_to_node x) + | Nodes.MethLambda x -> + group "meth_lambda" (meth_lambda_to_node x) -and op_to_name (x: Nodes.operator) = match x with +and op_to_name (x : Nodes.operator) = match x with | Add -> "+" | Sub -> "-" | Mul -> "*" | Div -> "*" -and abort_handle_to_node (x: Nodes.abort_handle) = match x with - | Nodes.AbortBody x -> body_to_node x +and abort_handle_to_node (x : Nodes.abort_handle) = match x with + | Nodes.AbortBody x -> body_to_node x | Nodes.AbortShorthand x -> expr_to_node x and func_call_to_node x = match x with - | Nodes.SafeCall x - -> group "function_call" (fields [ - ("callee", expr_to_node x.callee); - ("arg", map_seq expr_to_node x.args); - ]) + | Nodes.SafeCall x -> + group "function_call" (fields [ + ("callee", expr_to_node x.callee); + ("arg", map_seq expr_to_node x.args); + ]) | Nodes.AbortCall x -> let fs = [ - ("callee", expr_to_node x.callee); - ("args", map_seq expr_to_node x.args); - ("handle_block", abort_handle_to_node x.handle_block); + ("callee", expr_to_node x.callee); + ("args", map_seq expr_to_node x.args); + ("handle_block", abort_handle_to_node x.handle_block); ] in let fs = match x.binder with | Some b -> ("binder", Leaf b) :: fs @@ -70,79 +67,79 @@ and func_call_to_node x = match x with in group "function_call" (fields fs) -and param_to_node (x: Nodes.param) = +and param_to_node (x : Nodes.param) = fields [ ("name", Leaf x.name); ("type", type_to_node x.type_); ] -and params_to_node (x: Nodes.param list) = +and params_to_node (x : Nodes.param list) = map_seq param_to_node x -and stat_to_node (x: Nodes.stat) = match x with +and stat_to_node (x : Nodes.stat) = match x with | Nodes.FuncCallStat x -> func_call_to_node x | Nodes.DeclStat x -> decl_to_node x | Nodes.AbortStat x -> group "abort_stat" (expr_to_node x) | Nodes.RetStat x -> group "ret_stat" (expr_to_node x) | Nodes.ResolveStat x -> group "resolve_stat" (expr_to_node x) -and body_to_node (x: Nodes.body) = match x with - | Nodes.Scope scope - -> group "scope" (fields [ - ("stat", map_seq stat_to_node scope); - ]) - | Nodes.RetShorthand x - -> group "ret_shorthand" (expr_to_node x) +and body_to_node (x : Nodes.body) = match x with + | Nodes.Scope scope -> + group "scope" (fields [ + ("stat", map_seq stat_to_node scope); + ]) + | Nodes.RetShorthand x -> + group "ret_shorthand" (expr_to_node x) -and ret_to_node (x: Nodes.ret_type) = match x with +and ret_to_node (x : Nodes.ret_type) = match x with | Nodes.SafeRet ret -> type_to_node ret - | Nodes.AbortRet (ret_type, abort_type) - -> fields [ - ("safe_type", type_to_node abort_type); - ("abort_type", type_to_node ret_type); - ] + | Nodes.AbortRet (ret_type, abort_type) -> + fields [ + ("safe_type", type_to_node abort_type); + ("abort_type", type_to_node ret_type); + ] -and func_lambda_to_node (x: Nodes.func_lambda) = +and func_lambda_to_node (x : Nodes.func_lambda) = fields [ ("param", params_to_node x.params); ("ret_type", ret_to_node x.ret_type); ("body", body_to_node x.body); ] -and meth_lambda_to_node (x: Nodes.meth_lambda) = +and meth_lambda_to_node (x : Nodes.meth_lambda) = fields [ ("this_type", type_to_node x.this_type); - ("param", params_to_node x.params); - ("ret_type", ret_to_node x.ret_type); - ("body", body_to_node x.body); - ("is_mut", Leaf (string_of_bool x.is_mut)); + ("param", params_to_node x.params); + ("ret_type", ret_to_node x.ret_type); + ("body", body_to_node x.body); + ("is_mut", Leaf (string_of_bool x.is_mut)); ] and decl_to_node = function - | Nodes.FuncDecl x - -> group "func_decl" (fields [ + | Nodes.FuncDecl x -> + group "func_decl" (fields [ ("name", Leaf x.name); ("func", func_lambda_to_node x.func); ]) - | Nodes.MethDecl x - -> group "func_decl" (fields [ + | Nodes.MethDecl x -> + group "func_decl" (fields [ ("name", Leaf x.name); ("func", meth_lambda_to_node x.func); ]) - | Nodes.VarDecl { name; type_; value } - -> group "var_decl" (fields [ - ("name", Leaf name); - ("type", type_to_node type_); - ("value", expr_to_node value); - ]) - | Nodes.ConstructorDecl { name; type_; args } - -> group "constructor_decl" (fields [ - ("name", Leaf name); - ("type", type_to_node type_); - ("args", map_seq expr_to_node args); - ]) + | Nodes.VarDecl { name; type_; value } -> + group "var_decl" (fields [ + ("name", Leaf name); + ("type", type_to_node type_); + ("value", expr_to_node value); + ]) + | Nodes.ConstructorDecl { name; type_; args } -> + group "constructor_decl" (fields [ + ("name", Leaf name); + ("type", type_to_node type_); + ("args", map_seq expr_to_node args); + ]) -let to_node ({ Nodes.decls }: Nodes.package) = +let to_node ({ Nodes.decls } : Nodes.package) = group "package" (fields [ ("declarations", map_seq decl_to_node decls); ]) diff --git a/lib/tree_graph/render.ml b/lib/tree_graph/render.ml index fa73ec60..bc6a80a7 100644 --- a/lib/tree_graph/render.ml +++ b/lib/tree_graph/render.ml @@ -4,15 +4,15 @@ type item = let rec collect ~name node = match node with - | Node.Leaf v - -> [ILeaf (name, v)] + | Node.Leaf v -> + [ILeaf (name, v)] - | Node.Group { title; body } - -> let new_name = if name = "" then title else name ^ " > " ^ title in + | Node.Group { title; body } -> + let new_name = if name = "" then title else name ^ " > " ^ title in collect ~name:new_name body - | Node.Fields map - -> let nested_items = + | Node.Fields map -> + let nested_items = Node.StringMap.bindings map |> List.map (fun (k, v) -> collect ~name:k v) |> List.flatten @@ -20,12 +20,12 @@ let rec collect ~name node = if name = "" then nested_items else [IContainer (name, nested_items)] - | Node.Sequence list - -> if list = [] then + | Node.Sequence list -> + if list = [] then if name = "" then [] else [IContainer (name, [])] else - List.mapi (fun i v - -> let element_name = + List.mapi (fun i v -> + let element_name = if name = "" then Printf.sprintf "[%d]" i else Printf.sprintf "%s[%d]" name i in @@ -36,8 +36,8 @@ let render root_node = let items = collect ~name:"" root_node in let rec print_items prefix items = let len = List.length items in - List.iteri (fun i item - -> let is_last = (i = len - 1) in + List.iteri (fun i item -> + let is_last = (i = len - 1) in let branch = if is_last then "└── " else "├── " in let nested_prefix = prefix ^ (if is_last then " " else "│ ") in match item with From 343edbfa7aae7a7c7127323a57de9350396506a4 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 6 Jun 2026 20:54:34 +0200 Subject: [PATCH 105/154] fixup --- bin/compiler/main.ml | 10 +++++++--- lib/cst/cst.ml | 6 +++--- lib/cst/lexer.ml | 2 -- lib/cst/parse_error.ml | 37 ++++++++++++++++++++++++++++--------- lib/cst/parser.mly | 1 + lib/cst/to_tree_graph.ml | 14 +++++++------- test-parser/main.zn | 2 +- 7 files changed, 47 insertions(+), 25 deletions(-) diff --git a/bin/compiler/main.ml b/bin/compiler/main.ml index 699c8c6f..86ec7c8f 100644 --- a/bin/compiler/main.ml +++ b/bin/compiler/main.ml @@ -3,6 +3,10 @@ let read_file path = let () = let input = read_file "test-parser/main.zn" in - let cst = Cst.parse "test-parser/main,zn" input in - let output = Cst.to_node cst in - Tree_graph.render output + match Cst.parse "test-parser/main.zn" input with + | Ok cst -> + let output = Cst.to_node cst in + Tree_graph.render output + | Error message -> + prerr_string message; + exit 1 diff --git a/lib/cst/cst.ml b/lib/cst/cst.ml index 1384f3d7..ede91170 100644 --- a/lib/cst/cst.ml +++ b/lib/cst/cst.ml @@ -7,7 +7,7 @@ let parse filename input = let lexbuf = Sedlexing.Utf8.from_string input in let tokenizer = Sedlexing.with_tokenizer Lexer.token lexbuf in try - MenhirLib.Convert.Simplified.traditional2revised Parser.package tokenizer - with Parser.Error tokenizer -> + Ok (MenhirLib.Convert.Simplified.traditional2revised Parser.package tokenizer) + with Parser.Error _tokenizer -> let (pos_start, pos_end) = Sedlexing.lexing_positions lexbuf in - Parse_error.print_parse_error filename input pos_start pos_end + Error (Parse_error.format_parse_error filename input pos_start pos_end) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index 4ae67b14..a047670d 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -9,8 +9,6 @@ let nonascii = [%sedlex.regexp? 192 .. 214 | 216 .. 246 | 248 .. 255] let ident_char = [%sedlex.regexp? 'a'..'z' | 'A'..'Z' | '_' | nonascii] let str_char = [%sedlex.regexp? Compl ('"' | '\\') | '\\', any] -let strip_sep s = String.concat "" (String.split_on_char '\'' s) - let rec token buf = match%sedlex buf with | Plus (' ' | '\t' | '\r' | '\n') -> token buf diff --git a/lib/cst/parse_error.ml b/lib/cst/parse_error.ml index 3de7a2a3..a140dfd7 100644 --- a/lib/cst/parse_error.ml +++ b/lib/cst/parse_error.ml @@ -26,10 +26,9 @@ let expand_tabs s = in aux 0 0 -let print_parse_error filename input pos_start pos_end = +let format_parse_error filename input pos_start pos_end = let line = pos_start.Lexing.pos_lnum in let char_start = pos_start.Lexing.pos_cnum - pos_start.Lexing.pos_bol in - let char_end = pos_end.Lexing.pos_cnum - pos_start.Lexing.pos_bol in let lines = String.split_on_char '\n' input in let source_line = match List.nth_opt lines (line - 1) with @@ -38,13 +37,33 @@ let print_parse_error filename input pos_start pos_end = if len > 0 && l.[len - 1] = '\r' then String.sub l 0 (len - 1) else l | None -> "" in - + let line_len = String.length source_line in + (* The error span may cross newlines. We only display the start line, so the + caret must stop at that line's end rather than following pos_end into + later lines. *) + let same_line = pos_end.Lexing.pos_lnum = line in + let char_end = + if same_line then + min line_len (pos_end.Lexing.pos_cnum - pos_start.Lexing.pos_bol) + else + line_len + in + let char_start = min char_start line_len in + let char_end = max char_start char_end in + let vcol_start = visual_col_of_idx source_line char_start in let vcol_end = visual_col_of_idx source_line char_end in let visual_source_line = expand_tabs source_line in - - let () = Printf.eprintf "File \"%s\", line %d, characters %d-%d:\n" filename line (vcol_start + 1) (vcol_end + 1) in - let () = Printf.eprintf "%d | %s\n" line visual_source_line in - let () = Printf.eprintf " | %s%s\n" (String.make vcol_start ' ') (String.make (max 1 (vcol_end - vcol_start)) '^') in - let () = Printf.eprintf "Error: Parse error\n" in - exit 1 + + let buf = Buffer.create 256 in + Buffer.add_string buf + (Printf.sprintf "File \"%s\", line %d, characters %d-%d:\n" + filename line (vcol_start + 1) (vcol_end + 1)); + Buffer.add_string buf + (Printf.sprintf "%d | %s\n" line visual_source_line); + Buffer.add_string buf + (Printf.sprintf " | %s%s\n" + (String.make vcol_start ' ') + (String.make (max 1 (vcol_end - vcol_start)) '^')); + Buffer.add_string buf "Error: Parse error\n"; + Buffer.contents buf diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index a6cc8665..c6bc1ad2 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -151,6 +151,7 @@ expr: | TRUE { Nodes.BoolLit true } | FALSE { Nodes.BoolLit false } | ident=IDENT { Nodes.Ident ident } + | pkg=IDENT "$" ident=IDENT { Nodes.QualifiedIdent (pkg, ident) } | e1=expr "+" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Add } } | e1=expr "-" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Sub } } | e1=expr "*" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Mul } } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index bcabcbab..892c4a24 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -2,7 +2,7 @@ open Tree_graph let rec type_to_node = function | Nodes.SimpleType s -> Leaf s - | Nodes.QualifiedType (pkg, type_) -> Leaf (pkg ^ type_) + | Nodes.QualifiedType (pkg, type_) -> Leaf (pkg ^ "$" ^ type_) | Nodes.FuncType { params; ret_type } -> fields [ ("param", map_seq type_to_node params); @@ -35,7 +35,7 @@ and expr_to_node (x : Nodes.expr) = match x with | Nodes.FuncCall x -> func_call_to_node x | Nodes.FuncLambda x -> - group "func_decl" (func_lambda_to_node x) + group "func_lambda" (func_lambda_to_node x) | Nodes.MethLambda x -> group "meth_lambda" (meth_lambda_to_node x) @@ -43,7 +43,7 @@ and op_to_name (x : Nodes.operator) = match x with | Add -> "+" | Sub -> "-" | Mul -> "*" - | Div -> "*" + | Div -> "/" and abort_handle_to_node (x : Nodes.abort_handle) = match x with | Nodes.AbortBody x -> body_to_node x @@ -53,7 +53,7 @@ and func_call_to_node x = match x with | Nodes.SafeCall x -> group "function_call" (fields [ ("callee", expr_to_node x.callee); - ("arg", map_seq expr_to_node x.args); + ("args", map_seq expr_to_node x.args); ]) | Nodes.AbortCall x -> let fs = [ @@ -95,8 +95,8 @@ and ret_to_node (x : Nodes.ret_type) = match x with | Nodes.SafeRet ret -> type_to_node ret | Nodes.AbortRet (ret_type, abort_type) -> fields [ - ("safe_type", type_to_node abort_type); - ("abort_type", type_to_node ret_type); + ("safe_type", type_to_node ret_type); + ("abort_type", type_to_node abort_type); ] and func_lambda_to_node (x : Nodes.func_lambda) = @@ -122,7 +122,7 @@ and decl_to_node = function ("func", func_lambda_to_node x.func); ]) | Nodes.MethDecl x -> - group "func_decl" (fields [ + group "meth_decl" (fields [ ("name", Leaf x.name); ("func", meth_lambda_to_node x.func); ]) diff --git a/test-parser/main.zn b/test-parser/main.zn index cd18bdbf..208734f7 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -3,7 +3,7 @@ main (this Int, a Bool)! Void?String { y String = "world" content String = read("wordlist.txt") ?? "" results List = crawl(content) error ? { - print(error) + std$print(error) abort error } From b820d5e07276c9f585259e68102d90206191c438 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sun, 7 Jun 2026 13:33:30 +0200 Subject: [PATCH 106/154] add boolean ops --- lib/cst/lexer.ml | 9 +++++++++ lib/cst/nodes.ml | 6 ++++++ lib/cst/parser.mly | 15 +++++++++++++++ lib/cst/to_tree_graph.ml | 37 ++++++++++++++++++++++--------------- test-parser/main.zn | 2 ++ 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index a047670d..1057b30d 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -14,6 +14,11 @@ let rec token buf = | Plus (' ' | '\t' | '\r' | '\n') -> token buf | "->" -> THIN_ARROW | "=>" -> THICK_ARROW + | "==" -> EQEQ + | "<=" -> LESSEQ + | ">=" -> MOREEQ + | '<' -> LESS + | '>' -> MORE | '=' -> EQUAL | '(' -> LPAREN | ')' -> RPAREN @@ -38,6 +43,10 @@ let rec token buf = | '"', Star str_char, '"' -> let s = Utf8.lexeme buf in STRING (String.sub s 1 (String.length s - 2)) + | "if" -> IF + | "elif" -> ELIF + | "else" -> ELSE + (* | "loop" -> LOOP *) | "true" -> TRUE | "false" -> FALSE | "this" -> THIS diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index fcfc0954..e938360f 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -5,6 +5,11 @@ type operator = | Sub | Mul | Div + | Eq + | LessEq + | MoreEq + | Less + | More type expr = | IntLit of string @@ -14,6 +19,7 @@ type expr = | Ident of string | QualifiedIdent of string * string | Op of { left: expr; right: expr; operator: operator } + | Flip of expr | Parenthized of expr | FuncCall of func_call | FuncLambda of func_lambda diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index c6bc1ad2..6089aa62 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -27,6 +27,14 @@ %token TILDE "~" %token THIN_ARROW "->" %token THICK_ARROW "=>" +%token EQEQ "==" +%token LESSEQ "<=" +%token MOREEQ ">=" +%token LESS "<" +%token MORE ">" +%token IF "if" +%token ELIF "elif" +%token ELSE "else" %token TRUE "true" %token FALSE "false" %token THIS "this" @@ -39,6 +47,7 @@ %left LPAREN %left PLUS MINUS %left STAR SLASH +%nonassoc TILDE %start package @@ -156,6 +165,12 @@ expr: | e1=expr "-" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Sub } } | e1=expr "*" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Mul } } | e1=expr "/" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Div } } + | e1=expr "==" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Eq } } + | e1=expr "<=" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.LessEq } } + | e1=expr ">=" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.MoreEq } } + | e1=expr "<" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Less } } + | e1=expr ">" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.More } } + | "~" value=expr { Nodes.Flip value } | "(" e=expr ")" { Nodes.Parenthized e } | func_call=func_call { Nodes.FuncCall func_call diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 892c4a24..49ba7ad1 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -18,32 +18,39 @@ let rec type_to_node = function and expr_to_node (x : Nodes.expr) = match x with | Nodes.IntLit x -> Leaf x - | Nodes.FloatLit x -> Leaf x - | Nodes.StrLit x -> Leaf x - | Nodes.BoolLit x -> Leaf (string_of_bool x) - | Nodes.Ident x -> Leaf x - | Nodes.QualifiedIdent (pkg, name) -> Leaf (pkg ^ "$" ^ name) - | Nodes.Op x -> + | FloatLit x -> Leaf x + | StrLit x -> Leaf x + | BoolLit x -> Leaf (string_of_bool x) + | Ident x -> Leaf x + | QualifiedIdent (pkg, name) -> Leaf (pkg ^ "$" ^ name) + | Op x -> fields [ (op_to_name x.operator, fields [ ("left", expr_to_node x.left); ("right", expr_to_node x.right); ]); ] - | Nodes.Parenthized x -> - group "Parenthized" (expr_to_node x) - | Nodes.FuncCall x -> + | Flip x -> + group "flip" (expr_to_node x) + | Parenthized x -> + group "parenthized" (expr_to_node x) + | FuncCall x -> func_call_to_node x - | Nodes.FuncLambda x -> + | FuncLambda x -> group "func_lambda" (func_lambda_to_node x) - | Nodes.MethLambda x -> + | MethLambda x -> group "meth_lambda" (meth_lambda_to_node x) and op_to_name (x : Nodes.operator) = match x with - | Add -> "+" - | Sub -> "-" - | Mul -> "*" - | Div -> "/" + | Add -> "+" + | Sub -> "-" + | Mul -> "*" + | Div -> "/" + | Eq -> "==" + | LessEq -> "<=" + | MoreEq -> ">=" + | Less -> "<" + | More -> ">" and abort_handle_to_node (x : Nodes.abort_handle) = match x with | Nodes.AbortBody x -> body_to_node x diff --git a/test-parser/main.zn b/test-parser/main.zn index 208734f7..070389a1 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -8,6 +8,8 @@ main (this Int, a Bool)! Void?String { } rifle Weapon("rifle", 20) + + value Bool = ~true + 3 } square (x Int, y Int) Int => x * y From a85dd03913366f239cfa97b91c912ab2ccf63f6e Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sun, 7 Jun 2026 13:39:13 +0200 Subject: [PATCH 107/154] remove Nodes prefix in to_tree_graph.ml --- lib/cst/to_tree_graph.ml | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 49ba7ad1..d709a694 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -1,14 +1,14 @@ open Tree_graph -let rec type_to_node = function - | Nodes.SimpleType s -> Leaf s - | Nodes.QualifiedType (pkg, type_) -> Leaf (pkg ^ "$" ^ type_) - | Nodes.FuncType { params; ret_type } -> +let rec type_to_node (x: Nodes.type_expr) = match x with + | SimpleType s -> Leaf s + | QualifiedType (pkg, type_) -> Leaf (pkg ^ "$" ^ type_) + | FuncType { params; ret_type } -> fields [ ("param", map_seq type_to_node params); ("type", type_to_node ret_type); ] - | Nodes.MethType { this_type; params; ret_type; is_mut } -> + | MethType { this_type; params; ret_type; is_mut } -> fields [ ("this_type", type_to_node this_type); ("param", map_seq type_to_node params); @@ -16,8 +16,8 @@ let rec type_to_node = function ("is_mut", Leaf (string_of_bool is_mut)); ] -and expr_to_node (x : Nodes.expr) = match x with - | Nodes.IntLit x -> Leaf x +and expr_to_node (x: Nodes.expr) = match x with + | IntLit x -> Leaf x | FloatLit x -> Leaf x | StrLit x -> Leaf x | BoolLit x -> Leaf (string_of_bool x) @@ -53,16 +53,16 @@ and op_to_name (x : Nodes.operator) = match x with | More -> ">" and abort_handle_to_node (x : Nodes.abort_handle) = match x with - | Nodes.AbortBody x -> body_to_node x - | Nodes.AbortShorthand x -> expr_to_node x + | AbortBody x -> body_to_node x + | AbortShorthand x -> expr_to_node x and func_call_to_node x = match x with - | Nodes.SafeCall x -> + | SafeCall x -> group "function_call" (fields [ ("callee", expr_to_node x.callee); ("args", map_seq expr_to_node x.args); ]) - | Nodes.AbortCall x -> + | AbortCall x -> let fs = [ ("callee", expr_to_node x.callee); ("args", map_seq expr_to_node x.args); @@ -84,23 +84,23 @@ and params_to_node (x : Nodes.param list) = map_seq param_to_node x and stat_to_node (x : Nodes.stat) = match x with - | Nodes.FuncCallStat x -> func_call_to_node x - | Nodes.DeclStat x -> decl_to_node x - | Nodes.AbortStat x -> group "abort_stat" (expr_to_node x) - | Nodes.RetStat x -> group "ret_stat" (expr_to_node x) - | Nodes.ResolveStat x -> group "resolve_stat" (expr_to_node x) + | FuncCallStat x -> func_call_to_node x + | DeclStat x -> decl_to_node x + | AbortStat x -> group "abort_stat" (expr_to_node x) + | RetStat x -> group "ret_stat" (expr_to_node x) + | ResolveStat x -> group "resolve_stat" (expr_to_node x) and body_to_node (x : Nodes.body) = match x with - | Nodes.Scope scope -> + | Scope scope -> group "scope" (fields [ ("stat", map_seq stat_to_node scope); ]) - | Nodes.RetShorthand x -> + | RetShorthand x -> group "ret_shorthand" (expr_to_node x) and ret_to_node (x : Nodes.ret_type) = match x with - | Nodes.SafeRet ret -> type_to_node ret - | Nodes.AbortRet (ret_type, abort_type) -> + | SafeRet ret -> type_to_node ret + | AbortRet (ret_type, abort_type) -> fields [ ("safe_type", type_to_node ret_type); ("abort_type", type_to_node abort_type); @@ -122,24 +122,24 @@ and meth_lambda_to_node (x : Nodes.meth_lambda) = ("is_mut", Leaf (string_of_bool x.is_mut)); ] -and decl_to_node = function - | Nodes.FuncDecl x -> +and decl_to_node (x: Nodes.decl) = match x with + | FuncDecl x -> group "func_decl" (fields [ ("name", Leaf x.name); ("func", func_lambda_to_node x.func); ]) - | Nodes.MethDecl x -> + | MethDecl x -> group "meth_decl" (fields [ ("name", Leaf x.name); ("func", meth_lambda_to_node x.func); ]) - | Nodes.VarDecl { name; type_; value } -> + | VarDecl { name; type_; value } -> group "var_decl" (fields [ ("name", Leaf name); ("type", type_to_node type_); ("value", expr_to_node value); ]) - | Nodes.ConstructorDecl { name; type_; args } -> + | ConstructorDecl { name; type_; args } -> group "constructor_decl" (fields [ ("name", Leaf name); ("type", type_to_node type_); From c1cd9bc79cf05da9c15ebe7b8dafb45ea97a68a3 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sun, 7 Jun 2026 15:25:47 +0200 Subject: [PATCH 108/154] add control flow --- lib/cst/nodes.ml | 12 ++++++++++++ lib/cst/parser.mly | 18 ++++++++++++++++++ lib/cst/to_tree_graph.ml | 22 ++++++++++++++++++++++ test-parser/main.zn | 17 ++++++++++------- 4 files changed, 62 insertions(+), 7 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index e938360f..9f08fef1 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -64,12 +64,24 @@ and param = { type_: type_expr } +and cond_block = { + cond: expr; + block: stat list +} + +and cond_seq = { + if_: cond_block; + elifs_: cond_block list; + else_: stat list option; +} + and stat = | FuncCallStat of func_call | DeclStat of decl | AbortStat of expr | RetStat of expr | ResolveStat of expr + | CondSeq of cond_seq and body = | Scope of stat list diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 6089aa62..eb6d086e 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -118,6 +118,21 @@ func_call: Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortShorthand value } } +%inline if_: + | IF cond=expr "{" block=list(stat) "}" { + { Nodes.cond; block } + } + +%inline elif_: + | ELIF cond=expr "{" block=list(stat) "}" { + { Nodes.cond; block } + } + +%inline else_: + | ELSE "{" statements=list(stat) "}" { + statements + } + stat: | decl=decl { Nodes.DeclStat decl } | func_call=func_call { @@ -132,6 +147,9 @@ stat: | RESOLVE value=expr { Nodes.ResolveStat value } + | if_=if_ elifs_=list(elif_) else_=ioption(else_) { + Nodes.CondSeq { if_; elifs_; else_ } + } param: | name=IDENT type_=type_expr { { Nodes.name; type_ } } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index d709a694..565e59cc 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -83,12 +83,34 @@ and param_to_node (x : Nodes.param) = and params_to_node (x : Nodes.param list) = map_seq param_to_node x +and elif_to_fields (x: Nodes.cond_block) = + fields [ + ("cond", expr_to_node x.cond); + ("block", map_seq stat_to_node x.block); + ] + +and cond_seq_to_node (x: Nodes.cond_seq) = + let cond_seq = [ + ("if", fields [ + ("cond", expr_to_node x.if_.cond); + ("block", map_seq stat_to_node x.if_.block); + ]); + ("elif", map_seq elif_to_fields x.elifs_); + ] in + let cond_seq = match x.else_ with + | Some x -> ("else", fields [ + ("block", map_seq stat_to_node x); + ]) :: cond_seq + | None -> cond_seq + in group "cond_seq" (fields cond_seq) + and stat_to_node (x : Nodes.stat) = match x with | FuncCallStat x -> func_call_to_node x | DeclStat x -> decl_to_node x | AbortStat x -> group "abort_stat" (expr_to_node x) | RetStat x -> group "ret_stat" (expr_to_node x) | ResolveStat x -> group "resolve_stat" (expr_to_node x) + | CondSeq x -> cond_seq_to_node x and body_to_node (x : Nodes.body) = match x with | Scope scope -> diff --git a/test-parser/main.zn b/test-parser/main.zn index 070389a1..faf5d921 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -2,14 +2,17 @@ main (this Int, a Bool)! Void?String { x [this Int]! -> Void = "hello" y String = "world" content String = read("wordlist.txt") ?? "" - results List = crawl(content) error ? { - std$print(error) - abort error + + if random() { + results List = crawl(content) error ? { + std$print(error) + abort error + } + } + else { + rifle Weapon("rifle", 20) + value Bool = ~true + 3 } - - rifle Weapon("rifle", 20) - - value Bool = ~true + 3 } square (x Int, y Int) Int => x * y From b283bce19f78c47558cda5f60bd11b27c12cd34d Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sun, 7 Jun 2026 15:41:54 +0200 Subject: [PATCH 109/154] seperate type and value ident tokens --- lib/cst/lexer.ml | 13 ++++++++++--- lib/cst/parser.mly | 25 +++++++++++++------------ test-parser/main.zn | 2 +- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index 1057b30d..d4e452f0 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -5,10 +5,16 @@ let digit = [%sedlex.regexp? '0'..'9'] let digits = [%sedlex.regexp? Plus digit] let int_lit = [%sedlex.regexp? digits, Star ('\'', digits)] let float_lit = [%sedlex.regexp? int_lit, '.', digits] -let nonascii = [%sedlex.regexp? 192 .. 214 | 216 .. 246 | 248 .. 255] -let ident_char = [%sedlex.regexp? 'a'..'z' | 'A'..'Z' | '_' | nonascii] let str_char = [%sedlex.regexp? Compl ('"' | '\\') | '\\', any] +(* Any character valid inside an identifier (after the first) *) +let ident_char = [%sedlex.regexp? alphabetic | '0'..'9' | '_'] + +(* Starts with a Unicode lowercase letter, or '_' then one *) +let lower_ident = [%sedlex.regexp? (lowercase | '_', lowercase), Star ident_char] +(* Starts with a Unicode uppercase letter, or '_' then one *) +let upper_ident = [%sedlex.regexp? (uppercase | '_', uppercase), Star ident_char] + let rec token buf = match%sedlex buf with | Plus (' ' | '\t' | '\r' | '\n') -> token buf @@ -53,6 +59,7 @@ let rec token buf = | "abort" -> ABORT | "return" -> RETURN | "resolve" -> RESOLVE - | Plus ident_char -> IDENT (Utf8.lexeme buf) + | lower_ident -> LIDENT (Utf8.lexeme buf) + | upper_ident -> UIDENT (Utf8.lexeme buf) | eof -> EOF | _ -> ERROR diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index eb6d086e..c181cbae 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -4,7 +4,8 @@ %token INT "43" %token FLOAT "8.647" %token STRING "\"john\"" -%token IDENT "foo" +%token LIDENT "length" +%token UIDENT "Int" %token LPAREN "(" %token RPAREN ")" @@ -78,16 +79,16 @@ meth_lambda: } decl: - | name=IDENT type_=type_expr "=" value=expr { + | name=LIDENT type_=type_expr "=" value=expr { Nodes.VarDecl { name; type_; value } } - | name=IDENT type_=type_expr "(" args=separated_list(COMMA, expr) ")" { + | name=LIDENT type_=type_expr "(" args=separated_list(COMMA, expr) ")" { Nodes.ConstructorDecl { name; type_; args } } - | name=IDENT func_lambda=func_lambda { + | name=LIDENT func_lambda=func_lambda { Nodes.FuncDecl { name; func=func_lambda } } - | name=IDENT meth_lambda=meth_lambda { + | name=LIDENT meth_lambda=meth_lambda { Nodes.MethDecl { name; func=meth_lambda } } @@ -111,10 +112,10 @@ func_call: | callee=expr "(" args=separated_list(COMMA, expr) ")" { Nodes.SafeCall { callee; args } } - | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(IDENT) "?" body=body { + | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(LIDENT) "?" body=body { Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortBody body } } - | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(IDENT) "??" value=expr { + | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(LIDENT) "??" value=expr { Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortShorthand value } } @@ -152,11 +153,11 @@ stat: } param: - | name=IDENT type_=type_expr { { Nodes.name; type_ } } + | name=LIDENT type_=type_expr { { Nodes.name; type_ } } type_expr: - | name=IDENT { Nodes.SimpleType name } - | pkg=IDENT name=IDENT { Nodes.QualifiedType (pkg, name) } + | name=UIDENT { Nodes.SimpleType name } + | pkg=UIDENT name=UIDENT { Nodes.QualifiedType (pkg, name) } | "[" params=separated_list(",", type_expr) "]" "->" ret=type_expr { Nodes.FuncType { params; ret_type=ret } } @@ -177,8 +178,8 @@ expr: | string=STRING { Nodes.StrLit string } | TRUE { Nodes.BoolLit true } | FALSE { Nodes.BoolLit false } - | ident=IDENT { Nodes.Ident ident } - | pkg=IDENT "$" ident=IDENT { Nodes.QualifiedIdent (pkg, ident) } + | ident=LIDENT { Nodes.Ident ident } + | pkg=UIDENT "$" ident=LIDENT { Nodes.QualifiedIdent (pkg, ident) } | e1=expr "+" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Add } } | e1=expr "-" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Sub } } | e1=expr "*" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Mul } } diff --git a/test-parser/main.zn b/test-parser/main.zn index faf5d921..697ee0ef 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -5,7 +5,7 @@ main (this Int, a Bool)! Void?String { if random() { results List = crawl(content) error ? { - std$print(error) + Std$print(error) abort error } } From 80ef191a2d968ac6371cfa3f8d3c0ce1e144ccc3 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sun, 7 Jun 2026 16:07:26 +0200 Subject: [PATCH 110/154] inline some rules + correct prec --- lib/cst/parser.mly | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index c181cbae..b364c236 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -45,10 +45,13 @@ %token ERROR "" %token EOF "" -%left LPAREN +%nonassoc EQEQ LESSEQ MOREEQ LESS MORE /* comparisons */ %left PLUS MINUS %left STAR SLASH -%nonassoc TILDE +%left LPAREN /* function application */ +%nonassoc IF +%nonassoc ELSE +%nonassoc TILDE /* prefix ~ */ %start package @@ -60,13 +63,13 @@ package: | decls=list(decl) EOF { { Nodes.decls=decls } } -func_lambda: +%inline func_lambda: | "(" params=separated_list(COMMA, param) ")" ret_type=ret_type body=body { { Nodes.params; ret_type; body } } -meth_lambda: +%inline meth_lambda: | "(" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", param))) ")" ret_type=ret_type body=body { @@ -92,7 +95,7 @@ decl: Nodes.MethDecl { name; func=meth_lambda } } -ret_type: +%inline ret_type: | ret_type=type_expr { Nodes.SafeRet ret_type } @@ -109,15 +112,12 @@ body: } func_call: - | callee=expr "(" args=separated_list(COMMA, expr) ")" { - Nodes.SafeCall { callee; args } - } - | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(LIDENT) "?" body=body { - Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortBody body } - } - | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(LIDENT) "??" value=expr { - Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortShorthand value } - } + | callee=expr "(" args=separated_list(COMMA, expr) ")" %prec LPAREN + { Nodes.SafeCall { callee; args } } + | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(LIDENT) "?" body=body %prec LPAREN + { Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortBody body } } + | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(LIDENT) "??" value=expr %prec LPAREN + { Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortShorthand value } } %inline if_: | IF cond=expr "{" block=list(stat) "}" { @@ -152,7 +152,7 @@ stat: Nodes.CondSeq { if_; elifs_; else_ } } -param: +%inline param: | name=LIDENT type_=type_expr { { Nodes.name; type_ } } type_expr: From c64b108ec23ca51e40f6d221f222d4dcfaa230ff Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sun, 7 Jun 2026 16:11:20 +0200 Subject: [PATCH 111/154] correct handling syntax --- lib/cst/parser.mly | 6 +++--- test-parser/main.zn | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index b364c236..3c1cdc21 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -114,9 +114,9 @@ body: func_call: | callee=expr "(" args=separated_list(COMMA, expr) ")" %prec LPAREN { Nodes.SafeCall { callee; args } } - | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(LIDENT) "?" body=body %prec LPAREN + | callee=expr "(" args=separated_list(COMMA, expr) ")" "?" binder=ioption(LIDENT) body=body %prec LPAREN { Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortBody body } } - | callee=expr "(" args=separated_list(COMMA, expr) ")" binder=ioption(LIDENT) "??" value=expr %prec LPAREN + | callee=expr "(" args=separated_list(COMMA, expr) ")" "??" binder=ioption(LIDENT) value=expr %prec LPAREN { Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortShorthand value } } %inline if_: @@ -189,7 +189,7 @@ expr: | e1=expr ">=" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.MoreEq } } | e1=expr "<" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Less } } | e1=expr ">" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.More } } - | "~" value=expr { Nodes.Flip value } + | "~" value=expr %prec TILDE { Nodes.Flip value } | "(" e=expr ")" { Nodes.Parenthized e } | func_call=func_call { Nodes.FuncCall func_call diff --git a/test-parser/main.zn b/test-parser/main.zn index 697ee0ef..83ad6d0b 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -4,7 +4,7 @@ main (this Int, a Bool)! Void?String { content String = read("wordlist.txt") ?? "" if random() { - results List = crawl(content) error ? { + results List = crawl(content) ? error { Std$print(error) abort error } From 7c3b3a2e40bf812a24e224fb5615ed16b7c2a2ec Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sat, 13 Jun 2026 14:00:26 +0200 Subject: [PATCH 112/154] new function syntax --- lib/cst/lexer.ml | 1 + lib/cst/nodes.ml | 18 ++++++- lib/cst/parser.mly | 104 +++++++++++++++++++++------------------ lib/cst/to_tree_graph.ml | 4 +- syntax.txt | 7 --- test-parser/main.zn | 6 +-- 6 files changed, 78 insertions(+), 62 deletions(-) delete mode 100644 syntax.txt diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index d4e452f0..ae034c35 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -56,6 +56,7 @@ let rec token buf = | "true" -> TRUE | "false" -> FALSE | "this" -> THIS + | "mut" -> MUT | "abort" -> ABORT | "return" -> RETURN | "resolve" -> RESOLVE diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 9f08fef1..18134202 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -50,12 +50,12 @@ and type_expr = | QualifiedType of string * string | FuncType of { params: type_expr list; - ret_type: type_expr + ret_type: ret_type } | MethType of { this_type: type_expr; params: type_expr list; - ret_type: type_expr; + ret_type: ret_type; is_mut: bool } @@ -114,3 +114,17 @@ and decl = type package = { decls: decl list } + +let func_type_of_lambda (x: func_lambda) : type_expr = + FuncType { + params = List.map (fun (p: param) -> p.type_) x.params; + ret_type = x.ret_type; +} + +let meth_type_of_lambda (x: meth_lambda) : type_expr = + MethType { + this_type = x.this_type; + params = List.map (fun (p: param) -> p.type_) x.params; + ret_type = x.ret_type; + is_mut = x.is_mut; + } diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 3c1cdc21..45ba069a 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -7,43 +7,44 @@ %token LIDENT "length" %token UIDENT "Int" -%token LPAREN "(" -%token RPAREN ")" -%token COMMA "," -%token LCURLY "{" -%token RCURLY "}" -%token LBRACKET "[" -%token RBRACKET "]" +%token LPAREN "(" +%token RPAREN ")" +%token COMMA "," +%token LCURLY "{" +%token RCURLY "}" +%token LBRACKET "[" +%token RBRACKET "]" %token COLON -%token EQUAL "=" -%token PLUS "+" -%token MINUS "-" -%token STAR "*" -%token SLASH "/" -%token DOLLAR "$" -%token AT "@" -%token EXCL "!" -%token QSTNMARK "?" -%token QSTNQSTN "??" -%token TILDE "~" -%token THIN_ARROW "->" +%token EQUAL "=" +%token PLUS "+" +%token MINUS "-" +%token STAR "*" +%token SLASH "/" +%token DOLLAR "$" +%token AT "@" +%token EXCL "!" +%token QSTNMARK "?" +%token QSTNQSTN "??" +%token TILDE "~" +%token THIN_ARROW "->" %token THICK_ARROW "=>" -%token EQEQ "==" -%token LESSEQ "<=" -%token MOREEQ ">=" -%token LESS "<" -%token MORE ">" -%token IF "if" -%token ELIF "elif" -%token ELSE "else" -%token TRUE "true" -%token FALSE "false" -%token THIS "this" -%token ABORT "abort" -%token RETURN "return" -%token RESOLVE "resolve" -%token ERROR "" -%token EOF "" +%token EQEQ "==" +%token LESSEQ "<=" +%token MOREEQ ">=" +%token LESS "<" +%token MORE ">" +%token IF "if" +%token ELIF "elif" +%token ELSE "else" +%token TRUE "true" +%token FALSE "false" +%token THIS "this" +%token MUT "mut" +%token ABORT "abort" +%token RETURN "return" +%token RESOLVE "resolve" +%token ERROR "" +%token EOF "" %nonassoc EQEQ LESSEQ MOREEQ LESS MORE /* comparisons */ %left PLUS MINUS @@ -64,20 +65,19 @@ package: | decls=list(decl) EOF { { Nodes.decls=decls } } %inline func_lambda: - | "(" params=separated_list(COMMA, param) ")" - ret_type=ret_type body=body { + | ret_type=ret_type "(" params=separated_list(COMMA, param) ")" body=body { { Nodes.params; ret_type; body } } %inline meth_lambda: - | "(" THIS this_type=type_expr + | ret_type=ret_type "(" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", param))) - ")" ret_type=ret_type body=body { + ")" body=body { { Nodes.this_type; params; ret_type; is_mut=false; body } } - | "(" THIS this_type=type_expr + | ret_type=ret_type "(" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", param))) - ")" "!" ret_type=ret_type body=body { + ")" MUT body=body { { Nodes.this_type; params; ret_type; is_mut=true; body } } @@ -89,10 +89,18 @@ decl: Nodes.ConstructorDecl { name; type_; args } } | name=LIDENT func_lambda=func_lambda { - Nodes.FuncDecl { name; func=func_lambda } + Nodes.VarDecl { + name; + type_=Nodes.func_type_of_lambda func_lambda; + value=Nodes.FuncLambda func_lambda + } } | name=LIDENT meth_lambda=meth_lambda { - Nodes.MethDecl { name; func=meth_lambda } + Nodes.VarDecl { + name; + type_=Nodes.meth_type_of_lambda meth_lambda; + value=Nodes.MethLambda meth_lambda + } } %inline ret_type: @@ -158,17 +166,17 @@ stat: type_expr: | name=UIDENT { Nodes.SimpleType name } | pkg=UIDENT name=UIDENT { Nodes.QualifiedType (pkg, name) } - | "[" params=separated_list(",", type_expr) "]" "->" ret=type_expr { + | ret=ret_type "[" params=separated_list(",", type_expr) "]" { Nodes.FuncType { params; ret_type=ret } } - | "[" THIS this_type=type_expr + | ret=ret_type "[" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", type_expr))) - "]" "->" ret=type_expr { + "]" { Nodes.MethType { this_type; params; ret_type=ret; is_mut=false } } - | "[" THIS this_type=type_expr + | ret=ret_type "[" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", type_expr))) - "]" "!" "->" ret=type_expr { + "]" MUT { Nodes.MethType { this_type; params; ret_type=ret; is_mut=true } } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 565e59cc..5862651c 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -6,13 +6,13 @@ let rec type_to_node (x: Nodes.type_expr) = match x with | FuncType { params; ret_type } -> fields [ ("param", map_seq type_to_node params); - ("type", type_to_node ret_type); + ("type", ret_to_node ret_type); ] | MethType { this_type; params; ret_type; is_mut } -> fields [ ("this_type", type_to_node this_type); ("param", map_seq type_to_node params); - ("type", type_to_node ret_type); + ("type", ret_to_node ret_type); ("is_mut", Leaf (string_of_bool is_mut)); ] diff --git a/syntax.txt b/syntax.txt deleted file mode 100644 index 738fbb05..00000000 --- a/syntax.txt +++ /dev/null @@ -1,7 +0,0 @@ -main (this Int, a Bool)! Void { - print(2, 2) -} - - -new function type syntax: -varName [this Player, Weapon]! -> Void diff --git a/test-parser/main.zn b/test-parser/main.zn index 83ad6d0b..6d4395c1 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,5 +1,5 @@ -main (this Int, a Bool)! Void?String { - x [this Int]! -> Void = "hello" +main Void?String (this Int, a Bool) mut { + x Void[this Int] = "hello" y String = "world" content String = read("wordlist.txt") ?? "" @@ -15,4 +15,4 @@ main (this Int, a Bool)! Void?String { } } -square (x Int, y Int) Int => x * y +square Int (x Int, y Int) => x * y From d6df90c02221f579f1d8f5bebf14da6147658880 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sun, 14 Jun 2026 18:52:33 +0200 Subject: [PATCH 113/154] add func/meth decl --- lib/cst/nodes.ml | 16 ++++++++++++++-- lib/cst/parser.mly | 31 ++++++++++++++++++++++++------- lib/cst/to_tree_graph.ml | 10 ++++++++-- test-parser/main.zn | 2 +- 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 18134202..3af3ed70 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -106,8 +106,20 @@ and meth_lambda = { } and decl = - | FuncDecl of { name: string; func: func_lambda } - | MethDecl of { name: string; func: meth_lambda } + | FuncDecl of { + name: string; + params: param list; + ret_type: ret_type; + body: body + } + | MethDecl of { + name: string; + this_type: type_expr; + params: param list; + ret_type: ret_type; + is_mut: bool; + body: body + } | VarDecl of { name: string; type_: type_expr; value: expr } | ConstructorDecl of { name: string; type_: type_expr; args: expr list } diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 45ba069a..63eb3c4f 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -72,13 +72,8 @@ package: %inline meth_lambda: | ret_type=ret_type "(" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", param))) - ")" body=body { - { Nodes.this_type; params; ret_type; is_mut=false; body } - } - | ret_type=ret_type "(" THIS this_type=type_expr - params=loption(preceded(",", separated_nonempty_list(",", param))) - ")" MUT body=body { - { Nodes.this_type; params; ret_type; is_mut=true; body } + ")" is_mut=boption(MUT) body=body { + { Nodes.this_type; params; ret_type; is_mut; body } } decl: @@ -102,6 +97,28 @@ decl: value=Nodes.MethLambda meth_lambda } } + | ret_type=ret_type name=LIDENT + "(" params=separated_list(COMMA, param) ")" body=body { + Nodes.FuncDecl { + name; + params; + ret_type; + body; + } + } + | ret_type=ret_type name=LIDENT + "(" THIS this_type=type_expr + params=loption(preceded(",", separated_nonempty_list(",", param))) + ")" is_mut=boption(MUT) body=body { + Nodes.MethDecl { + name; + this_type; + params; + ret_type; + is_mut; + body; + } + } %inline ret_type: | ret_type=type_expr { diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 5862651c..8e789cca 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -148,12 +148,18 @@ and decl_to_node (x: Nodes.decl) = match x with | FuncDecl x -> group "func_decl" (fields [ ("name", Leaf x.name); - ("func", func_lambda_to_node x.func); + ("param", params_to_node x.params); + ("ret_type", ret_to_node x.ret_type); + ("body", body_to_node x.body); ]) | MethDecl x -> group "meth_decl" (fields [ ("name", Leaf x.name); - ("func", meth_lambda_to_node x.func); + ("this_type", type_to_node x.this_type); + ("param", params_to_node x.params); + ("ret_type", ret_to_node x.ret_type); + ("body", body_to_node x.body); + ("is_mut", Leaf (string_of_bool x.is_mut)); ]) | VarDecl { name; type_; value } -> group "var_decl" (fields [ diff --git a/test-parser/main.zn b/test-parser/main.zn index 6d4395c1..491e264e 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,4 +1,4 @@ -main Void?String (this Int, a Bool) mut { +Void?String main (this Int, a Bool) mut { x Void[this Int] = "hello" y String = "world" content String = read("wordlist.txt") ?? "" From 43eb42085d340395ec9aad95ddc7269b1c936c7b Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sun, 14 Jun 2026 21:16:38 +0200 Subject: [PATCH 114/154] type and alias decls --- lib/cst/lexer.ml | 5 ++++- lib/cst/nodes.ml | 8 +++++++- lib/cst/parser.mly | 29 +++++++++++++++++++++++++++-- lib/cst/to_tree_graph.ml | 26 +++++++++++++++++++++++++- test-parser/main.zn | 2 ++ 5 files changed, 65 insertions(+), 5 deletions(-) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index ae034c35..f467172b 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -18,7 +18,6 @@ let upper_ident = [%sedlex.regexp? (uppercase | '_', uppercase), Star ident_char let rec token buf = match%sedlex buf with | Plus (' ' | '\t' | '\r' | '\n') -> token buf - | "->" -> THIN_ARROW | "=>" -> THICK_ARROW | "==" -> EQEQ | "<=" -> LESSEQ @@ -49,6 +48,10 @@ let rec token buf = | '"', Star str_char, '"' -> let s = Utf8.lexeme buf in STRING (String.sub s 1 (String.length s - 2)) + | "type" -> LTYPE + | "alias" -> ALIAS + | "Type" -> UTYPE + | "Number" -> NUMBER | "if" -> IF | "elif" -> ELIF | "else" -> ELSE diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 3af3ed70..a3b850ef 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -105,6 +105,10 @@ and meth_lambda = { body: body } +and type_param = + | Type of string + | Number of string + and decl = | FuncDecl of { name: string; @@ -121,7 +125,9 @@ and decl = body: body } | VarDecl of { name: string; type_: type_expr; value: expr } - | ConstructorDecl of { name: string; type_: type_expr; args: expr list } + | VarDeclShorthand of { name: string; type_: type_expr; args: expr list } + | TypeDecl of { name: string; params: type_param list option; value: type_expr } + | AliasDecl of { name: string; params: type_param list option; value: type_expr } type package = { decls: decl list diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 63eb3c4f..656546ff 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -26,13 +26,16 @@ %token QSTNMARK "?" %token QSTNQSTN "??" %token TILDE "~" -%token THIN_ARROW "->" %token THICK_ARROW "=>" %token EQEQ "==" %token LESSEQ "<=" %token MOREEQ ">=" %token LESS "<" %token MORE ">" +%token LTYPE "type" +%token ALIAS "alias" +%token UTYPE "Type" +%token NUMBER "Number" %token IF "if" %token ELIF "elif" %token ELSE "else" @@ -76,12 +79,20 @@ package: { Nodes.this_type; params; ret_type; is_mut; body } } +%inline type_param: + | name=UIDENT "Type" { + Nodes.Type name + } + | name=UIDENT "Number" { + Nodes.Number name + } + decl: | name=LIDENT type_=type_expr "=" value=expr { Nodes.VarDecl { name; type_; value } } | name=LIDENT type_=type_expr "(" args=separated_list(COMMA, expr) ")" { - Nodes.ConstructorDecl { name; type_; args } + Nodes.VarDeclShorthand { name; type_; args } } | name=LIDENT func_lambda=func_lambda { Nodes.VarDecl { @@ -119,6 +130,20 @@ decl: body; } } + | "type" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", type_param), ">")) "=" value=type_expr { + Nodes.TypeDecl { + name; + params; + value; + } + } + | "alias" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", type_param), ">")) "=" value=type_expr { + Nodes.AliasDecl { + name; + params; + value; + } + } %inline ret_type: | ret_type=type_expr { diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 8e789cca..4d31b41e 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -167,12 +167,36 @@ and decl_to_node (x: Nodes.decl) = match x with ("type", type_to_node type_); ("value", expr_to_node value); ]) - | ConstructorDecl { name; type_; args } -> + | VarDeclShorthand { name; type_; args } -> group "constructor_decl" (fields [ ("name", Leaf name); ("type", type_to_node type_); ("args", map_seq expr_to_node args); ]) + | TypeDecl x -> + let fs = [ + ("name", Leaf x.name); + ("value", type_to_node x.value); + ] in + let fs = match x.params with + | Some p -> ("params", map_seq type_param_to_node p) :: fs + | None -> fs + in + group "type_decl" (fields fs) + | AliasDecl x -> + let fs = [ + ("name", Leaf x.name); + ("value", type_to_node x.value); + ] in + let fs = match x.params with + | Some p -> ("params", map_seq type_param_to_node p) :: fs + | None -> fs + in + group "alias_decl" (fields fs) + +and type_param_to_node (x: Nodes.type_param) = match x with + | Type x ->group "generic_param" (Leaf x) + | Number x -> group "number_param" (Leaf x) let to_node ({ Nodes.decls } : Nodes.package) = group "package" (fields [ diff --git a/test-parser/main.zn b/test-parser/main.zn index 491e264e..99bf94fe 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,3 +1,5 @@ +type Vector = Vector + Void?String main (this Int, a Bool) mut { x Void[this Int] = "hello" y String = "world" From 3c30dbc065ccd166089f8ef15c0d12c45b8b20dc Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sun, 14 Jun 2026 22:31:07 +0200 Subject: [PATCH 115/154] type params --- lib/cst/nodes.ml | 31 +++++++++++++++++++++---------- lib/cst/parser.mly | 34 ++++++++++++++++++++++++++++------ lib/cst/to_tree_graph.ml | 29 ++++++++++++++++++++++------- test-parser/main.zn | 2 +- 4 files changed, 72 insertions(+), 24 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index a3b850ef..401d36f6 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -45,9 +45,11 @@ and func_call = | SafeCall of safe_call | AbortCall of abort_call -and type_expr = +and name_type = | SimpleType of string | QualifiedType of string * string + +and call_type = | FuncType of { params: type_expr list; ret_type: ret_type @@ -59,6 +61,15 @@ and type_expr = is_mut: bool } +and generic_arg = + | TypeArg of type_expr + | NumberArg of string + +and type_expr = + | NameType of name_type + | CallType of call_type + | GenericType of name_type * generic_arg list + and param = { name: string; type_: type_expr @@ -105,9 +116,9 @@ and meth_lambda = { body: body } -and type_param = - | Type of string - | Number of string +and generic_param = + | TypeParam of string + | NumberParam of string and decl = | FuncDecl of { @@ -126,23 +137,23 @@ and decl = } | VarDecl of { name: string; type_: type_expr; value: expr } | VarDeclShorthand of { name: string; type_: type_expr; args: expr list } - | TypeDecl of { name: string; params: type_param list option; value: type_expr } - | AliasDecl of { name: string; params: type_param list option; value: type_expr } + | TypeDecl of { name: string; params: generic_param list option; value: type_expr } + | AliasDecl of { name: string; params: generic_param list option; value: type_expr } type package = { decls: decl list } let func_type_of_lambda (x: func_lambda) : type_expr = - FuncType { + CallType (FuncType { params = List.map (fun (p: param) -> p.type_) x.params; ret_type = x.ret_type; -} + }) let meth_type_of_lambda (x: meth_lambda) : type_expr = - MethType { + CallType (MethType { this_type = x.this_type; params = List.map (fun (p: param) -> p.type_) x.params; ret_type = x.ret_type; is_mut = x.is_mut; - } + }) diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 656546ff..8f4a0196 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -79,12 +79,12 @@ package: { Nodes.this_type; params; ret_type; is_mut; body } } -%inline type_param: +%inline generic_param: | name=UIDENT "Type" { - Nodes.Type name + Nodes.TypeParam name } | name=UIDENT "Number" { - Nodes.Number name + Nodes.NumberParam name } decl: @@ -130,14 +130,14 @@ decl: body; } } - | "type" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", type_param), ">")) "=" value=type_expr { + | "type" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_expr { Nodes.TypeDecl { name; params; value; } } - | "alias" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", type_param), ">")) "=" value=type_expr { + | "alias" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_expr { Nodes.AliasDecl { name; params; @@ -205,9 +205,11 @@ stat: %inline param: | name=LIDENT type_=type_expr { { Nodes.name; type_ } } -type_expr: +%inline name_type: | name=UIDENT { Nodes.SimpleType name } | pkg=UIDENT name=UIDENT { Nodes.QualifiedType (pkg, name) } + +%inline call_type: | ret=ret_type "[" params=separated_list(",", type_expr) "]" { Nodes.FuncType { params; ret_type=ret } } @@ -222,6 +224,26 @@ type_expr: Nodes.MethType { this_type; params; ret_type=ret; is_mut=true } } +%inline generic_arg: + | type_expr=type_expr { + Nodes.TypeArg type_expr + } + | number=INT { + Nodes.NumberArg number + } + + +type_expr: + | name_type=name_type { + Nodes.NameType name_type + } + | call_type=call_type { + Nodes.CallType call_type + } + | name_type=name_type "<" params=separated_nonempty_list(",", generic_arg) ">" { + Nodes.GenericType (name_type, params) + } + expr: | int=INT { Nodes.IntLit int } | float=FLOAT { Nodes.FloatLit float } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 4d31b41e..6313d1ab 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -1,8 +1,10 @@ open Tree_graph -let rec type_to_node (x: Nodes.type_expr) = match x with +let rec name_type_to_node (x: Nodes.name_type) = match x with | SimpleType s -> Leaf s | QualifiedType (pkg, type_) -> Leaf (pkg ^ "$" ^ type_) + +and call_type_to_node (x: Nodes.call_type) = match x with | FuncType { params; ret_type } -> fields [ ("param", map_seq type_to_node params); @@ -16,6 +18,19 @@ let rec type_to_node (x: Nodes.type_expr) = match x with ("is_mut", Leaf (string_of_bool is_mut)); ] +and generic_arg_to_node (x: Nodes.generic_arg) = match x with + | TypeArg x -> type_to_node x + | NumberArg x -> group "number" (Leaf x) + +and type_to_node (x: Nodes.type_expr) = match x with + | NameType x -> name_type_to_node x + | CallType x -> call_type_to_node x + | GenericType (name, generics) -> + group "generic_type" (fields [ + ("name", name_type_to_node name); + ("args", map_seq generic_arg_to_node generics); + ]) + and expr_to_node (x: Nodes.expr) = match x with | IntLit x -> Leaf x | FloatLit x -> Leaf x @@ -168,7 +183,7 @@ and decl_to_node (x: Nodes.decl) = match x with ("value", expr_to_node value); ]) | VarDeclShorthand { name; type_; args } -> - group "constructor_decl" (fields [ + group "var_decl_shorthand" (fields [ ("name", Leaf name); ("type", type_to_node type_); ("args", map_seq expr_to_node args); @@ -179,7 +194,7 @@ and decl_to_node (x: Nodes.decl) = match x with ("value", type_to_node x.value); ] in let fs = match x.params with - | Some p -> ("params", map_seq type_param_to_node p) :: fs + | Some p -> ("params", map_seq generic_param_to_node p) :: fs | None -> fs in group "type_decl" (fields fs) @@ -189,14 +204,14 @@ and decl_to_node (x: Nodes.decl) = match x with ("value", type_to_node x.value); ] in let fs = match x.params with - | Some p -> ("params", map_seq type_param_to_node p) :: fs + | Some p -> ("params", map_seq generic_param_to_node p) :: fs | None -> fs in group "alias_decl" (fields fs) -and type_param_to_node (x: Nodes.type_param) = match x with - | Type x ->group "generic_param" (Leaf x) - | Number x -> group "number_param" (Leaf x) +and generic_param_to_node (x: Nodes.generic_param) = match x with + | TypeParam x ->group "type_param" (Leaf x) + | NumberParam x -> group "number_param" (Leaf x) let to_node ({ Nodes.decls } : Nodes.package) = group "package" (fields [ diff --git a/test-parser/main.zn b/test-parser/main.zn index 99bf94fe..9c8fcde1 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,4 +1,4 @@ -type Vector = Vector +type Vector = Vector Void?String main (this Int, a Bool) mut { x Void[this Int] = "hello" From 71c107c17b8251c255ac866a481e689a1485f744 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Mon, 15 Jun 2026 11:43:57 +0200 Subject: [PATCH 116/154] update --- lib/cst/lexer.ml | 6 ++++++ lib/cst/nodes.ml | 13 +++++++++++++ lib/cst/parser.mly | 31 ++++++++++++++++++++++++++++++- lib/cst/to_tree_graph.ml | 13 +++++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index f467172b..7fd47bc7 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -33,6 +33,7 @@ let rec token buf = | ']' -> RBRACKET | ',' -> COMMA | ':' -> COLON + | ';' -> SEMICOLON | '!' -> EXCL | "??" -> QSTNQSTN | '?' -> QSTNMARK @@ -52,6 +53,11 @@ let rec token buf = | "alias" -> ALIAS | "Type" -> UTYPE | "Number" -> NUMBER + | "class" -> CLASS + | "struct" -> STRUCT + | "variant" -> VARIANT + | "tuple" -> TUPLE + | "enum" -> ENUM | "if" -> IF | "elif" -> ELIF | "else" -> ELSE diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 401d36f6..16b513c2 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -61,6 +61,18 @@ and call_type = is_mut: bool } +and body_field = { + name: string; + type_: type_expr; +} + +and body_type = + | Class of body_field list + | Struct of body_field list + | Variant of body_field list + | Tuple of type_expr list + (* | Enum of type_expr list *) + and generic_arg = | TypeArg of type_expr | NumberArg of string @@ -69,6 +81,7 @@ and type_expr = | NameType of name_type | CallType of call_type | GenericType of name_type * generic_arg list + | BodyType of body_type and param = { name: string; diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 8f4a0196..aa03e8c0 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -14,7 +14,8 @@ %token RCURLY "}" %token LBRACKET "[" %token RBRACKET "]" -%token COLON +%token COLON ":" +%token SEMICOLON ";" %token EQUAL "=" %token PLUS "+" %token MINUS "-" @@ -36,6 +37,11 @@ %token ALIAS "alias" %token UTYPE "Type" %token NUMBER "Number" +%token CLASS "class" +%token STRUCT "struct" +%token VARIANT "variant" +%token TUPLE "tuple" +%token ENUM "enum" %token IF "if" %token ELIF "elif" %token ELSE "else" @@ -224,6 +230,26 @@ stat: Nodes.MethType { this_type; params; ret_type=ret; is_mut=true } } +%inline body_field: + | name=LIDENT type_=type_expr { + { Nodes.name; type_ } + } + +%inline body_type: + | CLASS "{" fields=separated_list(";", body_field) "}" { + Nodes.Class fields + } + | STRUCT "{" fields=separated_list(";", body_field) "}" { + Nodes.Struct fields + } + | VARIANT "{" fields=separated_list(";", body_field) "}" { + Nodes.Variant fields + } + | TUPLE "[" types=separated_list(",", type_expr) "]" { + Nodes.Tuple types + } + + %inline generic_arg: | type_expr=type_expr { Nodes.TypeArg type_expr @@ -243,6 +269,9 @@ type_expr: | name_type=name_type "<" params=separated_nonempty_list(",", generic_arg) ">" { Nodes.GenericType (name_type, params) } + | body_type=body_type { + Nodes.BodyType body_type + } expr: | int=INT { Nodes.IntLit int } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 6313d1ab..e81d2536 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -18,6 +18,18 @@ and call_type_to_node (x: Nodes.call_type) = match x with ("is_mut", Leaf (string_of_bool is_mut)); ] +and body_field_to_node (x: Nodes.body_field) = + group "body_field" (fields [ + ("name", Leaf x.name); + ("type", type_to_node x.type_); + ]) + +and body_type_to_node (x: Nodes.body_type) = match x with + | Class x -> group "class" (map_seq body_field_to_node x) + | Struct x -> group "struct" (map_seq body_field_to_node x) + | Variant x -> group "variant" (map_seq body_field_to_node x) + | Tuple x -> group "tuple" (map_seq type_to_node x) + and generic_arg_to_node (x: Nodes.generic_arg) = match x with | TypeArg x -> type_to_node x | NumberArg x -> group "number" (Leaf x) @@ -30,6 +42,7 @@ and type_to_node (x: Nodes.type_expr) = match x with ("name", name_type_to_node name); ("args", map_seq generic_arg_to_node generics); ]) + | BodyType x -> body_type_to_node x and expr_to_node (x: Nodes.expr) = match x with | IntLit x -> Leaf x From a5e0c305fe3370d3d956884f29b5551c993ec8a3 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Mon, 15 Jun 2026 16:27:06 +0200 Subject: [PATCH 117/154] update --- .claude/settings.local.json | 8 ++++++++ lib/cst/parser.mly | 10 +++++----- test-parser/main.zn | 5 ++++- 3 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 .claude/settings.local.json diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 00000000..2f398ec3 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "WebFetch(domain:github.com)", + "WebFetch(domain:raw.githubusercontent.com)" + ] + } +} diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index aa03e8c0..544b4423 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -231,18 +231,18 @@ stat: } %inline body_field: - | name=LIDENT type_=type_expr { - { Nodes.name; type_ } + | name=LIDENT type_=type_expr ";" { + ({ Nodes.name; type_ } : Nodes.body_field) } %inline body_type: - | CLASS "{" fields=separated_list(";", body_field) "}" { + | CLASS "{" fields=list(body_field) "}" { Nodes.Class fields } - | STRUCT "{" fields=separated_list(";", body_field) "}" { + | STRUCT "{" fields=list(body_field) "}" { Nodes.Struct fields } - | VARIANT "{" fields=separated_list(";", body_field) "}" { + | VARIANT "{" fields=list(body_field) "}" { Nodes.Variant fields } | TUPLE "[" types=separated_list(",", type_expr) "]" { diff --git a/test-parser/main.zn b/test-parser/main.zn index 9c8fcde1..60f53a63 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -1,4 +1,7 @@ -type Vector = Vector +type Vector2 = struct { + x T; + y T; +} Void?String main (this Int, a Bool) mut { x Void[this Int] = "hello" From d2cd961ba800b2c3dc3a4a05101927fa2d3c94f8 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Mon, 15 Jun 2026 17:30:47 +0200 Subject: [PATCH 118/154] add enums --- lib/cst/nodes.ml | 2 +- lib/cst/parser.mly | 3 +++ lib/cst/to_tree_graph.ml | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 16b513c2..2851822f 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -71,7 +71,7 @@ and body_type = | Struct of body_field list | Variant of body_field list | Tuple of type_expr list - (* | Enum of type_expr list *) + | Enum of string list and generic_arg = | TypeArg of type_expr diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 544b4423..695feaf7 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -245,6 +245,9 @@ stat: | VARIANT "{" fields=list(body_field) "}" { Nodes.Variant fields } + | ENUM "[" cases=separated_list(",", LIDENT) "]" { + Nodes.Enum cases + } | TUPLE "[" types=separated_list(",", type_expr) "]" { Nodes.Tuple types } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index e81d2536..5bbb9b15 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -28,6 +28,7 @@ and body_type_to_node (x: Nodes.body_type) = match x with | Class x -> group "class" (map_seq body_field_to_node x) | Struct x -> group "struct" (map_seq body_field_to_node x) | Variant x -> group "variant" (map_seq body_field_to_node x) + | Enum x -> group "enum" (map_seq (fun x -> Leaf x) x) | Tuple x -> group "tuple" (map_seq type_to_node x) and generic_arg_to_node (x: Nodes.generic_arg) = match x with From 10d205f49ec3ff1f8eeef6df216b099fa254ac6d Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Mon, 15 Jun 2026 22:11:00 +0200 Subject: [PATCH 119/154] update --- lib/cst/lexer.ml | 5 ++++- lib/cst/nodes.ml | 8 ++++++++ lib/cst/parser.mly | 12 ++++++++++++ lib/cst/to_tree_graph.ml | 33 +++++++++++++++++++++++---------- test-parser/main.zn | 4 ++++ todo.md | 5 +++++ 6 files changed, 56 insertions(+), 11 deletions(-) create mode 100644 todo.md diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index 7fd47bc7..6ed642c0 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -43,6 +43,7 @@ let rec token buf = | '*' -> STAR | '/' -> SLASH | '$' -> DOLLAR + | '&' -> AND | '@' -> AT | float_lit -> FLOAT (Utf8.lexeme buf) | int_lit -> INT (Utf8.lexeme buf) @@ -61,7 +62,9 @@ let rec token buf = | "if" -> IF | "elif" -> ELIF | "else" -> ELSE - (* | "loop" -> LOOP *) + | "loop" -> LOOP + | "from" -> FROM + | "to" -> TO | "true" -> TRUE | "false" -> FALSE | "this" -> THIS diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 2851822f..2fd754ae 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -99,6 +99,13 @@ and cond_seq = { else_: stat list option; } +and loop = { + start: expr option; + end_: expr; + binder: string; + body: stat list; +} + and stat = | FuncCallStat of func_call | DeclStat of decl @@ -106,6 +113,7 @@ and stat = | RetStat of expr | ResolveStat of expr | CondSeq of cond_seq + | Loop of loop and body = | Scope of stat list diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 695feaf7..1faa24cb 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -22,6 +22,7 @@ %token STAR "*" %token SLASH "/" %token DOLLAR "$" +%token AND "&" %token AT "@" %token EXCL "!" %token QSTNMARK "?" @@ -46,6 +47,9 @@ %token ELIF "elif" %token ELSE "else" %token TRUE "true" +%token LOOP "loop" +%token FROM "from" +%token TO "to" %token FALSE "false" %token THIS "this" %token MUT "mut" @@ -190,6 +194,11 @@ func_call: statements } +%inline loop: + | LOOP binder=LIDENT start=ioption(preceded(FROM, expr)) TO end_=expr "{" statements=list(stat) "}" { + ({ start; end_; binder; body=statements; }: Nodes.loop) + } + stat: | decl=decl { Nodes.DeclStat decl } | func_call=func_call { @@ -207,6 +216,9 @@ stat: | if_=if_ elifs_=list(elif_) else_=ioption(else_) { Nodes.CondSeq { if_; elifs_; else_ } } + | loop=loop { + Nodes.Loop loop + } %inline param: | name=LIDENT type_=type_expr { { Nodes.name; type_ } } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 5bbb9b15..563852fc 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -70,7 +70,7 @@ and expr_to_node (x: Nodes.expr) = match x with | MethLambda x -> group "meth_lambda" (meth_lambda_to_node x) -and op_to_name (x : Nodes.operator) = match x with +and op_to_name (x: Nodes.operator) = match x with | Add -> "+" | Sub -> "-" | Mul -> "*" @@ -81,7 +81,7 @@ and op_to_name (x : Nodes.operator) = match x with | Less -> "<" | More -> ">" -and abort_handle_to_node (x : Nodes.abort_handle) = match x with +and abort_handle_to_node (x: Nodes.abort_handle) = match x with | AbortBody x -> body_to_node x | AbortShorthand x -> expr_to_node x @@ -103,13 +103,13 @@ and func_call_to_node x = match x with in group "function_call" (fields fs) -and param_to_node (x : Nodes.param) = +and param_to_node (x: Nodes.param) = fields [ ("name", Leaf x.name); ("type", type_to_node x.type_); ] -and params_to_node (x : Nodes.param list) = +and params_to_node (x: Nodes.param list) = map_seq param_to_node x and elif_to_fields (x: Nodes.cond_block) = @@ -133,15 +133,28 @@ and cond_seq_to_node (x: Nodes.cond_seq) = | None -> cond_seq in group "cond_seq" (fields cond_seq) -and stat_to_node (x : Nodes.stat) = match x with +and loop_to_node (x: Nodes.loop) = + let fs = [ + ("stats", map_seq stat_to_node x.body); + ("end", expr_to_node x.end_); + ("binder", Leaf x.binder); + ] in + let fs = match x.start with + | Some x -> ("start", expr_to_node x) :: fs + | None -> fs + in + group "loop_stat" (fields fs) + +and stat_to_node (x: Nodes.stat) = match x with | FuncCallStat x -> func_call_to_node x | DeclStat x -> decl_to_node x | AbortStat x -> group "abort_stat" (expr_to_node x) | RetStat x -> group "ret_stat" (expr_to_node x) | ResolveStat x -> group "resolve_stat" (expr_to_node x) | CondSeq x -> cond_seq_to_node x + | Loop x -> loop_to_node x -and body_to_node (x : Nodes.body) = match x with +and body_to_node (x: Nodes.body) = match x with | Scope scope -> group "scope" (fields [ ("stat", map_seq stat_to_node scope); @@ -149,7 +162,7 @@ and body_to_node (x : Nodes.body) = match x with | RetShorthand x -> group "ret_shorthand" (expr_to_node x) -and ret_to_node (x : Nodes.ret_type) = match x with +and ret_to_node (x: Nodes.ret_type) = match x with | SafeRet ret -> type_to_node ret | AbortRet (ret_type, abort_type) -> fields [ @@ -157,14 +170,14 @@ and ret_to_node (x : Nodes.ret_type) = match x with ("abort_type", type_to_node abort_type); ] -and func_lambda_to_node (x : Nodes.func_lambda) = +and func_lambda_to_node (x: Nodes.func_lambda) = fields [ ("param", params_to_node x.params); ("ret_type", ret_to_node x.ret_type); ("body", body_to_node x.body); ] -and meth_lambda_to_node (x : Nodes.meth_lambda) = +and meth_lambda_to_node (x: Nodes.meth_lambda) = fields [ ("this_type", type_to_node x.this_type); ("param", params_to_node x.params); @@ -227,7 +240,7 @@ and generic_param_to_node (x: Nodes.generic_param) = match x with | TypeParam x ->group "type_param" (Leaf x) | NumberParam x -> group "number_param" (Leaf x) -let to_node ({ Nodes.decls } : Nodes.package) = +let to_node ({ Nodes.decls }: Nodes.package) = group "package" (fields [ ("declarations", map_seq decl_to_node decls); ]) diff --git a/test-parser/main.zn b/test-parser/main.zn index 60f53a63..d2a89962 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -18,6 +18,10 @@ Void?String main (this Int, a Bool) mut { rifle Weapon("rifle", 20) value Bool = ~true + 3 } + + loop i to 3 { + print(i) + } } square Int (x Int, y Int) => x * y diff --git a/todo.md b/todo.md new file mode 100644 index 00000000..45629320 --- /dev/null +++ b/todo.md @@ -0,0 +1,5 @@ +ConstructorDecl +OpDecl +MethodCall + +rename callables to verb From 39568e47cae1c0d677779ffa0c19c92866127035 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 16 Jun 2026 18:00:09 +0200 Subject: [PATCH 120/154] add ref types --- lib/cst/nodes.ml | 10 +++++++--- lib/cst/parser.mly | 25 ++++++++++++++----------- lib/cst/to_tree_graph.ml | 11 ++++++++--- test-parser/main.zn | 2 +- todo.md | 1 + 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 2fd754ae..a2217ce2 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -77,11 +77,15 @@ and generic_arg = | TypeArg of type_expr | NumberArg of string -and type_expr = +and refable = + | BodyType of body_type | NameType of name_type - | CallType of call_type | GenericType of name_type * generic_arg list - | BodyType of body_type + +and type_expr = + | CallType of call_type + | NormalType of refable + | RefType of refable and param = { name: string; diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 1faa24cb..2c352e19 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -231,15 +231,10 @@ stat: | ret=ret_type "[" params=separated_list(",", type_expr) "]" { Nodes.FuncType { params; ret_type=ret } } - | ret=ret_type "[" THIS this_type=type_expr - params=loption(preceded(",", separated_nonempty_list(",", type_expr))) - "]" { - Nodes.MethType { this_type; params; ret_type=ret; is_mut=false } - } | ret=ret_type "[" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", type_expr))) - "]" MUT { - Nodes.MethType { this_type; params; ret_type=ret; is_mut=true } + "]" is_mut=boption(MUT) { + Nodes.MethType { this_type; params; ret_type=ret; is_mut } } %inline body_field: @@ -274,13 +269,10 @@ stat: } -type_expr: +refable: | name_type=name_type { Nodes.NameType name_type } - | call_type=call_type { - Nodes.CallType call_type - } | name_type=name_type "<" params=separated_nonempty_list(",", generic_arg) ">" { Nodes.GenericType (name_type, params) } @@ -288,6 +280,17 @@ type_expr: Nodes.BodyType body_type } +type_expr: + | call_type=call_type { + Nodes.CallType call_type + } + | refable=refable { + Nodes.NormalType refable + } + | "&" refable=refable { + Nodes.RefType refable + } + expr: | int=INT { Nodes.IntLit int } | float=FLOAT { Nodes.FloatLit float } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 563852fc..170abcab 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -35,15 +35,20 @@ and generic_arg_to_node (x: Nodes.generic_arg) = match x with | TypeArg x -> type_to_node x | NumberArg x -> group "number" (Leaf x) -and type_to_node (x: Nodes.type_expr) = match x with - | NameType x -> name_type_to_node x - | CallType x -> call_type_to_node x +and refable_to_node (x: Nodes.refable) = match x with | GenericType (name, generics) -> group "generic_type" (fields [ ("name", name_type_to_node name); ("args", map_seq generic_arg_to_node generics); ]) | BodyType x -> body_type_to_node x + | NameType x -> name_type_to_node x + + +and type_to_node (x: Nodes.type_expr) = match x with + | CallType x -> call_type_to_node x + | NormalType x -> refable_to_node x + | RefType x -> group "ref_type" (refable_to_node x) and expr_to_node (x: Nodes.expr) = match x with | IntLit x -> Leaf x diff --git a/test-parser/main.zn b/test-parser/main.zn index d2a89962..b26183e3 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -6,7 +6,7 @@ type Vector2 = struct { Void?String main (this Int, a Bool) mut { x Void[this Int] = "hello" y String = "world" - content String = read("wordlist.txt") ?? "" + content &String = read("wordlist.txt") ?? "" if random() { results List = crawl(content) ? error { diff --git a/todo.md b/todo.md index 45629320..7bae631c 100644 --- a/todo.md +++ b/todo.md @@ -3,3 +3,4 @@ OpDecl MethodCall rename callables to verb +refs From ab268266efb85886e17048e0616c332ec0400742 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 17 Jun 2026 15:06:59 +0200 Subject: [PATCH 121/154] generic params for verbs --- lib/cst/nodes.ml | 19 +++++++++++++------ lib/cst/parser.mly | 34 ++++++++++++++++++++++++++-------- lib/cst/to_tree_graph.ml | 22 ++++++++++++++++------ 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index a2217ce2..8a7652ab 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -51,12 +51,12 @@ and name_type = and call_type = | FuncType of { - params: type_expr list; + params: param_type list; ret_type: ret_type } | MethType of { this_type: type_expr; - params: type_expr list; + params: param_type list; ret_type: ret_type; is_mut: bool } @@ -87,9 +87,13 @@ and type_expr = | NormalType of refable | RefType of refable +and param_type = + | NormalParam of type_expr + | GenericParam of generic_param_type + and param = { name: string; - type_: type_expr + type_: param_type } and cond_block = { @@ -141,9 +145,12 @@ and meth_lambda = { body: body } -and generic_param = - | TypeParam of string - | NumberParam of string +and generic_param_type = TypeParam | NumberParam + +and generic_param = { + name: string; + type_: generic_param_type; +} and decl = | FuncDecl of { diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 2c352e19..6c31eafa 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -89,12 +89,17 @@ package: { Nodes.this_type; params; ret_type; is_mut; body } } -%inline generic_param: - | name=UIDENT "Type" { - Nodes.TypeParam name +%inline generic_param_type: + | "Type" { + Nodes.TypeParam } - | name=UIDENT "Number" { - Nodes.NumberParam name + | "Number" { + Nodes.NumberParam + } + +%inline generic_param: + | name=UIDENT type_=generic_param_type { + ({ name; type_ }: Nodes.generic_param) } decl: @@ -220,19 +225,32 @@ stat: Nodes.Loop loop } +%inline param_type: + | type_=type_expr { + Nodes.NormalParam type_ + } + | type_=generic_param_type { + Nodes.GenericParam type_ + } + %inline param: - | name=LIDENT type_=type_expr { { Nodes.name; type_ } } + | name=LIDENT type_=type_expr { + ({ Nodes.name; type_=Nodes.NormalParam type_ }: Nodes.param) + } + | name=UIDENT type_=generic_param_type { + ({ Nodes.name; type_=Nodes.GenericParam type_ }: Nodes.param) + } %inline name_type: | name=UIDENT { Nodes.SimpleType name } | pkg=UIDENT name=UIDENT { Nodes.QualifiedType (pkg, name) } %inline call_type: - | ret=ret_type "[" params=separated_list(",", type_expr) "]" { + | ret=ret_type "[" params=separated_list(",", param_type) "]" { Nodes.FuncType { params; ret_type=ret } } | ret=ret_type "[" THIS this_type=type_expr - params=loption(preceded(",", separated_nonempty_list(",", type_expr))) + params=loption(preceded(",", separated_nonempty_list(",", param_type))) "]" is_mut=boption(MUT) { Nodes.MethType { this_type; params; ret_type=ret; is_mut } } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 170abcab..499ef5bd 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -4,16 +4,24 @@ let rec name_type_to_node (x: Nodes.name_type) = match x with | SimpleType s -> Leaf s | QualifiedType (pkg, type_) -> Leaf (pkg ^ "$" ^ type_) +and generic_param_type_to_node (x: Nodes.generic_param_type) = match x with + | TypeParam -> Leaf "Type" + | NumberParam -> Leaf "Number" + +and param_type_to_node (x: Nodes.param_type) = match x with + | NormalParam x -> type_to_node x + | GenericParam x -> generic_param_type_to_node x + and call_type_to_node (x: Nodes.call_type) = match x with | FuncType { params; ret_type } -> fields [ - ("param", map_seq type_to_node params); + ("param", map_seq param_type_to_node params); ("type", ret_to_node ret_type); ] | MethType { this_type; params; ret_type; is_mut } -> fields [ ("this_type", type_to_node this_type); - ("param", map_seq type_to_node params); + ("param", map_seq param_type_to_node params); ("type", ret_to_node ret_type); ("is_mut", Leaf (string_of_bool is_mut)); ] @@ -111,7 +119,7 @@ and func_call_to_node x = match x with and param_to_node (x: Nodes.param) = fields [ ("name", Leaf x.name); - ("type", type_to_node x.type_); + ("type", param_type_to_node x.type_); ] and params_to_node (x: Nodes.param list) = @@ -241,9 +249,11 @@ and decl_to_node (x: Nodes.decl) = match x with in group "alias_decl" (fields fs) -and generic_param_to_node (x: Nodes.generic_param) = match x with - | TypeParam x ->group "type_param" (Leaf x) - | NumberParam x -> group "number_param" (Leaf x) +and generic_param_to_node (x: Nodes.generic_param) = + fields [ + ("name", Leaf x.name); + ("type", generic_param_type_to_node x.type_); + ] let to_node ({ Nodes.decls }: Nodes.package) = group "package" (fields [ From 9958d31cae58bc5ea50367dbee005ba53220e657 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 17 Jun 2026 15:22:10 +0200 Subject: [PATCH 122/154] constructor decl --- lib/cst/nodes.ml | 5 +++++ lib/cst/parser.mly | 8 ++++++++ lib/cst/to_tree_graph.ml | 6 ++++++ todo.md | 2 +- 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 8a7652ab..aa5db402 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -167,6 +167,11 @@ and decl = is_mut: bool; body: body } + | ConstructorDecl of { + type_: name_type; + params: param list; + body: body + } | VarDecl of { name: string; type_: type_expr; value: expr } | VarDeclShorthand of { name: string; type_: type_expr; args: expr list } | TypeDecl of { name: string; params: generic_param list option; value: type_expr } diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 6c31eafa..86e3a9ef 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -145,6 +145,14 @@ decl: body; } } + | type_=name_type + "(" params=separated_list(COMMA, param) ")" body=body { + Nodes.ConstructorDecl { + type_; + params; + body; + } + } | "type" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_expr { Nodes.TypeDecl { name; diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 499ef5bd..446acd51 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -216,6 +216,12 @@ and decl_to_node (x: Nodes.decl) = match x with ("body", body_to_node x.body); ("is_mut", Leaf (string_of_bool x.is_mut)); ]) + | ConstructorDecl x -> + group "meth_decl" (fields [ + ("type", name_type_to_node x.type_); + ("param", params_to_node x.params); + ("body", body_to_node x.body); + ]) | VarDecl { name; type_; value } -> group "var_decl" (fields [ ("name", Leaf name); diff --git a/todo.md b/todo.md index 7bae631c..bebef300 100644 --- a/todo.md +++ b/todo.md @@ -3,4 +3,4 @@ OpDecl MethodCall rename callables to verb -refs +x refs From 0582431d9ed4641c89d04bf0906ec0e9923bdd7d Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 17 Jun 2026 15:31:05 +0200 Subject: [PATCH 123/154] name type for vardecl shorthand --- lib/cst/nodes.ml | 2 +- lib/cst/parser.mly | 6 +++--- lib/cst/to_tree_graph.ml | 2 +- test-parser/main.zn | 5 +++-- todo.md | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index aa5db402..3e421a26 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -173,7 +173,7 @@ and decl = body: body } | VarDecl of { name: string; type_: type_expr; value: expr } - | VarDeclShorthand of { name: string; type_: type_expr; args: expr list } + | VarDeclShorthand of { name: string; type_: name_type; args: expr list } | TypeDecl of { name: string; params: generic_param list option; value: type_expr } | AliasDecl of { name: string; params: generic_param list option; value: type_expr } diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 86e3a9ef..fffce091 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -106,7 +106,7 @@ decl: | name=LIDENT type_=type_expr "=" value=expr { Nodes.VarDecl { name; type_; value } } - | name=LIDENT type_=type_expr "(" args=separated_list(COMMA, expr) ")" { + | name=LIDENT type_=name_type "(" args=separated_list(COMMA, expr) ")" { Nodes.VarDeclShorthand { name; type_; args } } | name=LIDENT func_lambda=func_lambda { @@ -251,7 +251,7 @@ stat: %inline name_type: | name=UIDENT { Nodes.SimpleType name } - | pkg=UIDENT name=UIDENT { Nodes.QualifiedType (pkg, name) } + | pkg=LIDENT "$" name=UIDENT { Nodes.QualifiedType (pkg, name) } %inline call_type: | ret=ret_type "[" params=separated_list(",", param_type) "]" { @@ -324,7 +324,7 @@ expr: | TRUE { Nodes.BoolLit true } | FALSE { Nodes.BoolLit false } | ident=LIDENT { Nodes.Ident ident } - | pkg=UIDENT "$" ident=LIDENT { Nodes.QualifiedIdent (pkg, ident) } + | pkg=LIDENT "$" ident=LIDENT { Nodes.QualifiedIdent (pkg, ident) } | e1=expr "+" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Add } } | e1=expr "-" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Sub } } | e1=expr "*" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Mul } } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 446acd51..98f7e306 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -231,7 +231,7 @@ and decl_to_node (x: Nodes.decl) = match x with | VarDeclShorthand { name; type_; args } -> group "var_decl_shorthand" (fields [ ("name", Leaf name); - ("type", type_to_node type_); + ("type", name_type_to_node type_); ("args", map_seq expr_to_node args); ]) | TypeDecl x -> diff --git a/test-parser/main.zn b/test-parser/main.zn index b26183e3..c33c83bf 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -7,10 +7,11 @@ Void?String main (this Int, a Bool) mut { x Void[this Int] = "hello" y String = "world" content &String = read("wordlist.txt") ?? "" + x Int(3) if random() { results List = crawl(content) ? error { - Std$print(error) + std$print(error) abort error } } @@ -20,7 +21,7 @@ Void?String main (this Int, a Bool) mut { } loop i to 3 { - print(i) + std$print(i) } } diff --git a/todo.md b/todo.md index bebef300..8958bcf5 100644 --- a/todo.md +++ b/todo.md @@ -1,4 +1,4 @@ -ConstructorDecl +x ConstructorDecl OpDecl MethodCall From 9ded79d85aa04d089f83b2c4372e3a2568b05d5a Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Mon, 22 Jun 2026 14:14:40 +0200 Subject: [PATCH 124/154] add inferred generics --- lib/cst/nodes.ml | 12 +++++++++++ lib/cst/parser.mly | 44 ++++++++++++++++++++++++++++++++-------- lib/cst/to_tree_graph.ml | 18 ++++++++++++++++ test-parser/main.zn | 4 ++++ 4 files changed, 69 insertions(+), 9 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 3e421a26..81197689 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -89,6 +89,7 @@ and type_expr = and param_type = | NormalParam of type_expr + | InfGenericParam of { type_: name_type; generics: generic_param list } | GenericParam of generic_param_type and param = { @@ -167,6 +168,17 @@ and decl = is_mut: bool; body: body } + | OpDecl of { + op: operator; + params: param list; + ret_type: ret_type; + body: body + } + | FlipDecl of { + params: param list; + ret_type: ret_type; + body: body + } | ConstructorDecl of { type_: name_type; params: param list; diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index fffce091..c2355ccf 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -153,6 +153,21 @@ decl: body; } } + | ret_type=ret_type op=operator "(" params=separated_list(COMMA, param) ")" body=body { + Nodes.OpDecl { + op; + params; + ret_type; + body; + } + } + | ret_type=ret_type "~" "(" params=separated_list(COMMA, param) ")" body=body { + Nodes.FlipDecl { + params; + ret_type; + body; + } + } | "type" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_expr { Nodes.TypeDecl { name; @@ -237,6 +252,10 @@ stat: | type_=type_expr { Nodes.NormalParam type_ } + | type_=name_type "<" + generics=separated_nonempty_list(",", generic_param) ">" { + Nodes.InfGenericParam {type_; generics} + } | type_=generic_param_type { Nodes.GenericParam type_ } @@ -245,6 +264,10 @@ stat: | name=LIDENT type_=type_expr { ({ Nodes.name; type_=Nodes.NormalParam type_ }: Nodes.param) } + | name=LIDENT type_=name_type "<" + generics=separated_nonempty_list(",", generic_param) ">" { + ({ Nodes.name; type_=Nodes.InfGenericParam {type_; generics}}: Nodes.param) + } | name=UIDENT type_=generic_param_type { ({ Nodes.name; type_=Nodes.GenericParam type_ }: Nodes.param) } @@ -317,6 +340,17 @@ type_expr: Nodes.RefType refable } +operator: + | "+" { Nodes.Add } + | "-" { Nodes.Sub } + | "*" { Nodes.Mul } + | "/" { Nodes.Div } + | "=="{ Nodes.Eq } + | "<="{ Nodes.LessEq } + | ">="{ Nodes.MoreEq } + | "<" { Nodes.Less } + | ">" { Nodes.More } + expr: | int=INT { Nodes.IntLit int } | float=FLOAT { Nodes.FloatLit float } @@ -325,15 +359,7 @@ expr: | FALSE { Nodes.BoolLit false } | ident=LIDENT { Nodes.Ident ident } | pkg=LIDENT "$" ident=LIDENT { Nodes.QualifiedIdent (pkg, ident) } - | e1=expr "+" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Add } } - | e1=expr "-" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Sub } } - | e1=expr "*" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Mul } } - | e1=expr "/" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Div } } - | e1=expr "==" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Eq } } - | e1=expr "<=" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.LessEq } } - | e1=expr ">=" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.MoreEq } } - | e1=expr "<" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.Less } } - | e1=expr ">" e2=expr { Nodes.Op { left=e1; right=e2; operator=Nodes.More } } + | e1=expr op=operator e2=expr { Nodes.Op { left=e1; right=e2; operator=op } } | "~" value=expr %prec TILDE { Nodes.Flip value } | "(" e=expr ")" { Nodes.Parenthized e } | func_call=func_call { diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 98f7e306..685611bb 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -10,6 +10,11 @@ and generic_param_type_to_node (x: Nodes.generic_param_type) = match x with and param_type_to_node (x: Nodes.param_type) = match x with | NormalParam x -> type_to_node x + | InfGenericParam x -> + group "InfGenericParam" (fields [ + ("type", name_type_to_node x.type_); + ("generics", map_seq generic_param_to_node x.generics); + ]) | GenericParam x -> generic_param_type_to_node x and call_type_to_node (x: Nodes.call_type) = match x with @@ -234,6 +239,19 @@ and decl_to_node (x: Nodes.decl) = match x with ("type", name_type_to_node type_); ("args", map_seq expr_to_node args); ]) + | OpDecl x -> + group "op_decl" (fields [ + ("op", Leaf (op_to_name x.op)); + ("param", params_to_node x.params); + ("ret_type", ret_to_node x.ret_type); + ("body", body_to_node x.body); + ]) + | FlipDecl x -> + group "flip_decl" (fields [ + ("param", params_to_node x.params); + ("ret_type", ret_to_node x.ret_type); + ("body", body_to_node x.body); + ]) | TypeDecl x -> let fs = [ ("name", Leaf x.name); diff --git a/test-parser/main.zn b/test-parser/main.zn index c33c83bf..f212d5b6 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -3,6 +3,10 @@ type Vector2 = struct { y T; } +Vector2 +(left Vector2, right Vector2) { + return Vector2(left.x + right.x, left.y + right.y) +} + Void?String main (this Int, a Bool) mut { x Void[this Int] = "hello" y String = "world" From 7f40c208860c05978c3460de796b50d0cf9ec32f Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Mon, 22 Jun 2026 14:57:09 +0200 Subject: [PATCH 125/154] update --- lib/cst/lexer.ml | 1 + lib/cst/nodes.ml | 2 ++ lib/cst/parser.mly | 15 ++++++++++++++- lib/cst/to_tree_graph.ml | 22 ++++++++++++++++++---- todo.md | 4 ++-- 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index 6ed642c0..1601f10c 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -32,6 +32,7 @@ let rec token buf = | '[' -> LBRACKET | ']' -> RBRACKET | ',' -> COMMA + | '.' -> DOT | ':' -> COLON | ';' -> SEMICOLON | '!' -> EXCL diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 81197689..5e6868df 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -20,6 +20,8 @@ type expr = | QualifiedIdent of string * string | Op of { left: expr; right: expr; operator: operator } | Flip of expr + | DotAccess of expr * string + | ConstructorCall of { type_: name_type; args: expr list } | Parenthized of expr | FuncCall of func_call | FuncLambda of func_lambda diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index c2355ccf..60b22be7 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -16,6 +16,7 @@ %token RBRACKET "]" %token COLON ":" %token SEMICOLON ";" +%token DOT "." %token EQUAL "=" %token PLUS "+" %token MINUS "-" @@ -66,6 +67,7 @@ %nonassoc IF %nonassoc ELSE %nonassoc TILDE /* prefix ~ */ +%left DOT /* field access */ %start package @@ -359,8 +361,19 @@ expr: | FALSE { Nodes.BoolLit false } | ident=LIDENT { Nodes.Ident ident } | pkg=LIDENT "$" ident=LIDENT { Nodes.QualifiedIdent (pkg, ident) } - | e1=expr op=operator e2=expr { Nodes.Op { left=e1; right=e2; operator=op } } + | e1=expr "+" e2=expr %prec PLUS { Nodes.Op { left=e1; right=e2; operator=Nodes.Add } } + | e1=expr "-" e2=expr %prec MINUS { Nodes.Op { left=e1; right=e2; operator=Nodes.Sub } } + | e1=expr "*" e2=expr %prec STAR { Nodes.Op { left=e1; right=e2; operator=Nodes.Mul } } + | e1=expr "/" e2=expr %prec SLASH { Nodes.Op { left=e1; right=e2; operator=Nodes.Div } } + | e1=expr "==" e2=expr %prec EQEQ { Nodes.Op { left=e1; right=e2; operator=Nodes.Eq } } + | e1=expr "<=" e2=expr %prec LESSEQ { Nodes.Op { left=e1; right=e2; operator=Nodes.LessEq } } + | e1=expr ">=" e2=expr %prec MOREEQ { Nodes.Op { left=e1; right=e2; operator=Nodes.MoreEq } } + | e1=expr "<" e2=expr %prec LESS { Nodes.Op { left=e1; right=e2; operator=Nodes.Less } } + | e1=expr ">" e2=expr %prec MORE { Nodes.Op { left=e1; right=e2; operator=Nodes.More } } | "~" value=expr %prec TILDE { Nodes.Flip value } + | value=expr "." field=LIDENT %prec DOT { Nodes.DotAccess (value, field) } + | type_=name_type "(" args=separated_list(COMMA, expr) ")" %prec LPAREN + { Nodes.ConstructorCall { type_; args } } | "(" e=expr ")" { Nodes.Parenthized e } | func_call=func_call { Nodes.FuncCall func_call diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 685611bb..2b63f6d3 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -71,12 +71,26 @@ and expr_to_node (x: Nodes.expr) = match x with | Ident x -> Leaf x | QualifiedIdent (pkg, name) -> Leaf (pkg ^ "$" ^ name) | Op x -> - fields [ - (op_to_name x.operator, fields [ + group (op_to_name x.operator) ( + fields [ ("left", expr_to_node x.left); ("right", expr_to_node x.right); - ]); - ] + ] + ) + | DotAccess (value, field) -> + group "dot_access" ( + fields [ + ("value", expr_to_node value); + ("field", Leaf field); + ] + ) + | ConstructorCall x -> + group "constructor_call" ( + fields [ + ("type", name_type_to_node x.type_); + ("args", map_seq expr_to_node x.args); + ] + ) | Flip x -> group "flip" (expr_to_node x) | Parenthized x -> diff --git a/todo.md b/todo.md index 8958bcf5..68dbd128 100644 --- a/todo.md +++ b/todo.md @@ -1,6 +1,6 @@ x ConstructorDecl -OpDecl +x OpDecl MethodCall -rename callables to verb +x rename callables to verb x refs From 08eeab2da66d0817a26b62e8881ec2055de73c39 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Tue, 23 Jun 2026 15:58:51 +0200 Subject: [PATCH 126/154] update --- lib/cst/nodes.ml | 5 ++++- lib/cst/parser.mly | 12 ++++-------- lib/cst/to_tree_graph.ml | 5 ----- test-parser/main.zn | 2 +- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 5e6868df..e266866d 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -91,7 +91,6 @@ and type_expr = and param_type = | NormalParam of type_expr - | InfGenericParam of { type_: name_type; generics: generic_param list } | GenericParam of generic_param_type and param = { @@ -158,12 +157,14 @@ and generic_param = { and decl = | FuncDecl of { name: string; + generic_header: generic_param list option; params: param list; ret_type: ret_type; body: body } | MethDecl of { name: string; + generic_header: generic_param list option; this_type: type_expr; params: param list; ret_type: ret_type; @@ -172,11 +173,13 @@ and decl = } | OpDecl of { op: operator; + generic_header: generic_param list option; params: param list; ret_type: ret_type; body: body } | FlipDecl of { + generic_header: generic_param list option; params: param list; ret_type: ret_type; body: body diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 60b22be7..98dba386 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -126,20 +126,24 @@ decl: } } | ret_type=ret_type name=LIDENT + generic_header=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "(" params=separated_list(COMMA, param) ")" body=body { Nodes.FuncDecl { name; + generic_header; params; ret_type; body; } } | ret_type=ret_type name=LIDENT + generic_header=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "(" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", param))) ")" is_mut=boption(MUT) body=body { Nodes.MethDecl { name; + generic_header; this_type; params; ret_type; @@ -254,10 +258,6 @@ stat: | type_=type_expr { Nodes.NormalParam type_ } - | type_=name_type "<" - generics=separated_nonempty_list(",", generic_param) ">" { - Nodes.InfGenericParam {type_; generics} - } | type_=generic_param_type { Nodes.GenericParam type_ } @@ -266,10 +266,6 @@ stat: | name=LIDENT type_=type_expr { ({ Nodes.name; type_=Nodes.NormalParam type_ }: Nodes.param) } - | name=LIDENT type_=name_type "<" - generics=separated_nonempty_list(",", generic_param) ">" { - ({ Nodes.name; type_=Nodes.InfGenericParam {type_; generics}}: Nodes.param) - } | name=UIDENT type_=generic_param_type { ({ Nodes.name; type_=Nodes.GenericParam type_ }: Nodes.param) } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 2b63f6d3..ae50af18 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -10,11 +10,6 @@ and generic_param_type_to_node (x: Nodes.generic_param_type) = match x with and param_type_to_node (x: Nodes.param_type) = match x with | NormalParam x -> type_to_node x - | InfGenericParam x -> - group "InfGenericParam" (fields [ - ("type", name_type_to_node x.type_); - ("generics", map_seq generic_param_to_node x.generics); - ]) | GenericParam x -> generic_param_type_to_node x and call_type_to_node (x: Nodes.call_type) = match x with diff --git a/test-parser/main.zn b/test-parser/main.zn index f212d5b6..6fc37084 100644 --- a/test-parser/main.zn +++ b/test-parser/main.zn @@ -3,7 +3,7 @@ type Vector2 = struct { y T; } -Vector2 +(left Vector2, right Vector2) { +Vector2 +(left Vector2, right Vector2) { return Vector2(left.x + right.x, left.y + right.y) } From 098dbfc8f316e906ed080f3bdc7ab2b1b919bc50 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Sun, 12 Jul 2026 17:09:59 +0200 Subject: [PATCH 127/154] update --- lib/cst/nodes.ml | 506 ++++++++++++++++++++++++----------------- lib/cst/parser.mly | 206 +++++------------ lib/cst/parser.mly.old | 386 +++++++++++++++++++++++++++++++ 3 files changed, 744 insertions(+), 354 deletions(-) create mode 100644 lib/cst/parser.mly.old diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index e266866d..fd690bde 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -1,213 +1,297 @@ (* The CST's job is to represent what was parsed, not what's valid. *) -type operator = - | Add - | Sub - | Mul - | Div - | Eq - | LessEq - | MoreEq - | Less - | More - -type expr = - | IntLit of string - | FloatLit of string - | StrLit of string - | BoolLit of bool - | Ident of string - | QualifiedIdent of string * string - | Op of { left: expr; right: expr; operator: operator } - | Flip of expr - | DotAccess of expr * string - | ConstructorCall of { type_: name_type; args: expr list } - | Parenthized of expr - | FuncCall of func_call - | FuncLambda of func_lambda - | MethLambda of meth_lambda - -and safe_call = { - callee: expr; - args: expr list; -} - -and abort_handle = - | AbortBody of body - | AbortShorthand of expr - -and abort_call = { - callee: expr; - args: expr list; - binder: string option; - handle_block: abort_handle; -} - -and func_call = - | SafeCall of safe_call - | AbortCall of abort_call - -and name_type = - | SimpleType of string - | QualifiedType of string * string - -and call_type = - | FuncType of { - params: param_type list; - ret_type: ret_type - } - | MethType of { - this_type: type_expr; - params: param_type list; - ret_type: ret_type; - is_mut: bool - } - -and body_field = { - name: string; - type_: type_expr; -} - -and body_type = - | Class of body_field list - | Struct of body_field list - | Variant of body_field list - | Tuple of type_expr list - | Enum of string list - -and generic_arg = - | TypeArg of type_expr - | NumberArg of string - -and refable = - | BodyType of body_type - | NameType of name_type - | GenericType of name_type * generic_arg list - -and type_expr = - | CallType of call_type - | NormalType of refable - | RefType of refable - -and param_type = - | NormalParam of type_expr - | GenericParam of generic_param_type - -and param = { - name: string; - type_: param_type -} - -and cond_block = { - cond: expr; - block: stat list -} - -and cond_seq = { - if_: cond_block; - elifs_: cond_block list; - else_: stat list option; -} - -and loop = { - start: expr option; - end_: expr; - binder: string; - body: stat list; -} - -and stat = - | FuncCallStat of func_call - | DeclStat of decl - | AbortStat of expr - | RetStat of expr - | ResolveStat of expr - | CondSeq of cond_seq - | Loop of loop - -and body = - | Scope of stat list - | RetShorthand of expr - -and ret_type = - | SafeRet of type_expr - | AbortRet of type_expr * type_expr - -and func_lambda = { - params: param list; - ret_type: ret_type; - body: body -} - -and meth_lambda = { - this_type: type_expr; - params: param list; - ret_type: ret_type; - is_mut: bool; - body: body -} - -and generic_param_type = TypeParam | NumberParam - -and generic_param = { - name: string; - type_: generic_param_type; -} - -and decl = - | FuncDecl of { - name: string; - generic_header: generic_param list option; - params: param list; - ret_type: ret_type; - body: body - } - | MethDecl of { - name: string; - generic_header: generic_param list option; - this_type: type_expr; - params: param list; - ret_type: ret_type; - is_mut: bool; - body: body - } - | OpDecl of { - op: operator; - generic_header: generic_param list option; - params: param list; - ret_type: ret_type; - body: body - } - | FlipDecl of { - generic_header: generic_param list option; - params: param list; - ret_type: ret_type; - body: body - } - | ConstructorDecl of { - type_: name_type; - params: param list; - body: body - } - | VarDecl of { name: string; type_: type_expr; value: expr } - | VarDeclShorthand of { name: string; type_: name_type; args: expr list } - | TypeDecl of { name: string; params: generic_param list option; value: type_expr } - | AliasDecl of { name: string; params: generic_param list option; value: type_expr } - -type package = { - decls: decl list -} - -let func_type_of_lambda (x: func_lambda) : type_expr = - CallType (FuncType { - params = List.map (fun (p: param) -> p.type_) x.params; - ret_type = x.ret_type; - }) - -let meth_type_of_lambda (x: meth_lambda) : type_expr = - CallType (MethType { - this_type = x.this_type; - params = List.map (fun (p: param) -> p.type_) x.params; - ret_type = x.ret_type; - is_mut = x.is_mut; - }) +(* ---------------------------------------------------------------------- *) +(* Leaf types: no back-references into the recursive core, so they live *) +(* outside the [module rec] chain as ordinary modules. *) +(* ---------------------------------------------------------------------- *) + +module Operator = struct + type t = + | Add + | Sub + | Mul + | Div + | Eq + | LessEq + | MoreEq + | Less + | More +end + +module Kind = struct + type t = Value | Reference +end + +module Name_type = struct + type t = + | Simple of string + | Qualified of string * string +end + +module Generic_param_type = struct + type t = Type | Number +end + +module Generic_param = struct + type t = { + name : string; + type_ : Generic_param_type.t; + } +end + +(* ---------------------------------------------------------------------- *) +(* Recursive core. Every node is its own module with a [t], so the *) +(* constructor names no longer need disambiguating suffixes: *) +(* FuncCallStat -> Stat.VerbCall, FuncDecl -> Decl.Func, *) +(* NormalType -> Type_expr.Normal, SafeRet -> Ret_type.Safe, ... *) +(* The [: sig .. end = Name] wrapper is required for recursive modules. *) +(* ---------------------------------------------------------------------- *) + +module rec Expr : sig + type t = + | IntLit of string + | FloatLit of string + | StrLit of string + | BoolLit of bool + | Ident of string + | QualifiedIdent of string * string + | Flip of t + | DotAccess of t * string + | ConstructorCall of { type_ : Name_type.t; args : t list } + | Parenthized of t + | VerbCall of Verb_call.t + | FuncLambda of Func_lambda.t + | MethLambda of Meth_lambda.t +end = Expr + +and Abort_handle : sig + type t = + | Shorthand of Expr.t + | Longhand of { binder: string option; body: Body.t } +end = Abort_handle + +(* needs grouping because then we can unify the abort handling *) +and Verb_call : sig + type t = + | Func of { callee: Expr.t; args: Expr.t list; } + | Meth of { callee: Expr.t; this: Expr.t; args: Expr.t list; } + | Constructor of { type_name: string option * string; args: Expr.t list; } + | Op of { op: Operator.t; left: Expr.t; right: Expr.t; } +end = Verb_call + +and Body_field : sig + type t = { + name : string; + type_ : Type_expr.t; + } +end = Body_field + +and Mould : sig + type t = + | Struct of Body_field.t list + | Variant of Body_field.t list + | Enum of string list + | Tuple of Type_expr.t list +end = Mould + +and Moulded : sig + type t = { + mould : Mould.t; + kind : Kind.t; + } +end = Moulded + +and Generic_arg : sig + type t = + | Type of Type_expr.t + | Number of string +end = Generic_arg + +and Verb_type : sig + type t = + | Func of { + params: param_type list; + ret_type: ret_type + } + | Meth of { + this_type: type_expr; + params: param_type list; + ret_type: ret_type; + is_mut: bool + } +end = Verb_type + +and Type_expr : sig + type t = + | Normal of Name_type.t * Generic_arg.t list option + | Call of Verb_type.t +end = Type_expr + +and Param_type : sig + type t = + | Normal of Type_expr.t + | Generic of Generic_param_type.t +end = Param_type + +and Param : sig + type t = { + name : string; + type_ : Param_type.t; + } +end = Param + +and Cond_block : sig + type t = { + cond : Expr.t; + block : Stat.t list; + } +end = Cond_block + +and Cond_seq : sig + type t = { + if_ : Cond_block.t; + elifs_ : Cond_block.t list; + else_ : Stat.t list option; + } +end = Cond_seq + +and Loop : sig + type t = { + start : Expr.t option; + end_ : Expr.t; + binder : string; + body : Stat.t list; + } +end = Loop + +and Stat : sig + type t = + | VerbCall of Verb_call.t + | Decl of Decl.t + | Abort of Expr.t + | Ret of Expr.t + | Resolve of Expr.t + | CondSeq of Cond_seq.t + | Loop of Loop.t +end = Stat + +and Body : sig + type t = + | Shorthand of Expr.t + | Longhand of Stat.t list +end = Body + +and Ret_type : sig + type t = + | Safe of Type_expr.t + | Abort of Type_expr.t * Type_expr.t +end = Ret_type + +and Func_lambda : sig + type t = { + params : Param.t list; + ret_type : Ret_type.t; + body : Body.t; + } +end = Func_lambda + +and Meth_lambda : sig + type t = { + this_type : Type_expr.t; + params : Param.t list; + ret_type : Ret_type.t; + is_mut : bool; + body : Body.t; + } +end = Meth_lambda + +and Type_or_moulded : sig + type t = + | Raw of Type_expr.t + | Moulded of Moulded.t +end = Type_or_moulded + +and Var_decl : sig + type t = + | Shorthand + | Longhand +end = Var_decl + +and Verb_decl : sig + type t = + | Func of { + name : string; + generic_header : Generic_param.t list option; + params : Param.t list; + ret_type : Ret_type.t; + body : Body.t; + } + | Meth of { + name : string; + generic_header : Generic_param.t list option; + this_type : Type_expr.t; + params : Param.t list; + ret_type : Ret_type.t; + is_mut : bool; + body : Body.t; + } + | Op of { + op : Operator.t; + generic_header : Generic_param.t list option; + params : Param.t list; + ret_type : Ret_type.t; + body : Body.t; + } + | Constructor of { + type_ : Name_type.t; + params : Param.t list; + body : Body.t; + } +end = Verb_decl + +and Decl : sig + type t = + | Flip of { + generic_header : Generic_param.t list option; + params : Param.t list; + ret_type : Ret_type.t; + body : Body.t; + } + | Var of { name : string; type_ : Type_expr.t; value : Expr.t } + | VarShorthand of { name : string; type_ : Name_type.t; args : Expr.t list } + | Type of { + name : string; + params : Generic_param.t list option; + value : Type_or_moulded.t; + } + | Alias of { + name : string; + params : Generic_param.t list option; + value : Type_expr.t; + } +end = Decl + +(* ---------------------------------------------------------------------- *) +(* Root + helpers. These are not part of the recursion, so they stay out *) +(* of the [module rec] block and just reference the modules above. *) +(* ---------------------------------------------------------------------- *) + +module Package = struct + type t = { decls : Decl.t list } +end + +let func_type_of_lambda (x : Func_lambda.t) : Type_expr.t = + Type_expr.Call + (Call_type.Func { + params = List.map (fun (p : Param.t) -> p.Param.type_) x.Func_lambda.params; + ret_type = x.Func_lambda.ret_type; + }) + +let meth_type_of_lambda (x : Meth_lambda.t) : Type_expr.t = + Type_expr.Call + (Call_type.Meth { + this_type = x.Meth_lambda.this_type; + params = List.map (fun (p : Param.t) -> p.Param.type_) x.Meth_lambda.params; + ret_type = x.Meth_lambda.ret_type; + is_mut = x.Meth_lambda.is_mut; + }) diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 98dba386..fd1e2f53 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -69,7 +69,7 @@ %nonassoc TILDE /* prefix ~ */ %left DOT /* field access */ -%start package +%start package (*************************) (* grammar rules *) @@ -77,58 +77,58 @@ %% package: - | decls=list(decl) EOF { { Nodes.decls=decls } } + | decls=list(decl) EOF { { Nodes.Package.decls = decls } } %inline func_lambda: | ret_type=ret_type "(" params=separated_list(COMMA, param) ")" body=body { - { Nodes.params; ret_type; body } + { Nodes.Func_lambda.params; ret_type; body } } %inline meth_lambda: | ret_type=ret_type "(" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", param))) ")" is_mut=boption(MUT) body=body { - { Nodes.this_type; params; ret_type; is_mut; body } + { Nodes.Meth_lambda.this_type; params; ret_type; is_mut; body } } %inline generic_param_type: | "Type" { - Nodes.TypeParam + Nodes.Generic_param_type.Type } | "Number" { - Nodes.NumberParam + Nodes.Generic_param_type.Number } %inline generic_param: | name=UIDENT type_=generic_param_type { - ({ name; type_ }: Nodes.generic_param) + ({ Nodes.Generic_param.name; type_ } : Nodes.Generic_param.t) } decl: | name=LIDENT type_=type_expr "=" value=expr { - Nodes.VarDecl { name; type_; value } + Nodes.Decl.Var { name; type_; value } } | name=LIDENT type_=name_type "(" args=separated_list(COMMA, expr) ")" { - Nodes.VarDeclShorthand { name; type_; args } + Nodes.Decl.VarShorthand { name; type_; args } } | name=LIDENT func_lambda=func_lambda { - Nodes.VarDecl { + Nodes.Decl.Var { name; - type_=Nodes.func_type_of_lambda func_lambda; - value=Nodes.FuncLambda func_lambda + type_ = Nodes.func_type_of_lambda func_lambda; + value = Nodes.Expr.FuncLambda func_lambda } } | name=LIDENT meth_lambda=meth_lambda { - Nodes.VarDecl { + Nodes.Decl.Var { name; - type_=Nodes.meth_type_of_lambda meth_lambda; - value=Nodes.MethLambda meth_lambda + type_ = Nodes.meth_type_of_lambda meth_lambda; + value = Nodes.Expr.MethLambda meth_lambda } } | ret_type=ret_type name=LIDENT generic_header=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "(" params=separated_list(COMMA, param) ")" body=body { - Nodes.FuncDecl { + Nodes.Decl.Func { name; generic_header; params; @@ -141,7 +141,7 @@ decl: "(" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", param))) ")" is_mut=boption(MUT) body=body { - Nodes.MethDecl { + Nodes.Decl.Meth { name; generic_header; this_type; @@ -153,14 +153,14 @@ decl: } | type_=name_type "(" params=separated_list(COMMA, param) ")" body=body { - Nodes.ConstructorDecl { + Nodes.Decl.Constructor { type_; params; body; } } | ret_type=ret_type op=operator "(" params=separated_list(COMMA, param) ")" body=body { - Nodes.OpDecl { + Nodes.Decl.Op { op; params; ret_type; @@ -168,21 +168,21 @@ decl: } } | ret_type=ret_type "~" "(" params=separated_list(COMMA, param) ")" body=body { - Nodes.FlipDecl { + Nodes.Decl.Flip { params; ret_type; body; } } | "type" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_expr { - Nodes.TypeDecl { + Nodes.Decl.Type { name; params; value; } } | "alias" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_expr { - Nodes.AliasDecl { + Nodes.Decl.Alias { name; params; value; @@ -191,36 +191,50 @@ decl: %inline ret_type: | ret_type=type_expr { - Nodes.SafeRet ret_type + Nodes.Ret_type.Safe ret_type } | safe_type=type_expr "?" abort_type=type_expr { - Nodes.AbortRet (safe_type, abort_type) + Nodes.Ret_type.Abort (safe_type, abort_type) } body: | "{" statements=list(stat) "}" { - Nodes.Scope statements + Nodes.Body.Scope statements } | "=>" value=expr { - Nodes.RetShorthand value + Nodes.Body.RetShorthand value } func_call: - | callee=expr "(" args=separated_list(COMMA, expr) ")" %prec LPAREN - { Nodes.SafeCall { callee; args } } + | + { Nodes.Func_call.Safe Nodes.Safe_call.{ callee; args } } | callee=expr "(" args=separated_list(COMMA, expr) ")" "?" binder=ioption(LIDENT) body=body %prec LPAREN - { Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortBody body } } + { Nodes.Func_call.Abort + Nodes.Abort_call.{ callee; args; binder; + handle_block = Nodes.Abort_handle.Body body } } | callee=expr "(" args=separated_list(COMMA, expr) ")" "??" binder=ioption(LIDENT) value=expr %prec LPAREN - { Nodes.AbortCall { callee; args; binder; handle_block=Nodes.AbortShorthand value } } + { Nodes.Func_call.Abort + Nodes.Abort_call.{ callee; args; binder; + handle_block = Nodes.Abort_handle.Shorthand value } } + +%inline abort_handle: + | "?" binder=ioption(LIDENT) body=body + | "??" value=expr + +verb_call: + | callee=expr "(" args=separated_list(COMMA, expr) ")" %prec LPAREN abort_handle=ioption(abort_handle) { + Nodes.Verb_call func_call + } + %inline if_: | IF cond=expr "{" block=list(stat) "}" { - { Nodes.cond; block } + { Nodes.Cond_block.cond; block } } %inline elif_: | ELIF cond=expr "{" block=list(stat) "}" { - { Nodes.cond; block } + { Nodes.Cond_block.cond; block } } %inline else_: @@ -230,153 +244,59 @@ func_call: %inline loop: | LOOP binder=LIDENT start=ioption(preceded(FROM, expr)) TO end_=expr "{" statements=list(stat) "}" { - ({ start; end_; binder; body=statements; }: Nodes.loop) + ({ Nodes.Loop.start; end_; binder; body = statements } : Nodes.Loop.t) } stat: - | decl=decl { Nodes.DeclStat decl } + | decl=decl { Nodes.Stat.Decl decl } | func_call=func_call { - Nodes.FuncCallStat func_call + Nodes.Stat.FuncCall func_call } | ABORT value=expr { - Nodes.AbortStat value + Nodes.Stat.Abort value } | RETURN value=expr { - Nodes.RetStat value + Nodes.Stat.Ret value } | RESOLVE value=expr { - Nodes.ResolveStat value + Nodes.Stat.Resolve value } | if_=if_ elifs_=list(elif_) else_=ioption(else_) { - Nodes.CondSeq { if_; elifs_; else_ } + Nodes.Stat.CondSeq Nodes.Cond_seq.{ if_; elifs_; else_ } } | loop=loop { - Nodes.Loop loop + Nodes.Stat.Loop loop } %inline param_type: | type_=type_expr { - Nodes.NormalParam type_ + Nodes.Param_type.Normal type_ } | type_=generic_param_type { - Nodes.GenericParam type_ + Nodes.Param_type.Generic type_ } %inline param: | name=LIDENT type_=type_expr { - ({ Nodes.name; type_=Nodes.NormalParam type_ }: Nodes.param) + ({ Nodes.Param.name; type_ = Nodes.Param_type.Normal type_ } : Nodes.Param.t) } | name=UIDENT type_=generic_param_type { - ({ Nodes.name; type_=Nodes.GenericParam type_ }: Nodes.param) + ({ Nodes.Param.name; type_ = Nodes.Param_type.Generic type_ } : Nodes.Param.t) } %inline name_type: - | name=UIDENT { Nodes.SimpleType name } - | pkg=LIDENT "$" name=UIDENT { Nodes.QualifiedType (pkg, name) } + | name=UIDENT { Nodes.Name_type.Simple name } + | pkg=LIDENT "$" name=UIDENT { Nodes.Name_type.Qualified (pkg, name) } -%inline call_type: +%inline verb_type: | ret=ret_type "[" params=separated_list(",", param_type) "]" { - Nodes.FuncType { params; ret_type=ret } + Nodes.Call_type.Func { params; ret_type = ret } } | ret=ret_type "[" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", param_type))) "]" is_mut=boption(MUT) { - Nodes.MethType { this_type; params; ret_type=ret; is_mut } - } - -%inline body_field: - | name=LIDENT type_=type_expr ";" { - ({ Nodes.name; type_ } : Nodes.body_field) - } - -%inline body_type: - | CLASS "{" fields=list(body_field) "}" { - Nodes.Class fields - } - | STRUCT "{" fields=list(body_field) "}" { - Nodes.Struct fields - } - | VARIANT "{" fields=list(body_field) "}" { - Nodes.Variant fields - } - | ENUM "[" cases=separated_list(",", LIDENT) "]" { - Nodes.Enum cases - } - | TUPLE "[" types=separated_list(",", type_expr) "]" { - Nodes.Tuple types - } - - -%inline generic_arg: - | type_expr=type_expr { - Nodes.TypeArg type_expr - } - | number=INT { - Nodes.NumberArg number - } - - -refable: - | name_type=name_type { - Nodes.NameType name_type - } - | name_type=name_type "<" params=separated_nonempty_list(",", generic_arg) ">" { - Nodes.GenericType (name_type, params) - } - | body_type=body_type { - Nodes.BodyType body_type + Nodes.Call_type.Meth { this_type; params; ret_type = ret; is_mut } } -type_expr: - | call_type=call_type { - Nodes.CallType call_type - } - | refable=refable { - Nodes.NormalType refable - } - | "&" refable=refable { - Nodes.RefType refable - } -operator: - | "+" { Nodes.Add } - | "-" { Nodes.Sub } - | "*" { Nodes.Mul } - | "/" { Nodes.Div } - | "=="{ Nodes.Eq } - | "<="{ Nodes.LessEq } - | ">="{ Nodes.MoreEq } - | "<" { Nodes.Less } - | ">" { Nodes.More } -expr: - | int=INT { Nodes.IntLit int } - | float=FLOAT { Nodes.FloatLit float } - | string=STRING { Nodes.StrLit string } - | TRUE { Nodes.BoolLit true } - | FALSE { Nodes.BoolLit false } - | ident=LIDENT { Nodes.Ident ident } - | pkg=LIDENT "$" ident=LIDENT { Nodes.QualifiedIdent (pkg, ident) } - | e1=expr "+" e2=expr %prec PLUS { Nodes.Op { left=e1; right=e2; operator=Nodes.Add } } - | e1=expr "-" e2=expr %prec MINUS { Nodes.Op { left=e1; right=e2; operator=Nodes.Sub } } - | e1=expr "*" e2=expr %prec STAR { Nodes.Op { left=e1; right=e2; operator=Nodes.Mul } } - | e1=expr "/" e2=expr %prec SLASH { Nodes.Op { left=e1; right=e2; operator=Nodes.Div } } - | e1=expr "==" e2=expr %prec EQEQ { Nodes.Op { left=e1; right=e2; operator=Nodes.Eq } } - | e1=expr "<=" e2=expr %prec LESSEQ { Nodes.Op { left=e1; right=e2; operator=Nodes.LessEq } } - | e1=expr ">=" e2=expr %prec MOREEQ { Nodes.Op { left=e1; right=e2; operator=Nodes.MoreEq } } - | e1=expr "<" e2=expr %prec LESS { Nodes.Op { left=e1; right=e2; operator=Nodes.Less } } - | e1=expr ">" e2=expr %prec MORE { Nodes.Op { left=e1; right=e2; operator=Nodes.More } } - | "~" value=expr %prec TILDE { Nodes.Flip value } - | value=expr "." field=LIDENT %prec DOT { Nodes.DotAccess (value, field) } - | type_=name_type "(" args=separated_list(COMMA, expr) ")" %prec LPAREN - { Nodes.ConstructorCall { type_; args } } - | "(" e=expr ")" { Nodes.Parenthized e } - | func_call=func_call { - Nodes.FuncCall func_call - } - | func_lambda=func_lambda { - Nodes.FuncLambda func_lambda - } - | meth_lambda=meth_lambda { - Nodes.MethLambda meth_lambda - } diff --git a/lib/cst/parser.mly.old b/lib/cst/parser.mly.old new file mode 100644 index 00000000..c3a19792 --- /dev/null +++ b/lib/cst/parser.mly.old @@ -0,0 +1,386 @@ +(*****************************) +(* token definitions *) +(*****************************) +%token INT "43" +%token FLOAT "8.647" +%token STRING "\"john\"" +%token LIDENT "length" +%token UIDENT "Int" + +%token LPAREN "(" +%token RPAREN ")" +%token COMMA "," +%token LCURLY "{" +%token RCURLY "}" +%token LBRACKET "[" +%token RBRACKET "]" +%token COLON ":" +%token SEMICOLON ";" +%token DOT "." +%token EQUAL "=" +%token PLUS "+" +%token MINUS "-" +%token STAR "*" +%token SLASH "/" +%token DOLLAR "$" +%token AND "&" +%token AT "@" +%token EXCL "!" +%token QSTNMARK "?" +%token QSTNQSTN "??" +%token TILDE "~" +%token THICK_ARROW "=>" +%token EQEQ "==" +%token LESSEQ "<=" +%token MOREEQ ">=" +%token LESS "<" +%token MORE ">" +%token LTYPE "type" +%token ALIAS "alias" +%token UTYPE "Type" +%token NUMBER "Number" +%token CLASS "class" +%token STRUCT "struct" +%token VARIANT "variant" +%token TUPLE "tuple" +%token ENUM "enum" +%token IF "if" +%token ELIF "elif" +%token ELSE "else" +%token TRUE "true" +%token LOOP "loop" +%token FROM "from" +%token TO "to" +%token FALSE "false" +%token THIS "this" +%token MUT "mut" +%token ABORT "abort" +%token RETURN "return" +%token RESOLVE "resolve" +%token ERROR "" +%token EOF "" + +%nonassoc EQEQ LESSEQ MOREEQ LESS MORE /* comparisons */ +%left PLUS MINUS +%left STAR SLASH +%left LPAREN /* function application */ +%nonassoc IF +%nonassoc ELSE +%nonassoc TILDE /* prefix ~ */ +%left DOT /* field access */ + +%start package + +(*************************) +(* grammar rules *) +(*************************) +%% + +package: + | decls=list(decl) EOF { { Nodes.Package.decls = decls } } + +%inline func_lambda: + | ret_type=ret_type "(" params=separated_list(COMMA, param) ")" body=body { + { Nodes.Func_lambda.params; ret_type; body } + } + +%inline meth_lambda: + | ret_type=ret_type "(" THIS this_type=type_expr + params=loption(preceded(",", separated_nonempty_list(",", param))) + ")" is_mut=boption(MUT) body=body { + { Nodes.Meth_lambda.this_type; params; ret_type; is_mut; body } + } + +%inline generic_param_type: + | "Type" { + Nodes.Generic_param_type.Type + } + | "Number" { + Nodes.Generic_param_type.Number + } + +%inline generic_param: + | name=UIDENT type_=generic_param_type { + ({ Nodes.Generic_param.name; type_ } : Nodes.Generic_param.t) + } + +decl: + | name=LIDENT type_=type_expr "=" value=expr { + Nodes.Decl.Var { name; type_; value } + } + | name=LIDENT type_=name_type "(" args=separated_list(COMMA, expr) ")" { + Nodes.Decl.VarShorthand { name; type_; args } + } + | name=LIDENT func_lambda=func_lambda { + Nodes.Decl.Var { + name; + type_ = Nodes.func_type_of_lambda func_lambda; + value = Nodes.Expr.FuncLambda func_lambda + } + } + | name=LIDENT meth_lambda=meth_lambda { + Nodes.Decl.Var { + name; + type_ = Nodes.meth_type_of_lambda meth_lambda; + value = Nodes.Expr.MethLambda meth_lambda + } + } + | ret_type=ret_type name=LIDENT + generic_header=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) + "(" params=separated_list(COMMA, param) ")" body=body { + Nodes.Decl.Func { + name; + generic_header; + params; + ret_type; + body; + } + } + | ret_type=ret_type name=LIDENT + generic_header=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) + "(" THIS this_type=type_expr + params=loption(preceded(",", separated_nonempty_list(",", param))) + ")" is_mut=boption(MUT) body=body { + Nodes.Decl.Meth { + name; + generic_header; + this_type; + params; + ret_type; + is_mut; + body; + } + } + | type_=name_type + "(" params=separated_list(COMMA, param) ")" body=body { + Nodes.Decl.Constructor { + type_; + params; + body; + } + } + | ret_type=ret_type op=operator "(" params=separated_list(COMMA, param) ")" body=body { + Nodes.Decl.Op { + op; + params; + ret_type; + body; + } + } + | ret_type=ret_type "~" "(" params=separated_list(COMMA, param) ")" body=body { + Nodes.Decl.Flip { + params; + ret_type; + body; + } + } + | "type" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_expr { + Nodes.Decl.Type { + name; + params; + value; + } + } + | "alias" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_expr { + Nodes.Decl.Alias { + name; + params; + value; + } + } + +%inline ret_type: + | ret_type=type_expr { + Nodes.Ret_type.Safe ret_type + } + | safe_type=type_expr "?" abort_type=type_expr { + Nodes.Ret_type.Abort (safe_type, abort_type) + } + +body: + | "{" statements=list(stat) "}" { + Nodes.Body.Scope statements + } + | "=>" value=expr { + Nodes.Body.RetShorthand value + } + +func_call: + | callee=expr "(" args=separated_list(COMMA, expr) ")" %prec LPAREN + { Nodes.Func_call.Safe Nodes.Safe_call.{ callee; args } } + | callee=expr "(" args=separated_list(COMMA, expr) ")" "?" binder=ioption(LIDENT) body=body %prec LPAREN + { Nodes.Func_call.Abort + Nodes.Abort_call.{ callee; args; binder; + handle_block = Nodes.Abort_handle.Body body } } + | callee=expr "(" args=separated_list(COMMA, expr) ")" "??" binder=ioption(LIDENT) value=expr %prec LPAREN + { Nodes.Func_call.Abort + Nodes.Abort_call.{ callee; args; binder; + handle_block = Nodes.Abort_handle.Shorthand value } } + +%inline if_: + | IF cond=expr "{" block=list(stat) "}" { + { Nodes.Cond_block.cond; block } + } + +%inline elif_: + | ELIF cond=expr "{" block=list(stat) "}" { + { Nodes.Cond_block.cond; block } + } + +%inline else_: + | ELSE "{" statements=list(stat) "}" { + statements + } + +%inline loop: + | LOOP binder=LIDENT start=ioption(preceded(FROM, expr)) TO end_=expr "{" statements=list(stat) "}" { + ({ Nodes.Loop.start; end_; binder; body = statements } : Nodes.Loop.t) + } + +stat: + | decl=decl { Nodes.Stat.Decl decl } + | func_call=func_call { + Nodes.Stat.FuncCall func_call + } + | ABORT value=expr { + Nodes.Stat.Abort value + } + | RETURN value=expr { + Nodes.Stat.Ret value + } + | RESOLVE value=expr { + Nodes.Stat.Resolve value + } + | if_=if_ elifs_=list(elif_) else_=ioption(else_) { + Nodes.Stat.CondSeq Nodes.Cond_seq.{ if_; elifs_; else_ } + } + | loop=loop { + Nodes.Stat.Loop loop + } + +%inline param_type: + | type_=type_expr { + Nodes.Param_type.Normal type_ + } + | type_=generic_param_type { + Nodes.Param_type.Generic type_ + } + +%inline param: + | name=LIDENT type_=type_expr { + ({ Nodes.Param.name; type_ = Nodes.Param_type.Normal type_ } : Nodes.Param.t) + } + | name=UIDENT type_=generic_param_type { + ({ Nodes.Param.name; type_ = Nodes.Param_type.Generic type_ } : Nodes.Param.t) + } + +%inline name_type: + | name=UIDENT { Nodes.Name_type.Simple name } + | pkg=LIDENT "$" name=UIDENT { Nodes.Name_type.Qualified (pkg, name) } + +%inline call_type: + | ret=ret_type "[" params=separated_list(",", param_type) "]" { + Nodes.Call_type.Func { params; ret_type = ret } + } + | ret=ret_type "[" THIS this_type=type_expr + params=loption(preceded(",", separated_nonempty_list(",", param_type))) + "]" is_mut=boption(MUT) { + Nodes.Call_type.Meth { this_type; params; ret_type = ret; is_mut } + } + +%inline body_field: + | name=LIDENT type_=type_expr ";" { + ({ Nodes.Body_field.name; type_ } : Nodes.Body_field.t) + } + +%inline mould: + | CLASS "{" fields=list(body_field) "}" { + Nodes.Mould.Class fields + } + | STRUCT "{" fields=list(body_field) "}" { + Nodes.Mould.Struct fields + } + | VARIANT "{" fields=list(body_field) "}" { + Nodes.Mould.Variant fields + } + | ENUM "[" cases=separated_list(",", LIDENT) "]" { + Nodes.Mould.Enum cases + } + | TUPLE "[" types=separated_list(",", type_expr) "]" { + Nodes.Mould.Tuple types + } + + +%inline generic_arg: + | type_expr=type_expr { + Nodes.Generic_arg.Type type_expr + } + | number=INT { + Nodes.Generic_arg.Number number + } + + +refable: + | name_type=name_type { + Nodes.Refable.Name name_type + } + | name_type=name_type "<" params=separated_nonempty_list(",", generic_arg) ">" { + Nodes.Refable.Generic (name_type, params) + } + | body_type=body_type { + Nodes.Refable.Body body_type + } + +type_expr: + | call_type=call_type { + Nodes.Type_expr.Call call_type + } + | refable=refable { + Nodes.Type_expr.Normal refable + } + | "&" refable=refable { + Nodes.Type_expr.Ref refable + } + +operator: + | "+" { Nodes.Operator.Add } + | "-" { Nodes.Operator.Sub } + | "*" { Nodes.Operator.Mul } + | "/" { Nodes.Operator.Div } + | "=="{ Nodes.Operator.Eq } + | "<="{ Nodes.Operator.LessEq } + | ">="{ Nodes.Operator.MoreEq } + | "<" { Nodes.Operator.Less } + | ">" { Nodes.Operator.More } + +expr: + | int=INT { Nodes.Expr.IntLit int } + | float=FLOAT { Nodes.Expr.FloatLit float } + | string=STRING { Nodes.Expr.StrLit string } + | TRUE { Nodes.Expr.BoolLit true } + | FALSE { Nodes.Expr.BoolLit false } + | ident=LIDENT { Nodes.Expr.Ident ident } + | pkg=LIDENT "$" ident=LIDENT { Nodes.Expr.QualifiedIdent (pkg, ident) } + | e1=expr "+" e2=expr %prec PLUS { Nodes.Expr.Op { left=e1; right=e2; operator=Nodes.Operator.Add } } + | e1=expr "-" e2=expr %prec MINUS { Nodes.Expr.Op { left=e1; right=e2; operator=Nodes.Operator.Sub } } + | e1=expr "*" e2=expr %prec STAR { Nodes.Expr.Op { left=e1; right=e2; operator=Nodes.Operator.Mul } } + | e1=expr "/" e2=expr %prec SLASH { Nodes.Expr.Op { left=e1; right=e2; operator=Nodes.Operator.Div } } + | e1=expr "==" e2=expr %prec EQEQ { Nodes.Expr.Op { left=e1; right=e2; operator=Nodes.Operator.Eq } } + | e1=expr "<=" e2=expr %prec LESSEQ { Nodes.Expr.Op { left=e1; right=e2; operator=Nodes.Operator.LessEq } } + | e1=expr ">=" e2=expr %prec MOREEQ { Nodes.Expr.Op { left=e1; right=e2; operator=Nodes.Operator.MoreEq } } + | e1=expr "<" e2=expr %prec LESS { Nodes.Expr.Op { left=e1; right=e2; operator=Nodes.Operator.Less } } + | e1=expr ">" e2=expr %prec MORE { Nodes.Expr.Op { left=e1; right=e2; operator=Nodes.Operator.More } } + | "~" value=expr %prec TILDE { Nodes.Expr.Flip value } + | value=expr "." field=LIDENT %prec DOT { Nodes.Expr.DotAccess (value, field) } + | type_=name_type "(" args=separated_list(COMMA, expr) ")" %prec LPAREN + { Nodes.Expr.ConstructorCall { type_; args } } + | "(" e=expr ")" { Nodes.Expr.Parenthized e } + | func_call=func_call { + Nodes.Expr.FuncCall func_call + } + | func_lambda=func_lambda { + Nodes.Expr.FuncLambda func_lambda + } + | meth_lambda=meth_lambda { + Nodes.Expr.MethLambda meth_lambda + } From 11c4f5ea02e498742cfcdf3b675b47ad0060c4e4 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 15 Jul 2026 11:13:21 +0200 Subject: [PATCH 128/154] finish completing nodes.ml --- lib/cst/nodes.ml | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index fd690bde..2a374e7d 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -77,6 +77,7 @@ and Verb_call : sig | Meth of { callee: Expr.t; this: Expr.t; args: Expr.t list; } | Constructor of { type_name: string option * string; args: Expr.t list; } | Op of { op: Operator.t; left: Expr.t; right: Expr.t; } + | Flip of { value: Expr.t; } end = Verb_call and Body_field : sig @@ -110,13 +111,13 @@ end = Generic_arg and Verb_type : sig type t = | Func of { - params: param_type list; - ret_type: ret_type + params: Param_type.t list; + ret_type: Ret_type.t } | Meth of { - this_type: type_expr; - params: param_type list; - ret_type: ret_type; + this_type: Type_expr.t; + params: Param_type.t list; + ret_type: Ret_type.t; is_mut: bool } end = Verb_type @@ -247,16 +248,16 @@ and Verb_decl : sig params : Param.t list; body : Body.t; } -end = Verb_decl - -and Decl : sig - type t = | Flip of { generic_header : Generic_param.t list option; params : Param.t list; ret_type : Ret_type.t; body : Body.t; } +end = Verb_decl + +and Decl : sig + type t = | Var of { name : string; type_ : Type_expr.t; value : Expr.t } | VarShorthand of { name : string; type_ : Name_type.t; args : Expr.t list } | Type of { @@ -282,14 +283,14 @@ end let func_type_of_lambda (x : Func_lambda.t) : Type_expr.t = Type_expr.Call - (Call_type.Func { + (Verb_type.Func { params = List.map (fun (p : Param.t) -> p.Param.type_) x.Func_lambda.params; ret_type = x.Func_lambda.ret_type; }) let meth_type_of_lambda (x : Meth_lambda.t) : Type_expr.t = Type_expr.Call - (Call_type.Meth { + (Verb_type.Meth { this_type = x.Meth_lambda.this_type; params = List.map (fun (p : Param.t) -> p.Param.type_) x.Meth_lambda.params; ret_type = x.Meth_lambda.ret_type; From 7b1e728a2d353672158e759264f87995d026ed5f Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 15 Jul 2026 12:45:47 +0200 Subject: [PATCH 129/154] update --- lib/cst/nodes.ml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 2a374e7d..b1e2daec 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -54,9 +54,8 @@ module rec Expr : sig | StrLit of string | BoolLit of bool | Ident of string - | QualifiedIdent of string * string - | Flip of t - | DotAccess of t * string + | QualifiedIdent of (string * string) + | DotAccess of (t * string) | ConstructorCall of { type_ : Name_type.t; args : t list } | Parenthized of t | VerbCall of Verb_call.t @@ -75,7 +74,7 @@ and Verb_call : sig type t = | Func of { callee: Expr.t; args: Expr.t list; } | Meth of { callee: Expr.t; this: Expr.t; args: Expr.t list; } - | Constructor of { type_name: string option * string; args: Expr.t list; } + | Constructor of { type_name: (string option * string); args: Expr.t list; } | Op of { op: Operator.t; left: Expr.t; right: Expr.t; } | Flip of { value: Expr.t; } end = Verb_call @@ -124,7 +123,7 @@ end = Verb_type and Type_expr : sig type t = - | Normal of Name_type.t * Generic_arg.t list option + | Normal of (Name_type.t * Generic_arg.t list option) | Call of Verb_type.t end = Type_expr @@ -185,7 +184,7 @@ end = Body and Ret_type : sig type t = | Safe of Type_expr.t - | Abort of Type_expr.t * Type_expr.t + | Abort of (Type_expr.t * Type_expr.t) end = Ret_type and Func_lambda : sig From f180d822bd9af53529ff6bde1d010a0201be0105 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 15 Jul 2026 12:48:54 +0200 Subject: [PATCH 130/154] add abort handle --- lib/cst/nodes.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index b1e2daec..f868bfee 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -72,11 +72,11 @@ end = Abort_handle (* needs grouping because then we can unify the abort handling *) and Verb_call : sig type t = - | Func of { callee: Expr.t; args: Expr.t list; } - | Meth of { callee: Expr.t; this: Expr.t; args: Expr.t list; } - | Constructor of { type_name: (string option * string); args: Expr.t list; } - | Op of { op: Operator.t; left: Expr.t; right: Expr.t; } - | Flip of { value: Expr.t; } + | Func of { callee: Expr.t; args: Expr.t list; abort_handle: Abort_handle option; } + | Meth of { callee: Expr.t; this: Expr.t; args: Expr.t list; abort_handle: Abort_handle option; } + | Constructor of { type_name: (string option * string); args: Expr.t list; abort_handle: Abort_handle option; } + | Op of { op: Operator.t; left: Expr.t; right: Expr.t; abort_handle: Abort_handle option; } + | Flip of { value: Expr.t; abort_handle: Abort_handle option; } end = Verb_call and Body_field : sig From a474ef0a25fd4fda96f949317dd505bd08b5e304 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 15 Jul 2026 17:28:19 +0200 Subject: [PATCH 131/154] fix --- lib/cst/nodes.ml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index f868bfee..e793c954 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -72,11 +72,11 @@ end = Abort_handle (* needs grouping because then we can unify the abort handling *) and Verb_call : sig type t = - | Func of { callee: Expr.t; args: Expr.t list; abort_handle: Abort_handle option; } - | Meth of { callee: Expr.t; this: Expr.t; args: Expr.t list; abort_handle: Abort_handle option; } - | Constructor of { type_name: (string option * string); args: Expr.t list; abort_handle: Abort_handle option; } - | Op of { op: Operator.t; left: Expr.t; right: Expr.t; abort_handle: Abort_handle option; } - | Flip of { value: Expr.t; abort_handle: Abort_handle option; } + | Func of { callee: Expr.t; args: Expr.t list; abort_handle: Abort_handle.t option; } + | Meth of { callee: Expr.t; this: Expr.t; args: Expr.t list; abort_handle: Abort_handle.t option; } + | Constructor of { type_name: (string option * string); args: Expr.t list; abort_handle: Abort_handle.t option; } + | Op of { op: Operator.t; left: Expr.t; right: Expr.t; abort_handle: Abort_handle.t option; } + | Flip of { value: Expr.t; abort_handle: Abort_handle.t option; } end = Verb_call and Body_field : sig From 94aca53042bf93a2031d74254d097fe2dfd2b538 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 16 Jul 2026 11:57:19 +0200 Subject: [PATCH 132/154] nodes are ok now, working on parser --- lib/cst/nodes.ml | 13 +- lib/cst/to_tree_graph.ml | 321 ++++++++++++++++++++++----------------- 2 files changed, 184 insertions(+), 150 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index e793c954..856ab787 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -18,7 +18,7 @@ module Operator = struct | More end -module Kind = struct +module Type_axis = struct type t = Value | Reference end @@ -97,7 +97,7 @@ end = Mould and Moulded : sig type t = { mould : Mould.t; - kind : Kind.t; + axis : Type_axis.t; } end = Moulded @@ -211,12 +211,6 @@ and Type_or_moulded : sig | Moulded of Moulded.t end = Type_or_moulded -and Var_decl : sig - type t = - | Shorthand - | Longhand -end = Var_decl - and Verb_decl : sig type t = | Func of { @@ -258,7 +252,7 @@ end = Verb_decl and Decl : sig type t = | Var of { name : string; type_ : Type_expr.t; value : Expr.t } - | VarShorthand of { name : string; type_ : Name_type.t; args : Expr.t list } + | VarShorthand of { name : string; constructor : Name_type.t; args : Expr.t list } | Type of { name : string; params : Generic_param.t list option; @@ -269,6 +263,7 @@ and Decl : sig params : Generic_param.t list option; value : Type_expr.t; } + | Verb of Verb_decl.t end = Decl (* ---------------------------------------------------------------------- *) diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index ae50af18..0d48b2a2 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -1,24 +1,35 @@ open Tree_graph -let rec name_type_to_node (x: Nodes.name_type) = match x with - | SimpleType s -> Leaf s - | QualifiedType (pkg, type_) -> Leaf (pkg ^ "$" ^ type_) +(* ================================================= *) +(* rule for splitting concerns *) +(* --- *) +(* helper functions never group their name *) +(* eg name_type_to_node doesnt say it's a name type *) +(* it's up to the caller whether it wants to do that *) +(* it only group its internals if needed *) +(* this rule is against double grouping by accident *) +(* and for keeping the usage of the helpers flexible *) +(* ================================================= *) -and generic_param_type_to_node (x: Nodes.generic_param_type) = match x with - | TypeParam -> Leaf "Type" - | NumberParam -> Leaf "Number" +let rec name_type_to_node (x: Nodes.Name_type.t) = match x with + | Simple s -> Leaf s + | Qualified (pkg, type_) -> Leaf (pkg ^ "$" ^ type_) -and param_type_to_node (x: Nodes.param_type) = match x with - | NormalParam x -> type_to_node x - | GenericParam x -> generic_param_type_to_node x +and generic_param_type_to_node (x: Nodes.Generic_param_type.t) = match x with + | Type -> Leaf "Type" + | Number -> Leaf "Number" -and call_type_to_node (x: Nodes.call_type) = match x with - | FuncType { params; ret_type } -> +and param_type_to_node (x: Nodes.Param_type.t) = match x with + | Normal x -> type_to_node x + | Generic x -> generic_param_type_to_node x + +and call_type_to_node (x: Nodes.Verb_type.t) = match x with + | Func { params; ret_type } -> fields [ ("param", map_seq param_type_to_node params); ("type", ret_to_node ret_type); ] - | MethType { this_type; params; ret_type; is_mut } -> + | Meth { this_type; params; ret_type; is_mut } -> fields [ ("this_type", type_to_node this_type); ("param", map_seq param_type_to_node params); @@ -26,78 +37,101 @@ and call_type_to_node (x: Nodes.call_type) = match x with ("is_mut", Leaf (string_of_bool is_mut)); ] -and body_field_to_node (x: Nodes.body_field) = - group "body_field" (fields [ +and body_field_to_node (x: Nodes.Body_field.t) = + fields [ ("name", Leaf x.name); ("type", type_to_node x.type_); - ]) + ] -and body_type_to_node (x: Nodes.body_type) = match x with - | Class x -> group "class" (map_seq body_field_to_node x) +and mould_to_node (x: Nodes.Mould.t) = match x with | Struct x -> group "struct" (map_seq body_field_to_node x) | Variant x -> group "variant" (map_seq body_field_to_node x) | Enum x -> group "enum" (map_seq (fun x -> Leaf x) x) | Tuple x -> group "tuple" (map_seq type_to_node x) -and generic_arg_to_node (x: Nodes.generic_arg) = match x with - | TypeArg x -> type_to_node x - | NumberArg x -> group "number" (Leaf x) +and generic_arg_to_node (x: Nodes.Generic_arg.t) = match x with + | Type x -> type_to_node x + | Number x -> group "number" (Leaf x) -and refable_to_node (x: Nodes.refable) = match x with - | GenericType (name, generics) -> - group "generic_type" (fields [ - ("name", name_type_to_node name); - ("args", map_seq generic_arg_to_node generics); - ]) - | BodyType x -> body_type_to_node x - | NameType x -> name_type_to_node x +(* Name_type.t * Generic_arg.t list option*) +and normal_type_to_node x = + let (name, generic_args) = x in + fields [ + ("qualifier", name_type_to_node name); + ("args", map_seq generic_arg_to_node (Option.value ~default:[] generic_args)); + ] +and type_to_node (x: Nodes.Type_expr.t) = match x with + | Call x -> call_type_to_node x + | Normal x -> normal_type_to_node x -and type_to_node (x: Nodes.type_expr) = match x with - | CallType x -> call_type_to_node x - | NormalType x -> refable_to_node x - | RefType x -> group "ref_type" (refable_to_node x) +and verb_call_to_node (x: Nodes.Verb_call.t) = match x with + | Func { callee; args; abort_handle } -> + group "func_call" (fields [ + ("callee", expr_to_node callee); + ("args", map_seq expr_to_node args); + ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); + ]) + | Meth { callee; this; args; abort_handle } -> + group "meth_call" (fields [ + ("callee", expr_to_node callee); + ("this", expr_to_node this); + ("args", map_seq expr_to_node args); + ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); + ]) + | Constructor { type_name; args; abort_handle } -> + let (pkg, name) = type_name in + let qual = match pkg with + | Some p -> Leaf (p ^ "$" ^ name) + | None -> Leaf name + in + group "ctor_call" (fields [ + ("type", qual); + ("args", map_seq expr_to_node args); + ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); + ]) + | Op { op; left; right; abort_handle } -> + group "op_call" (fields [ + ("op", Leaf (op_to_name op)); + ("left", expr_to_node left); + ("right", expr_to_node right); + ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); + ]) + | Flip { value; abort_handle } -> + group "flip_call" (fields [ + ("value", expr_to_node value); + ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); + ]) -and expr_to_node (x: Nodes.expr) = match x with + and expr_to_node (x: Nodes.Expr.t) = match x with | IntLit x -> Leaf x - | FloatLit x -> Leaf x - | StrLit x -> Leaf x - | BoolLit x -> Leaf (string_of_bool x) - | Ident x -> Leaf x - | QualifiedIdent (pkg, name) -> Leaf (pkg ^ "$" ^ name) - | Op x -> - group (op_to_name x.operator) ( - fields [ - ("left", expr_to_node x.left); - ("right", expr_to_node x.right); - ] - ) + | FloatLit x -> Leaf x + | StrLit x -> Leaf x + | BoolLit x -> Leaf (string_of_bool x) + | Ident x -> Leaf x + | QualifiedIdent (pkg, name) -> Leaf (pkg ^ "$" ^ name) | DotAccess (value, field) -> group "dot_access" ( fields [ ("value", expr_to_node value); ("field", Leaf field); - ] - ) - | ConstructorCall x -> - group "constructor_call" ( - fields [ - ("type", name_type_to_node x.type_); - ("args", map_seq expr_to_node x.args); - ] - ) - | Flip x -> - group "flip" (expr_to_node x) + ] + ) + | ConstructorCall { type_; args } -> + group "ctor_call" (fields [ + ("type", name_type_to_node type_); + ("args", map_seq expr_to_node args); + ]) | Parenthized x -> group "parenthized" (expr_to_node x) - | FuncCall x -> - func_call_to_node x | FuncLambda x -> group "func_lambda" (func_lambda_to_node x) | MethLambda x -> group "meth_lambda" (meth_lambda_to_node x) + | VerbCall x -> + verb_call_to_node x -and op_to_name (x: Nodes.operator) = match x with +and op_to_name (x: Nodes.Operator.t) = match x with | Add -> "+" | Sub -> "-" | Mul -> "*" @@ -108,44 +142,32 @@ and op_to_name (x: Nodes.operator) = match x with | Less -> "<" | More -> ">" -and abort_handle_to_node (x: Nodes.abort_handle) = match x with - | AbortBody x -> body_to_node x - | AbortShorthand x -> expr_to_node x - -and func_call_to_node x = match x with - | SafeCall x -> - group "function_call" (fields [ - ("callee", expr_to_node x.callee); - ("args", map_seq expr_to_node x.args); - ]) - | AbortCall x -> - let fs = [ - ("callee", expr_to_node x.callee); - ("args", map_seq expr_to_node x.args); - ("handle_block", abort_handle_to_node x.handle_block); - ] in - let fs = match x.binder with +and abort_handle_to_node (x: Nodes.Abort_handle.t) = match x with + | Longhand { binder; body } -> + let fs = [("body", body_to_node body)] in + let fs = match binder with | Some b -> ("binder", Leaf b) :: fs | None -> fs in - group "function_call" (fields fs) + group "longhand" (fields fs) + | Shorthand x -> group "shorthand" (expr_to_node x) -and param_to_node (x: Nodes.param) = +and param_to_node (x: Nodes.Param.t) = fields [ ("name", Leaf x.name); ("type", param_type_to_node x.type_); ] -and params_to_node (x: Nodes.param list) = +and params_to_node (x: Nodes.Param.t list) = map_seq param_to_node x -and elif_to_fields (x: Nodes.cond_block) = +and elif_to_fields (x: Nodes.Cond_block.t) = fields [ ("cond", expr_to_node x.cond); ("block", map_seq stat_to_node x.block); ] -and cond_seq_to_node (x: Nodes.cond_seq) = +and cond_seq_to_node (x: Nodes.Cond_seq.t) = let cond_seq = [ ("if", fields [ ("cond", expr_to_node x.if_.cond); @@ -158,9 +180,9 @@ and cond_seq_to_node (x: Nodes.cond_seq) = ("block", map_seq stat_to_node x); ]) :: cond_seq | None -> cond_seq - in group "cond_seq" (fields cond_seq) + in fields cond_seq -and loop_to_node (x: Nodes.loop) = +and loop_to_node (x: Nodes.Loop.t) = let fs = [ ("stats", map_seq stat_to_node x.body); ("end", expr_to_node x.end_); @@ -170,41 +192,41 @@ and loop_to_node (x: Nodes.loop) = | Some x -> ("start", expr_to_node x) :: fs | None -> fs in - group "loop_stat" (fields fs) + fields fs -and stat_to_node (x: Nodes.stat) = match x with - | FuncCallStat x -> func_call_to_node x - | DeclStat x -> decl_to_node x - | AbortStat x -> group "abort_stat" (expr_to_node x) - | RetStat x -> group "ret_stat" (expr_to_node x) - | ResolveStat x -> group "resolve_stat" (expr_to_node x) - | CondSeq x -> cond_seq_to_node x - | Loop x -> loop_to_node x +and stat_to_node (x: Nodes.Stat.t) = match x with + | VerbCall x -> verb_call_to_node x + | Decl x -> decl_to_node x + | Abort x -> group "abort_stat" (expr_to_node x) + | Ret x -> group "ret_stat" (expr_to_node x) + | Resolve x -> group "resolve_stat" (expr_to_node x) + | CondSeq x -> cond_seq_to_node x + | Loop x -> group "loop" (loop_to_node x) -and body_to_node (x: Nodes.body) = match x with - | Scope scope -> +and body_to_node (x: Nodes.Body.t) = match x with + | Longhand x -> group "scope" (fields [ - ("stat", map_seq stat_to_node scope); + ("stat", map_seq stat_to_node x); ]) - | RetShorthand x -> + | Shorthand x -> group "ret_shorthand" (expr_to_node x) -and ret_to_node (x: Nodes.ret_type) = match x with - | SafeRet ret -> type_to_node ret - | AbortRet (ret_type, abort_type) -> +and ret_to_node (x: Nodes.Ret_type.t) = match x with + | Safe ret -> type_to_node ret + | Abort (ret_type, abort_type) -> fields [ ("safe_type", type_to_node ret_type); ("abort_type", type_to_node abort_type); ] -and func_lambda_to_node (x: Nodes.func_lambda) = +and func_lambda_to_node (x: Nodes.Func_lambda.t) = fields [ ("param", params_to_node x.params); ("ret_type", ret_to_node x.ret_type); ("body", body_to_node x.body); ] -and meth_lambda_to_node (x: Nodes.meth_lambda) = +and meth_lambda_to_node (x: Nodes.Meth_lambda.t) = fields [ ("this_type", type_to_node x.this_type); ("param", params_to_node x.params); @@ -213,15 +235,64 @@ and meth_lambda_to_node (x: Nodes.meth_lambda) = ("is_mut", Leaf (string_of_bool x.is_mut)); ] -and decl_to_node (x: Nodes.decl) = match x with - | FuncDecl x -> +and type_axis_to_node (x: Nodes.Type_axis.t) = match x with + | Value -> Leaf "value" + | Reference -> Leaf "reference" + +and moulded_to_node (x: Nodes.Moulded.t) = + fields [ + ("mould", mould_to_node x.mould); + ("type_axis", type_axis_to_node x.axis); + ] + +and type_or_moulded_to_node (x: Nodes.Type_or_moulded.t) = match x with + | Raw x -> type_to_node x + | Moulded x -> moulded_to_node x + +and decl_to_node (x: Nodes.Decl.t) = match x with + | Var { name; type_; value } -> + group "var_decl" (fields [ + ("name", Leaf name); + ("type", type_to_node type_); + ("value", expr_to_node value); + ]) + | VarShorthand { name; constructor; args } -> + group "var_decl_shorthand" (fields [ + ("name", Leaf name); + ("type", name_type_to_node constructor); + ("args", map_seq expr_to_node args); + ]) + | Type x -> + let fs = [ + ("name", Leaf x.name); + ("value", type_or_moulded_to_node x.value); + ] in + let fs = match x.params with + | Some p -> ("params", map_seq generic_param_to_node p) :: fs + | None -> fs + in + group "type_decl" (fields fs) + | Alias x -> + let fs = [ + ("name", Leaf x.name); + ("value", type_to_node x.value); + ] in + let fs = match x.params with + | Some p -> ("params", map_seq generic_param_to_node p) :: fs + | None -> fs + in + group "alias_decl" (fields fs) + | Verb x -> verb_decl_to_node x + +and verb_decl_to_node (x: Nodes.Verb_decl.t) = match x with + | Func x -> group "func_decl" (fields [ ("name", Leaf x.name); ("param", params_to_node x.params); ("ret_type", ret_to_node x.ret_type); ("body", body_to_node x.body); ]) - | MethDecl x -> + | Meth x -> group "meth_decl" (fields [ ("name", Leaf x.name); ("this_type", type_to_node x.this_type); @@ -230,65 +301,33 @@ and decl_to_node (x: Nodes.decl) = match x with ("body", body_to_node x.body); ("is_mut", Leaf (string_of_bool x.is_mut)); ]) - | ConstructorDecl x -> + | Constructor x -> group "meth_decl" (fields [ ("type", name_type_to_node x.type_); ("param", params_to_node x.params); ("body", body_to_node x.body); ]) - | VarDecl { name; type_; value } -> - group "var_decl" (fields [ - ("name", Leaf name); - ("type", type_to_node type_); - ("value", expr_to_node value); - ]) - | VarDeclShorthand { name; type_; args } -> - group "var_decl_shorthand" (fields [ - ("name", Leaf name); - ("type", name_type_to_node type_); - ("args", map_seq expr_to_node args); - ]) - | OpDecl x -> + | Op x -> group "op_decl" (fields [ ("op", Leaf (op_to_name x.op)); ("param", params_to_node x.params); ("ret_type", ret_to_node x.ret_type); ("body", body_to_node x.body); ]) - | FlipDecl x -> + | Flip x -> group "flip_decl" (fields [ ("param", params_to_node x.params); ("ret_type", ret_to_node x.ret_type); ("body", body_to_node x.body); ]) - | TypeDecl x -> - let fs = [ - ("name", Leaf x.name); - ("value", type_to_node x.value); - ] in - let fs = match x.params with - | Some p -> ("params", map_seq generic_param_to_node p) :: fs - | None -> fs - in - group "type_decl" (fields fs) - | AliasDecl x -> - let fs = [ - ("name", Leaf x.name); - ("value", type_to_node x.value); - ] in - let fs = match x.params with - | Some p -> ("params", map_seq generic_param_to_node p) :: fs - | None -> fs - in - group "alias_decl" (fields fs) -and generic_param_to_node (x: Nodes.generic_param) = +and generic_param_to_node (x: Nodes.Generic_param.t) = fields [ ("name", Leaf x.name); ("type", generic_param_type_to_node x.type_); ] -let to_node ({ Nodes.decls }: Nodes.package) = +let to_node ({ decls }: Nodes.Package.t) = group "package" (fields [ ("declarations", map_seq decl_to_node decls); ]) From cdeb2011042816778a0a4f4896e38f67915a4e76 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 16 Jul 2026 15:23:47 +0200 Subject: [PATCH 133/154] cleanup --- lib/cst/nodes.ml | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 856ab787..004d94ed 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -24,8 +24,8 @@ end module Name_type = struct type t = - | Simple of string - | Qualified of string * string + | Ident of string + | Qualified of { package : string; ident : string } end module Generic_param_type = struct @@ -47,15 +47,20 @@ end (* The [: sig .. end = Name] wrapper is required for recursive modules. *) (* ---------------------------------------------------------------------- *) +module Name_expr = struct + type t = + | Ident of string + | Qualified of { package : string; ident : string } +end + module rec Expr : sig type t = | IntLit of string | FloatLit of string | StrLit of string | BoolLit of bool - | Ident of string - | QualifiedIdent of (string * string) - | DotAccess of (t * string) + | NameExpr of Name_expr.t + | DotAccess of { target : t; field : string } | ConstructorCall of { type_ : Name_type.t; args : t list } | Parenthized of t | VerbCall of Verb_call.t @@ -74,7 +79,7 @@ and Verb_call : sig type t = | Func of { callee: Expr.t; args: Expr.t list; abort_handle: Abort_handle.t option; } | Meth of { callee: Expr.t; this: Expr.t; args: Expr.t list; abort_handle: Abort_handle.t option; } - | Constructor of { type_name: (string option * string); args: Expr.t list; abort_handle: Abort_handle.t option; } + | Constructor of { name_type: Name_type.t; args: Expr.t list; abort_handle: Abort_handle.t option; } | Op of { op: Operator.t; left: Expr.t; right: Expr.t; abort_handle: Abort_handle.t option; } | Flip of { value: Expr.t; abort_handle: Abort_handle.t option; } end = Verb_call @@ -123,7 +128,7 @@ end = Verb_type and Type_expr : sig type t = - | Normal of (Name_type.t * Generic_arg.t list option) + | Normal of { name : Name_type.t; generics : Generic_arg.t list } | Call of Verb_type.t end = Type_expr @@ -184,7 +189,7 @@ end = Body and Ret_type : sig type t = | Safe of Type_expr.t - | Abort of (Type_expr.t * Type_expr.t) + | Abort of { ok : Type_expr.t; abort : Type_expr.t } end = Ret_type and Func_lambda : sig @@ -215,14 +220,12 @@ and Verb_decl : sig type t = | Func of { name : string; - generic_header : Generic_param.t list option; params : Param.t list; ret_type : Ret_type.t; body : Body.t; } | Meth of { name : string; - generic_header : Generic_param.t list option; this_type : Type_expr.t; params : Param.t list; ret_type : Ret_type.t; @@ -231,7 +234,6 @@ and Verb_decl : sig } | Op of { op : Operator.t; - generic_header : Generic_param.t list option; params : Param.t list; ret_type : Ret_type.t; body : Body.t; @@ -242,7 +244,6 @@ and Verb_decl : sig body : Body.t; } | Flip of { - generic_header : Generic_param.t list option; params : Param.t list; ret_type : Ret_type.t; body : Body.t; @@ -255,12 +256,12 @@ and Decl : sig | VarShorthand of { name : string; constructor : Name_type.t; args : Expr.t list } | Type of { name : string; - params : Generic_param.t list option; + params : Generic_param.t list; value : Type_or_moulded.t; } | Alias of { name : string; - params : Generic_param.t list option; + params : Generic_param.t list; value : Type_expr.t; } | Verb of Verb_decl.t From 645b98189e30e6589dc4477aaff6248ca5143191 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 16 Jul 2026 15:25:05 +0200 Subject: [PATCH 134/154] update --- lib/cst/nodes.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 004d94ed..48bda999 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -1,8 +1,8 @@ (* The CST's job is to represent what was parsed, not what's valid. *) (* ---------------------------------------------------------------------- *) -(* Leaf types: no back-references into the recursive core, so they live *) -(* outside the [module rec] chain as ordinary modules. *) +(* Leaf types: no back-references into the recursive core, so they live *) +(* outside the [module rec] chain as ordinary modules. *) (* ---------------------------------------------------------------------- *) module Operator = struct From 8b8c938e6205565b46de32f4dea258111ce0634c Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 16 Jul 2026 15:52:46 +0200 Subject: [PATCH 135/154] clean up --- lib/cst/nodes.ml | 17 ++-- lib/cst/to_tree_graph.ml | 175 +++++++++++++++++++-------------------- 2 files changed, 91 insertions(+), 101 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 48bda999..5525a369 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -28,14 +28,14 @@ module Name_type = struct | Qualified of { package : string; ident : string } end -module Generic_param_type = struct +module Concept = struct type t = Type | Number end module Generic_param = struct type t = { name : string; - type_ : Generic_param_type.t; + type_ : Concept.t; } end @@ -61,7 +61,6 @@ module rec Expr : sig | BoolLit of bool | NameExpr of Name_expr.t | DotAccess of { target : t; field : string } - | ConstructorCall of { type_ : Name_type.t; args : t list } | Parenthized of t | VerbCall of Verb_call.t | FuncLambda of Func_lambda.t @@ -128,14 +127,14 @@ end = Verb_type and Type_expr : sig type t = - | Normal of { name : Name_type.t; generics : Generic_arg.t list } - | Call of Verb_type.t + | Path of { name : Name_type.t; generics : Generic_arg.t list } + | Verb of Verb_type.t end = Type_expr and Param_type : sig type t = - | Normal of Type_expr.t - | Generic of Generic_param_type.t + | Concrete of Type_expr.t + | Concept of Concept.t end = Param_type and Param : sig @@ -277,14 +276,14 @@ module Package = struct end let func_type_of_lambda (x : Func_lambda.t) : Type_expr.t = - Type_expr.Call + Type_expr.Verb (Verb_type.Func { params = List.map (fun (p : Param.t) -> p.Param.type_) x.Func_lambda.params; ret_type = x.Func_lambda.ret_type; }) let meth_type_of_lambda (x : Meth_lambda.t) : Type_expr.t = - Type_expr.Call + Type_expr.Verb (Verb_type.Meth { this_type = x.Meth_lambda.this_type; params = List.map (fun (p : Param.t) -> p.Param.type_) x.Meth_lambda.params; diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 0d48b2a2..84f24a8c 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -1,29 +1,45 @@ open Tree_graph -(* ================================================= *) -(* rule for splitting concerns *) -(* --- *) -(* helper functions never group their name *) -(* eg name_type_to_node doesnt say it's a name type *) -(* it's up to the caller whether it wants to do that *) -(* it only group its internals if needed *) -(* this rule is against double grouping by accident *) -(* and for keeping the usage of the helpers flexible *) -(* ================================================= *) +(* =================================================== *) +(* rule: helpers return raw nodes, never self-wrap *) +(* --- *) +(* a helper like name_type_to_node returns the Node *) +(* for its value directly, it never calls group on *) +(* its own output, even if that means the result *) +(* looks "unlabeled" on its own. *) +(* *) +(* let name_type_to_node x = match x with *) +(* | Ident s -> Leaf s *) +(* | Qualified { .. } -> Leaf (...) *) +(* (* no group "name_type" (...) here *) *) +(* *) +(* labeling is the caller's decision, not the callee's *) +(* the same value can be grouped under different names *) +(* depending on where it's used (a "type" field here, *) +(* a "constructor" field there) or left ungrouped *) +(* entirely if it's just one entry among fields [...]. *) +(* if a helper pre-wraps its own result, that decision *) +(* is made once and for all callers, even the ones *) +(* that wanted a different label or no label at all. *) +(* =================================================== *) -let rec name_type_to_node (x: Nodes.Name_type.t) = match x with - | Simple s -> Leaf s - | Qualified (pkg, type_) -> Leaf (pkg ^ "$" ^ type_) +let name_type_to_node (x: Nodes.Name_type.t) = match x with + | Ident s -> Leaf s + | Qualified { package; ident } -> Leaf (package ^ "$" ^ ident) -and generic_param_type_to_node (x: Nodes.Generic_param_type.t) = match x with +let name_expr_to_node (x: Nodes.Name_expr.t) = match x with + | Ident s -> Leaf s + | Qualified { package; ident } -> Leaf (package ^ "$" ^ ident) + +let rec concept_to_node (x: Nodes.Concept.t) = match x with | Type -> Leaf "Type" | Number -> Leaf "Number" and param_type_to_node (x: Nodes.Param_type.t) = match x with - | Normal x -> type_to_node x - | Generic x -> generic_param_type_to_node x + | Concrete x -> type_to_node x + | Concept x -> concept_to_node x -and call_type_to_node (x: Nodes.Verb_type.t) = match x with +and verb_type_to_node (x: Nodes.Verb_type.t) = match x with | Func { params; ret_type } -> fields [ ("param", map_seq param_type_to_node params); @@ -53,17 +69,13 @@ and generic_arg_to_node (x: Nodes.Generic_arg.t) = match x with | Type x -> type_to_node x | Number x -> group "number" (Leaf x) -(* Name_type.t * Generic_arg.t list option*) -and normal_type_to_node x = - let (name, generic_args) = x in - fields [ - ("qualifier", name_type_to_node name); - ("args", map_seq generic_arg_to_node (Option.value ~default:[] generic_args)); - ] - and type_to_node (x: Nodes.Type_expr.t) = match x with - | Call x -> call_type_to_node x - | Normal x -> normal_type_to_node x + | Verb x -> verb_type_to_node x + | Path { name; generics } -> + fields [ + ("qualifier", name_type_to_node name); + ("args", map_seq generic_arg_to_node generics); + ] and verb_call_to_node (x: Nodes.Verb_call.t) = match x with | Func { callee; args; abort_handle } -> @@ -71,7 +83,7 @@ and verb_call_to_node (x: Nodes.Verb_call.t) = match x with ("callee", expr_to_node callee); ("args", map_seq expr_to_node args); ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); - ]) + ]) | Meth { callee; this; args; abort_handle } -> group "meth_call" (fields [ ("callee", expr_to_node callee); @@ -79,49 +91,36 @@ and verb_call_to_node (x: Nodes.Verb_call.t) = match x with ("args", map_seq expr_to_node args); ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); ]) - | Constructor { type_name; args; abort_handle } -> - let (pkg, name) = type_name in - let qual = match pkg with - | Some p -> Leaf (p ^ "$" ^ name) - | None -> Leaf name - in + | Constructor { name_type; args; abort_handle } -> group "ctor_call" (fields [ - ("type", qual); + ("type", name_type_to_node name_type); ("args", map_seq expr_to_node args); ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); ]) - | Op { op; left; right; abort_handle } -> - group "op_call" (fields [ - ("op", Leaf (op_to_name op)); + | Op { op; left; right; abort_handle } -> + group "op_call" (fields [ + ("op", Leaf (op_to_name op)); ("left", expr_to_node left); ("right", expr_to_node right); ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); ]) - | Flip { value; abort_handle } -> - group "flip_call" (fields [ - ("value", expr_to_node value); + | Flip { value; abort_handle } -> + group "flip_call" (fields [ + ("value", expr_to_node value); ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); - ]) + ]) - and expr_to_node (x: Nodes.Expr.t) = match x with - | IntLit x -> Leaf x - | FloatLit x -> Leaf x - | StrLit x -> Leaf x - | BoolLit x -> Leaf (string_of_bool x) - | Ident x -> Leaf x - | QualifiedIdent (pkg, name) -> Leaf (pkg ^ "$" ^ name) - | DotAccess (value, field) -> - group "dot_access" ( - fields [ - ("value", expr_to_node value); - ("field", Leaf field); - ] - ) - | ConstructorCall { type_; args } -> - group "ctor_call" (fields [ - ("type", name_type_to_node type_); - ("args", map_seq expr_to_node args); - ]) +and expr_to_node (x: Nodes.Expr.t) = match x with + | IntLit x -> Leaf x + | FloatLit x -> Leaf x + | StrLit x -> Leaf x + | BoolLit x -> Leaf (string_of_bool x) + | NameExpr x -> name_expr_to_node x + | DotAccess { target; field } -> + group "dot_access" (fields [ + ("target", expr_to_node target); + ("field", Leaf field); + ]) | Parenthized x -> group "parenthized" (expr_to_node x) | FuncLambda x -> @@ -213,10 +212,10 @@ and body_to_node (x: Nodes.Body.t) = match x with and ret_to_node (x: Nodes.Ret_type.t) = match x with | Safe ret -> type_to_node ret - | Abort (ret_type, abort_type) -> + | Abort { ok; abort } -> fields [ - ("safe_type", type_to_node ret_type); - ("abort_type", type_to_node abort_type); + ("safe_type", type_to_node ok); + ("abort_type", type_to_node abort); ] and func_lambda_to_node (x: Nodes.Func_lambda.t) = @@ -263,38 +262,30 @@ and decl_to_node (x: Nodes.Decl.t) = match x with ("args", map_seq expr_to_node args); ]) | Type x -> - let fs = [ - ("name", Leaf x.name); - ("value", type_or_moulded_to_node x.value); - ] in - let fs = match x.params with - | Some p -> ("params", map_seq generic_param_to_node p) :: fs - | None -> fs - in - group "type_decl" (fields fs) + group "type_decl" (fields [ + ("name", Leaf x.name); + ("params", map_seq generic_param_to_node x.params); + ("value", type_or_moulded_to_node x.value); + ]) | Alias x -> - let fs = [ - ("name", Leaf x.name); - ("value", type_to_node x.value); - ] in - let fs = match x.params with - | Some p -> ("params", map_seq generic_param_to_node p) :: fs - | None -> fs - in - group "alias_decl" (fields fs) + group "alias_decl" (fields [ + ("name", Leaf x.name); + ("params", map_seq generic_param_to_node x.params); + ("value", type_to_node x.value); + ]) | Verb x -> verb_decl_to_node x and verb_decl_to_node (x: Nodes.Verb_decl.t) = match x with | Func x -> group "func_decl" (fields [ - ("name", Leaf x.name); + ("name", Leaf x.name); ("param", params_to_node x.params); ("ret_type", ret_to_node x.ret_type); ("body", body_to_node x.body); ]) | Meth x -> group "meth_decl" (fields [ - ("name", Leaf x.name); + ("name", Leaf x.name); ("this_type", type_to_node x.this_type); ("param", params_to_node x.params); ("ret_type", ret_to_node x.ret_type); @@ -302,19 +293,19 @@ and verb_decl_to_node (x: Nodes.Verb_decl.t) = match x with ("is_mut", Leaf (string_of_bool x.is_mut)); ]) | Constructor x -> - group "meth_decl" (fields [ - ("type", name_type_to_node x.type_); - ("param", params_to_node x.params); - ("body", body_to_node x.body); + group "ctor_decl" (fields [ + ("type", name_type_to_node x.type_); + ("param", params_to_node x.params); + ("body", body_to_node x.body); ]) - | Op x -> + | Op x -> group "op_decl" (fields [ - ("op", Leaf (op_to_name x.op)); + ("op", Leaf (op_to_name x.op)); ("param", params_to_node x.params); ("ret_type", ret_to_node x.ret_type); ("body", body_to_node x.body); ]) - | Flip x -> + | Flip x -> group "flip_decl" (fields [ ("param", params_to_node x.params); ("ret_type", ret_to_node x.ret_type); @@ -324,7 +315,7 @@ and verb_decl_to_node (x: Nodes.Verb_decl.t) = match x with and generic_param_to_node (x: Nodes.Generic_param.t) = fields [ ("name", Leaf x.name); - ("type", generic_param_type_to_node x.type_); + ("type", concept_to_node x.type_); ] let to_node ({ decls }: Nodes.Package.t) = From 7559ac94e6438b3be882a3995ee283906b2551e5 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 16 Jul 2026 16:33:13 +0200 Subject: [PATCH 136/154] update --- lib/cst/lexer.ml | 1 + lib/cst/parser.mly | 152 ++++++++++++++++++++++++++++----------------- 2 files changed, 95 insertions(+), 58 deletions(-) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index 1601f10c..96754ea0 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -44,6 +44,7 @@ let rec token buf = | '*' -> STAR | '/' -> SLASH | '$' -> DOLLAR + | '#' -> HASH | '&' -> AND | '@' -> AT | float_lit -> FLOAT (Utf8.lexeme buf) diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index fd1e2f53..24e7a465 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -23,6 +23,7 @@ %token STAR "*" %token SLASH "/" %token DOLLAR "$" +%token HASH "#" %token AND "&" %token AT "@" %token EXCL "!" @@ -91,25 +92,29 @@ package: { Nodes.Meth_lambda.this_type; params; ret_type; is_mut; body } } -%inline generic_param_type: +(* renamed: Generic_param_type -> Concept *) +%inline concept: | "Type" { - Nodes.Generic_param_type.Type + Nodes.Concept.Type } | "Number" { - Nodes.Generic_param_type.Number + Nodes.Concept.Number } %inline generic_param: - | name=UIDENT type_=generic_param_type { - ({ Nodes.Generic_param.name; type_ } : Nodes.Generic_param.t) + | name=UIDENT "Type" { + ({ Nodes.Generic_param.name; type_ = Nodes.Concept.Type } : Nodes.Generic_param.t) + } + | name=LIDENT "Number" { + ({ Nodes.Generic_param.name; type_ = Nodes.Concept.Number } : Nodes.Generic_param.t) } decl: | name=LIDENT type_=type_expr "=" value=expr { Nodes.Decl.Var { name; type_; value } } - | name=LIDENT type_=name_type "(" args=separated_list(COMMA, expr) ")" { - Nodes.Decl.VarShorthand { name; type_; args } + | name=LIDENT constructor=name_type "(" args=separated_list(COMMA, expr) ")" { + Nodes.Decl.VarShorthand { name; constructor; args } } | name=LIDENT func_lambda=func_lambda { Nodes.Decl.Var { @@ -126,62 +131,60 @@ decl: } } | ret_type=ret_type name=LIDENT - generic_header=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "(" params=separated_list(COMMA, param) ")" body=body { - Nodes.Decl.Func { + Nodes.Decl.Verb (Nodes.Verb_decl.Func { name; - generic_header; params; ret_type; body; - } + }) } | ret_type=ret_type name=LIDENT - generic_header=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "(" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", param))) ")" is_mut=boption(MUT) body=body { - Nodes.Decl.Meth { + Nodes.Decl.Verb (Nodes.Verb_decl.Meth { name; - generic_header; this_type; params; ret_type; is_mut; body; - } + }) } | type_=name_type "(" params=separated_list(COMMA, param) ")" body=body { - Nodes.Decl.Constructor { + Nodes.Decl.Verb (Nodes.Verb_decl.Constructor { type_; params; body; - } + }) } | ret_type=ret_type op=operator "(" params=separated_list(COMMA, param) ")" body=body { - Nodes.Decl.Op { + Nodes.Decl.Verb (Nodes.Verb_decl.Op { op; params; ret_type; body; - } + }) } | ret_type=ret_type "~" "(" params=separated_list(COMMA, param) ")" body=body { - Nodes.Decl.Flip { + Nodes.Decl.Verb (Nodes.Verb_decl.Flip { params; ret_type; body; - } + }) } - | "type" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_expr { + (* params is a plain list now, so loption (not ioption) is the right + combinator — it already yields [] when the <> header is absent. *) + | "type" name=UIDENT params=loption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_or_moulded { Nodes.Decl.Type { name; params; value; } } - | "alias" name=UIDENT params=ioption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_expr { + | "alias" name=UIDENT params=loption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_expr { Nodes.Decl.Alias { name; params; @@ -189,43 +192,75 @@ decl: } } +%inline body_field: + | name=LIDENT type_=type_expr ";" { + Nodes.Body_field { name; type_ } + } + +%inline mould: + | STRUCT "{" fields=list(body_field) "}" { + Nodes.Mould.Struct fields + } + | VARIANT "{" fields=list(body_field) "}" { + Nodes.Mould.Variant fields + } + | ENUM "[" members=separated_nonempty_list(",", LIDENT) "]" { + Nodes.Mould.Enum members + } + | TUPLE "[" members=separated_nonempty_list(",", type_expr) "]"{ + Nodes.Mould.Tuple members + } + +%inline moulded: + | mould=mould { + Nodes.Moulded { mould; type_axis=Nodes.Type_axis.Value } + } + | "#" mould=mould { + Nodes.Moulded { mould; type_axis=Nodes.Type_axis.Reference } + } + +%inline type_or_moulded: + | type_expr=type_or_moulded { + Nodes.Type_or_moulded.Raw type_expr + } + | moulded=moulded { + Nodes.Type_or_moulded.Moulded moulded + } + %inline ret_type: | ret_type=type_expr { Nodes.Ret_type.Safe ret_type } - | safe_type=type_expr "?" abort_type=type_expr { - Nodes.Ret_type.Abort (safe_type, abort_type) + | ok=type_expr "?" abort=type_expr { + Nodes.Ret_type.Abort { ok; abort } } body: | "{" statements=list(stat) "}" { - Nodes.Body.Scope statements + Nodes.Body.Longhand statements } | "=>" value=expr { - Nodes.Body.RetShorthand value + Nodes.Body.Shorthand value } -func_call: - | - { Nodes.Func_call.Safe Nodes.Safe_call.{ callee; args } } - | callee=expr "(" args=separated_list(COMMA, expr) ")" "?" binder=ioption(LIDENT) body=body %prec LPAREN - { Nodes.Func_call.Abort - Nodes.Abort_call.{ callee; args; binder; - handle_block = Nodes.Abort_handle.Body body } } - | callee=expr "(" args=separated_list(COMMA, expr) ")" "??" binder=ioption(LIDENT) value=expr %prec LPAREN - { Nodes.Func_call.Abort - Nodes.Abort_call.{ callee; args; binder; - handle_block = Nodes.Abort_handle.Shorthand value } } - %inline abort_handle: - | "?" binder=ioption(LIDENT) body=body - | "??" value=expr + | "?" binder=ioption(LIDENT) body=body { + Nodes.Abort_handle.Longhand { binder; body } + } + | "??" value=expr { + Nodes.Abort_handle.Shorthand value + } verb_call: - | callee=expr "(" args=separated_list(COMMA, expr) ")" %prec LPAREN abort_handle=ioption(abort_handle) { - Nodes.Verb_call func_call + | callee=expr "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) %prec LPAREN { + Nodes.Verb_call.Func { callee; args; abort_handle } + } + | this=expr "!" callee=expr "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) %prec LPAREN { + Nodes.Verb_call.Meth { callee; this; args; abort_handle } + } + | name_type=name_type "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) %prec LPAREN { + Nodes.Verb_call.Constructor { name_type; args; abort_handle } } - %inline if_: | IF cond=expr "{" block=list(stat) "}" { @@ -249,8 +284,8 @@ verb_call: stat: | decl=decl { Nodes.Stat.Decl decl } - | func_call=func_call { - Nodes.Stat.FuncCall func_call + | verb_call=verb_call { + Nodes.Stat.VerbCall verb_call } | ABORT value=expr { Nodes.Stat.Abort value @@ -270,33 +305,34 @@ stat: %inline param_type: | type_=type_expr { - Nodes.Param_type.Normal type_ + Nodes.Param_type.Concrete type_ } - | type_=generic_param_type { - Nodes.Param_type.Generic type_ + | type_=concept { + Nodes.Param_type.Concept type_ } %inline param: | name=LIDENT type_=type_expr { - ({ Nodes.Param.name; type_ = Nodes.Param_type.Normal type_ } : Nodes.Param.t) + ({ Nodes.Param.name; type_ = Nodes.Param_type.Concrete type_ } : Nodes.Param.t) } - | name=UIDENT type_=generic_param_type { - ({ Nodes.Param.name; type_ = Nodes.Param_type.Generic type_ } : Nodes.Param.t) + | name=UIDENT "Type" { + ({ Nodes.Param.name; type_ = Nodes.Param_type.Concept Nodes.Concept.Type } : Nodes.Param.t) + } + | name=LIDENT "Number" { + ({ Nodes.Param.name; type_ = Nodes.Param_type.Concept Nodes.Concept.Number } : Nodes.Param.t) } %inline name_type: - | name=UIDENT { Nodes.Name_type.Simple name } - | pkg=LIDENT "$" name=UIDENT { Nodes.Name_type.Qualified (pkg, name) } + | name=UIDENT { Nodes.Name_type.Ident name } + | pkg=LIDENT "$" name=UIDENT { Nodes.Name_type.Qualified { package = pkg; ident = name } } %inline verb_type: | ret=ret_type "[" params=separated_list(",", param_type) "]" { - Nodes.Call_type.Func { params; ret_type = ret } + Nodes.Verb_type.Func { params; ret_type = ret } } | ret=ret_type "[" THIS this_type=type_expr params=loption(preceded(",", separated_nonempty_list(",", param_type))) "]" is_mut=boption(MUT) { - Nodes.Call_type.Meth { this_type; params; ret_type = ret; is_mut } + Nodes.Verb_type.Meth { this_type; params; ret_type = ret; is_mut } } - - From b447a62dd139ddf96442dd783c9c4791885965f9 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 16 Jul 2026 16:37:24 +0200 Subject: [PATCH 137/154] update --- lib/cst/parser.mly | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 24e7a465..f711b856 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -92,7 +92,6 @@ package: { Nodes.Meth_lambda.this_type; params; ret_type; is_mut; body } } -(* renamed: Generic_param_type -> Concept *) %inline concept: | "Type" { Nodes.Concept.Type @@ -175,8 +174,6 @@ decl: body; }) } - (* params is a plain list now, so loption (not ioption) is the right - combinator — it already yields [] when the <> header is absent. *) | "type" name=UIDENT params=loption(delimited("<", separated_nonempty_list(",", generic_param), ">")) "=" value=type_or_moulded { Nodes.Decl.Type { name; @@ -194,7 +191,7 @@ decl: %inline body_field: | name=LIDENT type_=type_expr ";" { - Nodes.Body_field { name; type_ } + { Nodes.Body_field.name; type_ } } %inline mould: @@ -207,20 +204,20 @@ decl: | ENUM "[" members=separated_nonempty_list(",", LIDENT) "]" { Nodes.Mould.Enum members } - | TUPLE "[" members=separated_nonempty_list(",", type_expr) "]"{ + | TUPLE "[" members=separated_nonempty_list(",", type_expr) "]" { Nodes.Mould.Tuple members } %inline moulded: | mould=mould { - Nodes.Moulded { mould; type_axis=Nodes.Type_axis.Value } + { Nodes.Moulded.mould; axis = Nodes.Type_axis.Value } } | "#" mould=mould { - Nodes.Moulded { mould; type_axis=Nodes.Type_axis.Reference } + { Nodes.Moulded.mould; axis = Nodes.Type_axis.Reference } } %inline type_or_moulded: - | type_expr=type_or_moulded { + | type_expr=type_expr { Nodes.Type_or_moulded.Raw type_expr } | moulded=moulded { From 92d2c6c3b99e898e5ac511729a57e50fb0314169 Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Thu, 16 Jul 2026 17:07:52 +0200 Subject: [PATCH 138/154] update --- lib/cst/nodes.ml | 1 + lib/cst/parser.mly | 80 ++++++++++++++++++++++++++++++++++++++++ lib/cst/to_tree_graph.ml | 1 + 3 files changed, 82 insertions(+) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 5525a369..835d3d7b 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -109,6 +109,7 @@ and Generic_arg : sig type t = | Type of Type_expr.t | Number of string + | Inferred of Param.t end = Generic_arg and Verb_type : sig diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index f711b856..d2041826 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -100,6 +100,30 @@ package: Nodes.Concept.Number } +%inline generic_arg: + | type_expr=type_expr { + Nodes.Generic_arg.Type type_expr + } + | number=INT { + Nodes.Generic_arg.Number number + } + | param=param { + Nodes.Generic_arg.Inferred param + } + +%inline generics: + | "<" generics=separated_nonempty_list(",", generic_arg) ">" { + generics + } + +type_expr: + | name=name_type generics=loption(generics) { + Nodes.Type_expr.Path { name; generics } + } + | verb_type=verb_type { + Nodes.Type_expr.Verb verb_type + } + %inline generic_param: | name=UIDENT "Type" { ({ Nodes.Generic_param.name; type_ = Nodes.Concept.Type } : Nodes.Generic_param.t) @@ -189,6 +213,62 @@ decl: } } +(* value-identifier counterpart to name_type — both segments lowercase + since Name_expr lives in the value namespace (LIDENT), unlike + Name_type's qualified form which ends in a UIDENT type name. *) +%inline name_expr: + | name=LIDENT { Nodes.Name_expr.Ident name } + | pkg=LIDENT "$" name=LIDENT { Nodes.Name_expr.Qualified { package = pkg; ident = name } } + +%inline comparison_op: + | "==" { Nodes.Operator.Eq } + | "<=" { Nodes.Operator.LessEq } + | ">=" { Nodes.Operator.MoreEq } + | "<" { Nodes.Operator.Less } + | ">" { Nodes.Operator.More } + +%inline additive_op: + | "+" { Nodes.Operator.Add } + | "-" { Nodes.Operator.Sub } + +%inline multiplicative_op: + | "*" { Nodes.Operator.Mul } + | "/" { Nodes.Operator.Div } + +(* used by decl's operator-overload form, e.g. `Int +(other Int) { ... }` — + a single bare operator token, no left/right operands involved there *) +%inline operator: + | op=comparison_op { op } + | op=additive_op { op } + | op=multiplicative_op { op } + +expr: + | i=INT { Nodes.Expr.IntLit i } + | f=FLOAT { Nodes.Expr.FloatLit f } + | s=STRING { Nodes.Expr.StrLit s } + | TRUE { Nodes.Expr.BoolLit true } + | FALSE { Nodes.Expr.BoolLit false } + | name_expr=name_expr { Nodes.Expr.NameExpr name_expr } + | "(" e=expr ")" { Nodes.Expr.Parenthized e } + | func_lambda=func_lambda { Nodes.Expr.FuncLambda func_lambda } + | meth_lambda=meth_lambda { Nodes.Expr.MethLambda meth_lambda } + | verb_call=verb_call { Nodes.Expr.VerbCall verb_call } + | target=expr "." field=LIDENT %prec DOT { + Nodes.Expr.DotAccess { target; field } + } + | left=expr op=comparison_op right=expr abort_handle=ioption(abort_handle) %prec EQEQ { + Nodes.Expr.VerbCall (Nodes.Verb_call.Op { op; left; right; abort_handle }) + } + | left=expr op=additive_op right=expr abort_handle=ioption(abort_handle) %prec PLUS { + Nodes.Expr.VerbCall (Nodes.Verb_call.Op { op; left; right; abort_handle }) + } + | left=expr op=multiplicative_op right=expr abort_handle=ioption(abort_handle) %prec STAR { + Nodes.Expr.VerbCall (Nodes.Verb_call.Op { op; left; right; abort_handle }) + } + | "~" value=expr abort_handle=ioption(abort_handle) %prec TILDE { + Nodes.Expr.VerbCall (Nodes.Verb_call.Flip { value; abort_handle }) + } + %inline body_field: | name=LIDENT type_=type_expr ";" { { Nodes.Body_field.name; type_ } diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 84f24a8c..29979d3d 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -68,6 +68,7 @@ and mould_to_node (x: Nodes.Mould.t) = match x with and generic_arg_to_node (x: Nodes.Generic_arg.t) = match x with | Type x -> type_to_node x | Number x -> group "number" (Leaf x) + | Inferred x -> group "param" (param_to_node x) and type_to_node (x: Nodes.Type_expr.t) = match x with | Verb x -> verb_type_to_node x From 12456239265ef45bc14bb10525079271f7d90eaf Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Thu, 16 Jul 2026 21:20:00 +0200 Subject: [PATCH 139/154] Parser: clear grammar warnings, add &-ref / @-intrinsic / immutable calls, kill method-call ambiguity (#35) * parser: add reference expr and immutable method call, fix warnings - add `&expr` reference-to-a-value expression (uses the AND token) - add `obj:method()` immutable method call alongside `obj!method()` mutable call; Verb_call.Meth now carries an is_mut flag - drop the redundant ERROR token; the lexer raises Lexing_error on an unrecognised character, formatted through the same parse-error path - remove the never-useful IF/ELSE precedence levels and the redundant %prec DOT on dot-access Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01PkF51jD8vywTCqcP4UNmXq * parser: add @ intrinsic namespace, remove class token - add `@package$name` intrinsic-namespace form to both name_type and name_expr (e.g. @primitives$I32, @funcs$strToI32("30")), modelled as an Intrinsic constructor mirroring Qualified; uses the AT token - remove the unused CLASS token and its lexer rule Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01PkF51jD8vywTCqcP4UNmXq * parser: stratify expr and unify calls to kill method-call ambiguity Split expr into primary / app (postfix chain) / expr (binary), so a call's receiver and a method name can no longer swallow a trailing binary operator. `a!b(c) * d(e)` now parses unambiguously as `(a!b(c)) * (d(e))` -- calls bind tighter than arithmetic -- rather than forking into two trees. Method calls `!`/`:` share one production (identical shape; the marker only selects the is_mut payload), and function and method calls are unified into a single form: a flexible `app` receiver with an optional (marker, primary-name) method part. The method name is a primary; the receiver is a full postfix expr. Removes the now-structural LPAREN/DOT precedence levels. Reduce/reduce conflict states drop 14 -> 6 and shift/reduce 54 -> 40; the whole method-call conflict family is gone. No node changes -- primary/app/expr all still yield Expr.t. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01PkF51jD8vywTCqcP4UNmXq --------- Co-authored-by: Claude --- lib/cst/cst.ml | 2 +- lib/cst/lexer.ml | 7 ++++-- lib/cst/nodes.ml | 7 +++++- lib/cst/parser.mly | 50 ++++++++++++++++++++++++++++------------ lib/cst/to_tree_graph.ml | 7 +++++- 5 files changed, 53 insertions(+), 20 deletions(-) diff --git a/lib/cst/cst.ml b/lib/cst/cst.ml index ede91170..81bd9b51 100644 --- a/lib/cst/cst.ml +++ b/lib/cst/cst.ml @@ -8,6 +8,6 @@ let parse filename input = let tokenizer = Sedlexing.with_tokenizer Lexer.token lexbuf in try Ok (MenhirLib.Convert.Simplified.traditional2revised Parser.package tokenizer) - with Parser.Error _tokenizer -> + with Parser.Error _tokenizer | Lexer.Lexing_error -> let (pos_start, pos_end) = Sedlexing.lexing_positions lexbuf in Error (Parse_error.format_parse_error filename input pos_start pos_end) diff --git a/lib/cst/lexer.ml b/lib/cst/lexer.ml index 96754ea0..f1b6ec53 100644 --- a/lib/cst/lexer.ml +++ b/lib/cst/lexer.ml @@ -1,6 +1,10 @@ open Sedlexing open Parser +(* Raised on a character that starts no valid token. Position is read from the + lexbuf by the caller, the same way a [Parser.Error] is located. *) +exception Lexing_error + let digit = [%sedlex.regexp? '0'..'9'] let digits = [%sedlex.regexp? Plus digit] let int_lit = [%sedlex.regexp? digits, Star ('\'', digits)] @@ -56,7 +60,6 @@ let rec token buf = | "alias" -> ALIAS | "Type" -> UTYPE | "Number" -> NUMBER - | "class" -> CLASS | "struct" -> STRUCT | "variant" -> VARIANT | "tuple" -> TUPLE @@ -77,4 +80,4 @@ let rec token buf = | lower_ident -> LIDENT (Utf8.lexeme buf) | upper_ident -> UIDENT (Utf8.lexeme buf) | eof -> EOF - | _ -> ERROR + | _ -> raise Lexing_error diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index 835d3d7b..e5d37af4 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -26,6 +26,8 @@ module Name_type = struct type t = | Ident of string | Qualified of { package : string; ident : string } + (* intrinsic namespace, spelled @package$Ident, e.g. @primitives$I32 *) + | Intrinsic of { package : string; ident : string } end module Concept = struct @@ -51,6 +53,8 @@ module Name_expr = struct type t = | Ident of string | Qualified of { package : string; ident : string } + (* intrinsic namespace, spelled @package$ident, e.g. @funcs$strToI32 *) + | Intrinsic of { package : string; ident : string } end module rec Expr : sig @@ -61,6 +65,7 @@ module rec Expr : sig | BoolLit of bool | NameExpr of Name_expr.t | DotAccess of { target : t; field : string } + | Ref of t | Parenthized of t | VerbCall of Verb_call.t | FuncLambda of Func_lambda.t @@ -77,7 +82,7 @@ end = Abort_handle and Verb_call : sig type t = | Func of { callee: Expr.t; args: Expr.t list; abort_handle: Abort_handle.t option; } - | Meth of { callee: Expr.t; this: Expr.t; args: Expr.t list; abort_handle: Abort_handle.t option; } + | Meth of { callee: Expr.t; this: Expr.t; args: Expr.t list; abort_handle: Abort_handle.t option; is_mut: bool; } | Constructor of { name_type: Name_type.t; args: Expr.t list; abort_handle: Abort_handle.t option; } | Op of { op: Operator.t; left: Expr.t; right: Expr.t; abort_handle: Abort_handle.t option; } | Flip of { value: Expr.t; abort_handle: Abort_handle.t option; } diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index d2041826..601cef46 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -40,7 +40,6 @@ %token ALIAS "alias" %token UTYPE "Type" %token NUMBER "Number" -%token CLASS "class" %token STRUCT "struct" %token VARIANT "variant" %token TUPLE "tuple" @@ -58,17 +57,12 @@ %token ABORT "abort" %token RETURN "return" %token RESOLVE "resolve" -%token ERROR "" %token EOF "" %nonassoc EQEQ LESSEQ MOREEQ LESS MORE /* comparisons */ %left PLUS MINUS %left STAR SLASH -%left LPAREN /* function application */ -%nonassoc IF -%nonassoc ELSE -%nonassoc TILDE /* prefix ~ */ -%left DOT /* field access */ +%nonassoc TILDE AND /* prefix ~ and & */ %start package @@ -219,6 +213,7 @@ decl: %inline name_expr: | name=LIDENT { Nodes.Name_expr.Ident name } | pkg=LIDENT "$" name=LIDENT { Nodes.Name_expr.Qualified { package = pkg; ident = name } } + | "@" pkg=LIDENT "$" name=LIDENT { Nodes.Name_expr.Intrinsic { package = pkg; ident = name } } %inline comparison_op: | "==" { Nodes.Operator.Eq } @@ -242,7 +237,8 @@ decl: | op=additive_op { op } | op=multiplicative_op { op } -expr: +(* atoms: literals, names, parenthesised exprs, lambdas *) +primary: | i=INT { Nodes.Expr.IntLit i } | f=FLOAT { Nodes.Expr.FloatLit f } | s=STRING { Nodes.Expr.StrLit s } @@ -252,10 +248,18 @@ expr: | "(" e=expr ")" { Nodes.Expr.Parenthized e } | func_lambda=func_lambda { Nodes.Expr.FuncLambda func_lambda } | meth_lambda=meth_lambda { Nodes.Expr.MethLambda meth_lambda } + +(* postfix chain: calls, method calls, field access. binds tighter than the + binary operators, so `a!b(c) * d(e)` is `(a!b(c)) * (d(e))`, unambiguously. *) +app: + | primary=primary { primary } | verb_call=verb_call { Nodes.Expr.VerbCall verb_call } - | target=expr "." field=LIDENT %prec DOT { + | target=app "." field=LIDENT { Nodes.Expr.DotAccess { target; field } } + +expr: + | app=app { app } | left=expr op=comparison_op right=expr abort_handle=ioption(abort_handle) %prec EQEQ { Nodes.Expr.VerbCall (Nodes.Verb_call.Op { op; left; right; abort_handle }) } @@ -268,6 +272,9 @@ expr: | "~" value=expr abort_handle=ioption(abort_handle) %prec TILDE { Nodes.Expr.VerbCall (Nodes.Verb_call.Flip { value; abort_handle }) } + | "&" value=expr %prec AND { + Nodes.Expr.Ref value + } %inline body_field: | name=LIDENT type_=type_expr ";" { @@ -328,14 +335,26 @@ body: Nodes.Abort_handle.Shorthand value } +(* mutable (!) and immutable (:) method calls are structurally identical, so + they share one production; the marker only decides the is_mut payload. *) +%inline meth_marker: + | "!" { true } + | ":" { false } + +%inline meth_part: + | is_mut=meth_marker name=primary { (is_mut, name) } + +(* a single call form: a flexible postfix receiver, then an optional method + part. no method part => function call; a method part => method call, with + the receiver as `this` and the (primary) name as the callee. *) verb_call: - | callee=expr "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) %prec LPAREN { - Nodes.Verb_call.Func { callee; args; abort_handle } - } - | this=expr "!" callee=expr "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) %prec LPAREN { - Nodes.Verb_call.Meth { callee; this; args; abort_handle } + | receiver=app part=ioption(meth_part) "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) { + match part with + | None -> Nodes.Verb_call.Func { callee = receiver; args; abort_handle } + | Some (is_mut, name) -> + Nodes.Verb_call.Meth { this = receiver; callee = name; args; abort_handle; is_mut } } - | name_type=name_type "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) %prec LPAREN { + | name_type=name_type "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) { Nodes.Verb_call.Constructor { name_type; args; abort_handle } } @@ -402,6 +421,7 @@ stat: %inline name_type: | name=UIDENT { Nodes.Name_type.Ident name } | pkg=LIDENT "$" name=UIDENT { Nodes.Name_type.Qualified { package = pkg; ident = name } } + | "@" pkg=LIDENT "$" name=UIDENT { Nodes.Name_type.Intrinsic { package = pkg; ident = name } } %inline verb_type: | ret=ret_type "[" params=separated_list(",", param_type) "]" { diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 29979d3d..00ed3af7 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -26,10 +26,12 @@ open Tree_graph let name_type_to_node (x: Nodes.Name_type.t) = match x with | Ident s -> Leaf s | Qualified { package; ident } -> Leaf (package ^ "$" ^ ident) + | Intrinsic { package; ident } -> Leaf ("@" ^ package ^ "$" ^ ident) let name_expr_to_node (x: Nodes.Name_expr.t) = match x with | Ident s -> Leaf s | Qualified { package; ident } -> Leaf (package ^ "$" ^ ident) + | Intrinsic { package; ident } -> Leaf ("@" ^ package ^ "$" ^ ident) let rec concept_to_node (x: Nodes.Concept.t) = match x with | Type -> Leaf "Type" @@ -85,11 +87,12 @@ and verb_call_to_node (x: Nodes.Verb_call.t) = match x with ("args", map_seq expr_to_node args); ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); ]) - | Meth { callee; this; args; abort_handle } -> + | Meth { callee; this; args; abort_handle; is_mut } -> group "meth_call" (fields [ ("callee", expr_to_node callee); ("this", expr_to_node this); ("args", map_seq expr_to_node args); + ("is_mut", Leaf (string_of_bool is_mut)); ("abort", Option.map abort_handle_to_node abort_handle |> Option.value ~default:(Leaf "none")); ]) | Constructor { name_type; args; abort_handle } -> @@ -122,6 +125,8 @@ and expr_to_node (x: Nodes.Expr.t) = match x with ("target", expr_to_node target); ("field", Leaf field); ]) + | Ref x -> + group "ref" (expr_to_node x) | Parenthized x -> group "parenthized" (expr_to_node x) | FuncLambda x -> From 166afc32aaeb6f9fbe523537ad6c4f49626a7fbd Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:44:23 +0200 Subject: [PATCH 140/154] Add optimized GLR ambiguity search (#36) * Add bounded ambiguity search recipe * Add bounded Menhir ambiguity finder * Prune inactive ambiguity lookaheads * Configure optimized ambiguity search executable * Add optimized parallel OCaml ambiguity search * Use parallel OCaml ambiguity search by default * Address ambiguity search review feedback * Report multiple ambiguity families * Expose ambiguity witness limit * Bound queued ambiguity frontiers * Add controlled syntax experiment harness * Test syntax experiment transformations * Document syntax experiment workflow * Add syntax experiment recipes * Respell known witnesses in each variant's syntax (#37) * Harden worker waits, file reads, and search invocation - retry Unix.waitpid on EINTR so signal delivery cannot abort result collection - close the read_lines channel with Fun.protect on any exception - strip trailing carriage returns before parsing token declarations - run syntax experiments against a prebuilt ambiguity_search.exe instead of concurrent dune exec, validating the executable up front with a build hint - build the executable in the syntax-experiment justfile recipes Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01QR6jhw2CXW3oQbBTT4C1aR * Respell known witnesses in each variant's syntax Each grammar transformation now registers a matching spelling update, and every known case builds its intended program from the composed spelling profile. A rejection now means the variant genuinely cannot parse the intended program, never that the old spelling became illegal; cases a variant cannot express at all are labeled explicitly and counted as rejected. Adds a plain named-call compatibility probe (print("hello"), spelled print["hello"] under bracket-calls) that every variant must parse exactly once, plus focused spelling tests. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01QR6jhw2CXW3oQbBTT4C1aR * Add anchored-abort-handle experiment variants A deep 10M-frontier search found 49 complete ambiguity families, of which 47 pivot on abort-handler attachment: every operator and call production carries its own optional handler suffix, so ?? and ? handlers can attach at multiple nesting depths of one undelimited expression. The new anchored-abort-handles transform removes the per-production slots and allows handlers only at delimited boundaries (statement calls, declaration values, return/resolve/abort values, call arguments, and grouping parentheses). Witness spellings are unchanged, so the spelling update is the identity. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01QR6jhw2CXW3oQbBTT4C1aR * Document the ambiguity policy for the GLR grammar Zane's grammar is deliberately not LR(1) and stays GLR-parsed, but must remain provably unambiguous: every LR conflict state carries either a documented precedence resolution, a transience argument, or a tracked open obligation that the bounded ambiguity search continuously attacks. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01QR6jhw2CXW3oQbBTT4C1aR * Add a conservative unambiguity prover (--prove) Abstract GLR stacks to their top-K states, with reductions that pop into the unknown region re-entering through every goto edge on the reduced nonterminal. The abstract configuration space is finite, so a pair search over runs consuming the same input terminates: if no pair of runs diverges and still accepts, the grammar is proven unambiguous with no sentence-length bound. Reduction chains advance in lockstep so shared cycles cancel, divergence is recognized only where two parses of one sentence can first part ways (different productions, or reducing against shifting), and a non-diverged pair with equal suffixes resolves unknown-base gotos identically on both sides because it is still a single run. An abstract candidate is concretized with the existing bounded search: witnesses mean ambiguous (exit 1), otherwise the verdict is not-proven (exit 3); a proof exits 0. Validated on known-ambiguous, LR(1), precedence-resolved, and unambiguous non-LR grammars (palindromes), on the Zane baseline (ambiguous, real witnesses), and on the anchored-handles variant (not proven at 10 tokens, ambiguous with witnesses at 12). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01QR6jhw2CXW3oQbBTT4C1aR * Check search executables portably and hoist joint move lookups Use os.path.dirname to detect a path-like search command so the existence check also runs on Windows, and bind both sides' move lists outside the joint pairing loops instead of re-looking one side up per inner iteration. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01QR6jhw2CXW3oQbBTT4C1aR --------- Co-authored-by: Claude * Address ambiguity search review feedback --------- Co-authored-by: Claude --- docs/ambiguity.md | 66 ++ justfile | 28 + tools/SYNTAX_EXPERIMENTS.md | 122 +++ tools/ambiguity_search.ml | 1249 ++++++++++++++++++++++++++++++ tools/dune | 3 + tools/find_ambiguity.py | 374 +++++++++ tools/syntax_experiments.py | 1089 ++++++++++++++++++++++++++ tools/test_syntax_experiments.py | 140 ++++ 8 files changed, 3071 insertions(+) create mode 100644 docs/ambiguity.md create mode 100644 tools/SYNTAX_EXPERIMENTS.md create mode 100644 tools/ambiguity_search.ml create mode 100644 tools/dune create mode 100644 tools/find_ambiguity.py create mode 100644 tools/syntax_experiments.py create mode 100644 tools/test_syntax_experiments.py diff --git a/docs/ambiguity.md b/docs/ambiguity.md new file mode 100644 index 00000000..bc86781a --- /dev/null +++ b/docs/ambiguity.md @@ -0,0 +1,66 @@ +# Ambiguity policy + +Zane's grammar is deliberately not LR(1): the language is parsed with a +GLR+LR hybrid (menhirGLR, previously Elkhound), and constructs may require +unbounded lookahead. Nondeterminism is accepted; ambiguity is not. + +**Policy: the grammar must remain provably unambiguous.** A GLR parser may +fork wherever it needs to, but on every input all forks except one must +eventually die. General context-free ambiguity is undecidable, so no tool +can certify this automatically for arbitrary grammars — instead the proof +is maintained as a finite set of per-conflict obligations, which is +possible because every fork point is an LR conflict state and Menhir +enumerates those exhaustively. + +## Proof obligations + +Every LR conflict state must carry exactly one of: + +1. **A precedence resolution.** The conflict is resolved by a declared + precedence or associativity; the resolution is deliberate and the + intended reading is documented. Resolved conflicts are deterministic and + need no further argument. +2. **A transience argument.** A short written proof that the two branches + of the fork can never both reach acceptance, keyed to the conflict + state's LR items so that grammar changes touching the construct + visibly invalidate the argument. +3. **An open obligation.** Permitted, but tracked: open obligations are the + standing targets of the bounded ambiguity search, and a found witness + turns one into a bug. + +A grammar change that introduces a new conflict state is incomplete until +the state is triaged into one of these categories. + +## Tooling + +- `just ambiguities` — bounded, parallel GLR search for complete ambiguous + sentences (`tools/ambiguity_search.ml`). A completed bound is a theorem + ("no ambiguous sentence of at most N tokens"); an interrupted bound is + evidence only. Witnesses are grouped by the conflict states they + traverse, which maps each finding directly onto an obligation above. +- `just prove` — conservative unambiguity prover (`--prove K`). It abstracts + GLR stacks to their top-K states and exhaustively explores pairs of + abstract parses of the same input, comparing reduction chains in lockstep. + Three verdicts: exit 0 "PROVEN UNAMBIGUOUS" is a genuine proof with no + sentence-length bound; exit 1 means a concrete ambiguous sentence was + found; exit 3 means not proven — the abstraction reported a candidate the + bounded search could not concretize, so raise `--prove` or the search + bounds. Because unambiguity is undecidable in general, the "not proven" + verdict can never be eliminated entirely; the prover is validated against + known-ambiguous grammars, LR(1) grammars, precedence-resolved expression + grammars, and unambiguous non-LR grammars such as palindromes. +- `just syntax-experiments` — compares candidate grammar changes under + equal search bounds before they are adopted + (`tools/SYNTAX_EXPERIMENTS.md`). +- `menhir --explain` — enumerates the conflict states that constitute the + obligation ledger. + +## Why this is sound + +Unambiguity of an arbitrary grammar admits no complete decision procedure, +but a *specific* grammar is proven unambiguous by a finite argument when +its structure supports one. Keeping the obligations discharged is exactly +keeping such a finite argument in existence at all times: determinism +certificates where the grammar is locally LR, human induction arguments +where it is not, and exhaustive bounded search as the continuous attempt at +falsification. diff --git a/justfile b/justfile index de805efd..6632ab08 100644 --- a/justfile +++ b/justfile @@ -18,3 +18,31 @@ stats: conflicts: menhir {{ grammarFile }} --random-sentence-concrete package --random-seed 1 --random-sentence-length 16 + +# Find a short complete ambiguity within a bounded, parallel GLR search. +ambiguities max_tokens="20" timeout="60" max_frontiers="500000" jobs="4" max_witnesses="20" menhir="menhir": + dune exec tools/ambiguity_search.exe -- {{ grammarFile }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --jobs {{ jobs }} --max-witnesses {{ max_witnesses }} + +# Conservative unambiguity proof attempt: exit 0 proven, 1 ambiguous, 3 not proven. +prove level="2" max_tokens="12" timeout="120" max_frontiers="2000000" jobs="4" menhir="menhir": + dune exec tools/ambiguity_search.exe -- {{ grammarFile }} --prove {{ level }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --jobs {{ jobs }} + +# Slower reference implementation, useful for cross-checking the OCaml search. +ambiguities-python max_tokens="20" timeout="60" max_frontiers="500000" menhir="menhir": + python3 tools/find_ambiguity.py {{ grammarFile }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} + +# Compare all controlled syntax variants and write Markdown/JSON reports. +syntax-experiments max_tokens="12" timeout="15" max_frontiers="150000" max_witnesses="10" jobs="4" menhir="menhir": + dune build tools/ambiguity_search.exe + python3 tools/syntax_experiments.py {{ grammarFile }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --max-witnesses {{ max_witnesses }} --jobs {{ jobs }} + +# Run one named variant, for example: just syntax-experiment semicolon-separated +syntax-experiment variant max_tokens="16" timeout="60" max_frontiers="500000" max_witnesses="20" menhir="menhir": + dune build tools/ambiguity_search.exe + python3 tools/syntax_experiments.py {{ grammarFile }} --variant {{ variant }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --max-witnesses {{ max_witnesses }} + +syntax-experiments-list: + python3 tools/syntax_experiments.py --list + +syntax-experiments-test: + python3 -m unittest tools.test_syntax_experiments -v diff --git a/tools/SYNTAX_EXPERIMENTS.md b/tools/SYNTAX_EXPERIMENTS.md new file mode 100644 index 00000000..b7755acd --- /dev/null +++ b/tools/SYNTAX_EXPERIMENTS.md @@ -0,0 +1,122 @@ +# Syntax experiments + +`syntax_experiments.py` compares small, explicit changes to Zane's concrete +syntax. It generates a temporary Menhir grammar for every selected variant, +replays the known complete-ambiguity witnesses, runs the bounded ambiguity +search, and produces Markdown and JSON reports. + +This is deliberately not a grammar-rewriting model. Every mutation is named, +reviewable, composable, and assigned an approximate edit cost. + +## Quick start + +```sh +just syntax-experiments-list +just syntax-experiments +just syntax-experiment semicolon-separated +``` + +Reports are written to: + +```text +_build/syntax-experiments/report.md +_build/syntax-experiments/report.json +``` + +Generated grammars normally live only for the duration of a run. To inspect +them directly: + +```sh +python3 tools/syntax_experiments.py --emit-only \ + --emit-dir _build/syntax-experiments/grammars +``` + +## Included ideas + +The predefined candidates cover: + +- semicolons required between adjacent statements; +- semicolons required after every statement; +- only statically named functions, methods, and constructors as call statements; +- significant newline separators; +- `[]`, `{}`, or `group()` expression grouping; +- removing general grouping; +- `[]`, `@()`, or `.()` for all calls; +- ordinary calls for names with `@()` or `[]` reserved for computed callees; +- abort handlers anchored to delimited boundaries (statement calls, + declaration values, `return`/`resolve`/`abort` values, call arguments, and + grouping) instead of every expression production; +- combinations of the most promising statement, grouping, call, and + abort-handler changes. + +The named-statement experiment still permits computed calls inside expressions. +It only prevents a computed call such as `(x)()` from independently reducing to +a statement. Named method calls remain valid statements even when their receiver +is computed. + +The `semicolon-separated` experiment requires a semicolon only where another +statement follows and permits one trailing semicolon. The stricter +`semicolon-terminated` experiment requires a terminator after every declaration +and statement, including the final item in a block. + +## Measurements + +Known witnesses are **respelled in each variant's own syntax** before being +replayed: every transformation that changes surface spelling registers a +matching update in `SPELLINGS`, and each known case builds its intended +program from the resulting spelling profile. A rejection therefore means the +variant genuinely cannot parse the intended program — never that an old +spelling merely became illegal. A case a variant cannot express at all (for +example a computed-call statement under `named-statement-calls`) is labeled +"not expressible" and counted as rejected. + +Alongside the ambiguity witnesses, the case set includes one plain +compatibility probe: an ordinary named call statement, `print("hello")`, +which every variant is expected to parse exactly once (spelled +`print["hello"]` under `bracket-calls`, and so on). + +For each candidate, the report records: + +- whether each known witness has zero, one, or two accepting derivations; +- complete ambiguity profiles found within the configured bounds; +- explored and unique frontiers; +- conflict seeds; +- search limits and elapsed time; +- up to five shortest concrete witnesses; +- an approximate syntax edit cost. + +A candidate that rejects a known program is penalized separately from one that +still parses it ambiguously. A zero-witness result that stopped at a timeout or +frontier limit is marked uncertain rather than ambiguity-free. + +The Pareto marker means that no other tested candidate was at least as good on +every measured axis. It is not an automatic language-design decision: readability, +orthogonality, and whether a changed spelling expresses Zane's intent still need +human judgment. + +## Adding an experiment + +1. Add a transformation function that uses `replace_once` or another checked + structural edit. A changed grammar anchor must fail loudly rather than silently + producing the baseline grammar. +2. Register it in `TRANSFORMS`, and register a matching spelling update in + `SPELLINGS` (the identity update for transforms that do not change how the + known witnesses are spelled). The two tables must cover the same names. +3. Add one or more `Variant` entries, including useful combinations and an edit + cost. +4. Add focused assertions to `test_syntax_experiments.py`. +5. Run `just syntax-experiments-test`, then a short single-variant search before + comparing the full matrix. + +## Limitations + +The ambiguity search is bounded because ambiguity of arbitrary context-free +grammars is undecidable. Results compare evidence found under equal bounds; they +do not prove global unambiguity. + +These variants mutate the parser grammar only. A candidate that introduces a +token such as `NEWLINE` or `group` would also require a corresponding lexer +change before it could become real language syntax. Likewise, compatibility is +currently measured with token witnesses rather than a large source-to-AST corpus. +Adding an AST golden corpus is the natural next step once enough representative +Zane programs exist. diff --git a/tools/ambiguity_search.ml b/tools/ambiguity_search.ml new file mode 100644 index 00000000..2bc0e22d --- /dev/null +++ b/tools/ambiguity_search.ml @@ -0,0 +1,1249 @@ +(* Bounded complete-ambiguity search for Menhir automata. The search retains + unresolved LR actions as GLR branches, caps derivation counts at two, and + accepts a witness only when two derivations recognize the start symbol. *) + +module StringSet = Set.Make (String) +module IntMap = Map.Make (Int) +module ConflictSet = Set.Make (struct + type t = int * string + let compare = compare +end) + +type reduction = { lhs : string; width : int; prod : int } + +type state = { + transitions : (string, int) Hashtbl.t; + reductions : (string, reduction list) Hashtbl.t; + mutable accepts : StringSet.t; +} + +type automaton = { + states : state array; + terminals : StringSet.t; + aliases : (string, string) Hashtbl.t; +} + +let empty_state () = + { + transitions = Hashtbl.create 16; + reductions = Hashtbl.create 16; + accepts = StringSet.empty; + } + +let cap_add a b = min 2 (a + b) + +let words_re = Str.regexp "[ \t]+" + +let words text = + if String.trim text = "" then [] + else Str.split words_re (String.trim text) + +let read_lines path = + let channel = open_in path in + Fun.protect ~finally:(fun () -> close_in channel) (fun () -> + let rec loop result = + match input_line channel with + | line -> loop (line :: result) + | exception End_of_file -> List.rev result + in + loop []) + +let read_file path = + let channel = open_in_bin path in + Fun.protect ~finally:(fun () -> close_in channel) (fun () -> + let length = in_channel_length channel in + really_input_string channel length) + +let split_lines source = + List.map + (fun line -> + let length = String.length line in + if length > 0 && line.[length - 1] = '\r' then + String.sub line 0 (length - 1) + else line) + (String.split_on_char '\n' source) + +let strip_comments source = + let length = String.length source in + let buffer = Buffer.create length in + let rec normal index = + if index >= length then () + else if index + 1 < length && source.[index] = '(' && source.[index + 1] = '*' + then ocaml_comment 1 (index + 2) + else if index + 1 < length && source.[index] = '/' && source.[index + 1] = '*' + then c_comment (index + 2) + else begin + Buffer.add_char buffer source.[index]; + normal (index + 1) + end + and ocaml_comment depth index = + if index >= length then () + else if index + 1 < length && source.[index] = '(' && source.[index + 1] = '*' + then ocaml_comment (depth + 1) (index + 2) + else if index + 1 < length && source.[index] = '*' && source.[index + 1] = ')' + then if depth = 1 then normal (index + 2) else ocaml_comment (depth - 1) (index + 2) + else begin + if source.[index] = '\n' then Buffer.add_char buffer '\n'; + ocaml_comment depth (index + 1) + end + and c_comment index = + if index >= length then () + else if index + 1 < length && source.[index] = '*' && source.[index + 1] = '/' + then normal (index + 2) + else begin + if source.[index] = '\n' then Buffer.add_char buffer '\n'; + c_comment (index + 1) + end + in + normal 0; + Buffer.contents buffer + +let token_decl_re = + Str.regexp "^[ \t]*%token\\([ \t]+<[^>]+>\\)?[ \t]+\\(.*\\)$" + +let is_uppercase = function 'A' .. 'Z' -> true | _ -> false +let is_token_char = function 'A' .. 'Z' | '0' .. '9' | '_' -> true | _ -> false + +let parse_token_specs text add = + let length = String.length text in + let rec skip index = + if index < length && not (is_uppercase text.[index]) then skip (index + 1) + else index + in + let rec token_end index = + if index < length && is_token_char text.[index] then token_end (index + 1) + else index + in + let rec whitespace index = + if index < length && (text.[index] = ' ' || text.[index] = '\t') then + whitespace (index + 1) + else index + in + let rec quoted_end escaped index = + if index >= length then length + else if escaped then quoted_end false (index + 1) + else if text.[index] = '\\' then quoted_end true (index + 1) + else if text.[index] = '"' then index + else quoted_end false (index + 1) + in + let rec loop index = + let start = skip index in + if start < length then begin + let finish = token_end start in + let token = String.sub text start (finish - start) in + let after = whitespace finish in + if after < length && text.[after] = '"' then begin + let quote_end = quoted_end false (after + 1) in + let raw = String.sub text (after + 1) (quote_end - after - 1) in + add token (Some raw); + loop (min length (quote_end + 1)) + end + else begin + add token None; + loop finish + end + end + in + loop 0 + +let parse_tokens grammar = + let terminals = ref StringSet.empty in + let aliases = Hashtbl.create 64 in + let source = strip_comments (read_file grammar) in + List.iter + (fun line -> + if Str.string_match token_decl_re line 0 then + parse_token_specs (Str.matched_group 2 line) (fun token alias -> + terminals := StringSet.add token !terminals; + Option.iter + (fun alias -> + let alias = try Scanf.unescaped alias with _ -> alias in + Hashtbl.replace aliases token alias) + alias)) + (split_lines source); + (!terminals, aliases) + +let quote = Filename.quote + +let run command = + match Sys.command command with + | 0 -> true + | _ -> false + +let prepare_automaton ~menhir ~grammar ~directory = + let expanded = Filename.concat directory "expanded.mly" in + let preprocess_error = Filename.concat directory "preprocess.err" in + let preprocess = + Printf.sprintf "%s --only-preprocess-uu %s > %s 2> %s" + (quote menhir) (quote grammar) (quote expanded) (quote preprocess_error) + in + if not (run preprocess) then begin + List.iter prerr_endline (read_lines preprocess_error); + failwith "Menhir failed to preprocess the grammar" + end; + let base = Filename.concat directory "automaton" in + let build_error = Filename.concat directory "automaton.err" in + let build = + Printf.sprintf "%s --dump --base %s %s > /dev/null 2> %s" + (quote menhir) (quote base) (quote expanded) (quote build_error) + in + ignore (run build); + let automaton = base ^ ".automaton" in + if not (Sys.file_exists automaton) then begin + List.iter prerr_endline (read_lines build_error); + failwith "Menhir did not produce an LR automaton" + end; + automaton + +let state_re = Str.regexp "^State \\([0-9]+\\):$" +let transition_re = + Str.regexp "^-- On \\([^ ]+\\) shift to state \\([0-9]+\\)$" +let lookahead_re = Str.regexp "^-- On \\(.+\\)$" +let reduction_re = Str.regexp "^-- reduce production \\(.+\\) ->\\(.*\\)$" +let accept_re = Str.regexp "^-- accept \\([^ ]+\\)$" + +let parse_automaton path terminals aliases = + let table = Hashtbl.create 1024 in + let current = ref None in + let lookaheads = ref [] in + let productions = Hashtbl.create 512 in + let intern_production text = + match Hashtbl.find_opt productions text with + | Some id -> id + | None -> + let id = Hashtbl.length productions in + Hashtbl.add productions text id; + id + in + let get_state number = + match Hashtbl.find_opt table number with + | Some state -> state + | None -> + let state = empty_state () in + Hashtbl.add table number state; + state + in + List.iter + (fun line -> + if Str.string_match state_re line 0 then begin + let number = int_of_string (Str.matched_group 1 line) in + current := Some (get_state number); + lookaheads := [] + end + else + match !current with + | None -> () + | Some state -> + if Str.string_match transition_re line 0 then begin + let symbol = Str.matched_group 1 line in + let target = int_of_string (Str.matched_group 2 line) in + Hashtbl.replace state.transitions symbol target; + lookaheads := [] + end + else if Str.string_match lookahead_re line 0 then + lookaheads := words (Str.matched_group 1 line) + else if Str.string_match reduction_re line 0 then begin + let lhs = String.trim (Str.matched_group 1 line) in + let rhs = String.trim (Str.matched_group 2 line) in + let reduction = + { + lhs; + width = List.length (words rhs); + prod = intern_production (lhs ^ " -> " ^ rhs); + } + in + List.iter + (fun token -> + let previous = + Option.value (Hashtbl.find_opt state.reductions token) + ~default:[] + in + Hashtbl.replace state.reductions token + (reduction :: previous)) + !lookaheads + end + else if Str.string_match accept_re line 0 then + List.iter + (fun token -> + state.accepts <- StringSet.add token state.accepts) + !lookaheads) + (read_lines path); + let maximum = Hashtbl.fold (fun number _ value -> max number value) table 0 in + let states = Array.init (maximum + 1) (fun number -> get_state number) in + { states; terminals; aliases } + +module Stack_pool = struct + type node = { + id : int; + state : int; + parent : node option; + depth : int; + } + + type t = { + by_edge : ((int * int), node) Hashtbl.t; + by_id : (int, node) Hashtbl.t; + mutable next_id : int; + root : node; + } + + let create () = + let root = { id = 0; state = 0; parent = None; depth = 0 } in + let by_id = Hashtbl.create 16_384 in + Hashtbl.add by_id 0 root; + { + by_edge = Hashtbl.create 16_384; + by_id; + next_id = 1; + root; + } + + let find pool id = Hashtbl.find pool.by_id id + + let push pool parent state = + let edge = (parent.id, state) in + match Hashtbl.find_opt pool.by_edge edge with + | Some node -> node + | None -> + let node = + { + id = pool.next_id; + state; + parent = Some parent; + depth = parent.depth + 1; + } + in + pool.next_id <- pool.next_id + 1; + Hashtbl.add pool.by_edge edge node; + Hashtbl.add pool.by_id node.id node; + node + + let rec pop node count = + if count = 0 then Some node + else + match node.parent with + | None -> None + | Some parent -> pop parent (count - 1) +end + +type frontier = int IntMap.t +type signature = (int * int) list + +let add_count stack_id count frontier = + let old = Option.value (IntMap.find_opt stack_id frontier) ~default:0 in + let updated = cap_add old count in + (IntMap.add stack_id updated frontier, updated - old) + +let signature frontier = IntMap.bindings frontier + +let derivations frontier = + IntMap.fold (fun _ count total -> cap_add total count) frontier 0 + +type engine = { + automaton : automaton; + stacks : Stack_pool.t; + closure_cache : ((int * string), frontier) Hashtbl.t; +} + +let reductions state token = + Option.value (Hashtbl.find_opt state.reductions token) ~default:[] + +let closure_one engine stack_id token = + match Hashtbl.find_opt engine.closure_cache (stack_id, token) with + | Some result -> result + | None -> + let closure = ref (IntMap.singleton stack_id 1) in + let propagated = Hashtbl.create 16 in + let queue = Queue.create () in + Queue.add stack_id queue; + while not (Queue.is_empty queue) do + let current_id = Queue.take queue in + let count = IntMap.find current_id !closure in + let sent = + Option.value (Hashtbl.find_opt propagated current_id) ~default:0 + in + let available = count - sent in + if available > 0 then begin + Hashtbl.replace propagated current_id count; + let current = Stack_pool.find engine.stacks current_id in + let state = engine.automaton.states.(current.state) in + List.iter + (fun reduction -> + match Stack_pool.pop current reduction.width with + | None -> () + | Some base -> + (match + Hashtbl.find_opt + engine.automaton.states.(base.state).transitions + reduction.lhs + with + | None -> () + | Some target -> + let reduced = Stack_pool.push engine.stacks base target in + let updated, delta = + add_count reduced.id available !closure + in + closure := updated; + if delta > 0 then Queue.add reduced.id queue)) + (reductions state token) + end + done; + Hashtbl.add engine.closure_cache (stack_id, token) !closure; + !closure + +let closure engine frontier token = + IntMap.fold + (fun stack_id outer_count result -> + IntMap.fold + (fun reduced_id inner_count result -> + fst + (add_count reduced_id + (min 2 (outer_count * inner_count)) + result)) + (closure_one engine stack_id token) result) + frontier IntMap.empty + +let shift engine frontier token = + IntMap.fold + (fun stack_id count result -> + let stack = Stack_pool.find engine.stacks stack_id in + match + Hashtbl.find_opt engine.automaton.states.(stack.state).transitions token + with + | None -> result + | Some target -> + let shifted = Stack_pool.push engine.stacks stack target in + fst (add_count shifted.id count result)) + (closure engine frontier token) IntMap.empty + +let accepted_count engine frontier = + IntMap.fold + (fun stack_id count total -> + let stack = Stack_pool.find engine.stacks stack_id in + if + StringSet.mem "#" + engine.automaton.states.(stack.state).accepts + then cap_add total count + else total) + (closure engine frontier "#") 0 + +let possible_tokens engine frontier = + IntMap.fold + (fun stack_id _ tokens -> + let stack = Stack_pool.find engine.stacks stack_id in + let state = engine.automaton.states.(stack.state) in + let tokens = + Hashtbl.fold + (fun symbol _ tokens -> + if StringSet.mem symbol engine.automaton.terminals then + StringSet.add symbol tokens + else tokens) + state.transitions tokens + in + Hashtbl.fold + (fun token _ tokens -> + if token = "#" then tokens else StringSet.add token tokens) + state.reductions tokens) + frontier StringSet.empty + +let conflict_states automaton = + Array.mapi + (fun _ state -> + Hashtbl.fold + (fun token reductions conflict -> + conflict + || List.length reductions > 1 + || Hashtbl.mem state.transitions token) + state.reductions false) + automaton.states + +(* Build an optimistic state graph. Terminal shifts cost one token; + nonterminal transitions and reductions cost zero. Reverse shortest paths on + this graph are safe lower bounds, even though stack context is ignored. *) +let reverse_distances automaton targets = + let count = Array.length automaton.states in + let reverse = Array.make count [] in + let add_edge source target cost = + reverse.(target) <- (source, cost) :: reverse.(target) + in + Array.iteri + (fun source state -> + Hashtbl.iter + (fun symbol target -> + let cost = if StringSet.mem symbol automaton.terminals then 1 else 0 in + add_edge source target cost) + state.transitions) + automaton.states; + let gotos = Hashtbl.create 128 in + Array.iter + (fun state -> + Hashtbl.iter + (fun symbol target -> + if not (StringSet.mem symbol automaton.terminals) then + let previous = + Option.value (Hashtbl.find_opt gotos symbol) ~default:[] + in + Hashtbl.replace gotos symbol (target :: previous)) + state.transitions) + automaton.states; + Array.iteri + (fun source state -> + Hashtbl.iter + (fun _ reductions -> + List.iter + (fun reduction -> + List.iter (fun target -> add_edge source target 0) + (Option.value (Hashtbl.find_opt gotos reduction.lhs) ~default:[])) + reductions) + state.reductions) + automaton.states; + let infinity = max_int / 4 in + let distance = Array.make count infinity in + let deque = Queue.create () in + Array.iteri + (fun state is_target -> + if is_target then begin + distance.(state) <- 0; + Queue.add state deque + end) + targets; + (* Repeated relaxation is sufficient here; zero/one weights and 590 states + keep this construction negligible compared with the search. *) + while not (Queue.is_empty deque) do + let target = Queue.take deque in + List.iter + (fun (source, cost) -> + let candidate = distance.(target) + cost in + if candidate < distance.(source) then begin + distance.(source) <- candidate; + Queue.add source deque + end) + reverse.(target) + done; + distance + +let frontier_lower_bound engine distances frontier = + IntMap.fold + (fun stack_id _ best -> + let stack = Stack_pool.find engine.stacks stack_id in + min best distances.(stack.state)) + frontier (max_int / 4) + +(* ----- Conservative unambiguity prover ----- + + Abstract every GLR stack to its top-K states; a suffix shorter than K means + the states below are unknown, which over-approximates every continuation, + including the true stack bottom. Reductions that pop into the unknown part + re-enter through every goto edge on the reduced nonterminal. The abstract + configuration space is finite, so a pair search over runs that consume the + same input terminates. Every concrete ambiguous sentence projects onto an + abstract pair of runs that diverge in their actions and both accept, so if + no such abstract pair exists, the grammar is unambiguous. The converse does + not hold: an abstract diverging pair may be spurious, which is why a found + candidate only downgrades the verdict to "not proven". *) + +let rec drop_states count list = + if count = 0 then list + else match list with [] -> [] | _ :: tail -> drop_states (count - 1) tail + +let truncate_suffix limit list = + let rec take count = function + | [] -> [] + | _ when count = 0 -> [] + | head :: tail -> head :: take (count - 1) tail + in + take limit list + +let goto_edges automaton = + let table = Hashtbl.create 256 in + Array.iteri + (fun source state -> + Hashtbl.iter + (fun symbol target -> + if not (StringSet.mem symbol automaton.terminals) then + Hashtbl.replace table symbol + ((source, target) + :: Option.value (Hashtbl.find_opt table symbol) ~default:[])) + state.transitions) + automaton.states; + table + +(* One micro-step of a single run while consuming a token: apply one + reduction, or terminate the chain by shifting the token (accepting, when + the token is "#"). *) +type side_move = + | Reduce of int * int list (* production id, suffix afterwards *) + | Terminate of int list (* suffix after the shift, or at acceptance *) + +let side_moves automaton gotos limit cache suffix token = + match Hashtbl.find_opt cache (suffix, token) with + | Some moves -> moves + | None -> + let moves = ref [] in + (match suffix with + | [] -> () + | top :: _ -> + let state = automaton.states.(top) in + if token = "#" then begin + if StringSet.mem "#" state.accepts then + moves := Terminate suffix :: !moves + end + else + Option.iter + (fun target -> + moves := + Terminate (truncate_suffix limit (target :: suffix)) :: !moves) + (Hashtbl.find_opt state.transitions token); + List.iter + (fun reduction -> + if reduction.width < List.length suffix then + match drop_states reduction.width suffix with + | [] -> assert false + | base :: _ as remaining -> + Option.iter + (fun target -> + moves := + Reduce + ( reduction.prod, + truncate_suffix limit (target :: remaining) ) + :: !moves) + (Hashtbl.find_opt + automaton.states.(base).transitions reduction.lhs) + else + (* The reduction pops into the unknown part of the stack; the + goto source is the state left on top afterwards. *) + List.iter + (fun (source, target) -> + moves := + Reduce + (reduction.prod, truncate_suffix limit [ target; source ]) + :: !moves) + (Option.value + (Hashtbl.find_opt gotos reduction.lhs) + ~default:[])) + (reductions state token)); + Hashtbl.add cache (suffix, token) !moves; + !moves + +type chain_status = Running of int list | Finished of int list + +(* All (left result, right result, diverged) ways for both runs to consume + [token]. The two reduction chains advance in lockstep: aligned identical + productions carry no divergence, so a reduction cycle both runs share + cancels out instead of poisoning the verdict, while any position where the + chains first differ - two different productions, or one run reducing while + the other shifts - is exactly where two distinct parses of one sentence + must part ways, and marks the pair diverged. Goto and shift-target + differences alone are abstraction artifacts, never a first divergence, so + they are deliberately not compared. *) +let joint_outcomes moves (start_left, start_right) token = + let seen = Hashtbl.create 64 in + let results = Hashtbl.create 16 in + let queue = Queue.create () in + let push node = + if not (Hashtbl.mem seen node) then begin + Hashtbl.add seen node (); + Queue.add node queue + end + in + push (Running start_left, Running start_right, false); + while not (Queue.is_empty queue) do + let (left, right, diverged) = Queue.take queue in + match (left, right) with + | Finished result_left, Finished result_right -> + Hashtbl.replace results (result_left, result_right, diverged) () + | Running suffix_left, Running suffix_right -> + let paired move_left move_right = + match (move_left, move_right) with + | Reduce (p, l), Reduce (q, r) -> + Some (Running l, Running r, diverged || p <> q) + | Reduce (_, l), Terminate r -> Some (Running l, Finished r, true) + | Terminate l, Reduce (_, r) -> Some (Finished l, Running r, true) + | Terminate l, Terminate r -> Some (Finished l, Finished r, diverged) + in + if (not diverged) && suffix_left = suffix_right then + (* The two runs are still the same run: same stack, so an + unknown-base goto resolves identically on both sides. Identical + moves pair diagonally; distinct moves pair only where two real + parses can first part ways - different productions, or reducing + against shifting. Same-production pairs with different gotos are + different possible worlds, never two parses of one sentence. *) + let all = moves suffix_left token in + List.iter + (fun move_left -> + List.iter + (fun move_right -> + let compatible = + match (move_left, move_right) with + | Reduce (p, _), Reduce (q, _) -> p <> q + | Reduce _, Terminate _ | Terminate _, Reduce _ -> true + | Terminate _, Terminate _ -> false + in + if move_left == move_right || compatible then + Option.iter push (paired move_left move_right)) + all) + all + else + let moves_left = moves suffix_left token in + let moves_right = moves suffix_right token in + List.iter + (fun move_left -> + List.iter + (fun move_right -> + Option.iter push (paired move_left move_right)) + moves_right) + moves_left + | Running suffix_left, Finished _ -> + List.iter + (fun move -> + match move with + | Reduce (_, l) -> push (Running l, right, diverged) + | Terminate l -> push (Finished l, right, diverged)) + (moves suffix_left token) + | Finished _, Running suffix_right -> + List.iter + (fun move -> + match move with + | Reduce (_, r) -> push (left, Running r, diverged) + | Terminate r -> push (left, Finished r, diverged)) + (moves suffix_right token) + done; + Hashtbl.fold (fun key () list -> key :: list) results [] + +type prove_result = + | Proven of int + | Abstract_candidate of string list * int + | Pair_overflow of int + +let prove engine limit pair_limit = + let automaton = engine.automaton in + let gotos = goto_edges automaton in + let moves_cache = Hashtbl.create 100_003 in + let moves = side_moves automaton gotos limit moves_cache in + let joint_cache = Hashtbl.create 100_003 in + let joint pair token = + match Hashtbl.find_opt joint_cache (pair, token) with + | Some outcomes -> outcomes + | None -> + let outcomes = joint_outcomes moves pair token in + Hashtbl.add joint_cache (pair, token) outcomes; + outcomes + in + let parents : + ( int list * int list * bool, + (string * (int list * int list * bool)) option ) + Hashtbl.t = + Hashtbl.create 100_003 + in + let queue = Queue.create () in + let overflow = ref false in + let candidate = ref None in + let canonical (left, right, diverged) = + if compare left right <= 0 then (left, right, diverged) + else (right, left, diverged) + in + let push origin node = + let node = canonical node in + if not (Hashtbl.mem parents node) then + if Hashtbl.length parents >= pair_limit then overflow := true + else begin + Hashtbl.add parents node origin; + Queue.add node queue + end + in + let rec trail node = + match Hashtbl.find parents node with + | None -> [] + | Some (token, parent) -> token :: trail parent + in + let terminals = StringSet.elements automaton.terminals in + push None ([ 0 ], [ 0 ], false); + while (not (Queue.is_empty queue)) && !candidate = None && not !overflow do + let (left, right, diverged) as node = Queue.take queue in + List.iter + (fun (_, _, chain_diverged) -> + if (diverged || chain_diverged) && !candidate = None then + candidate := Some (List.rev (trail node))) + (joint (left, right) "#"); + if !candidate = None then + List.iter + (fun token -> + List.iter + (fun (next_left, next_right, chain_diverged) -> + push + (Some (token, node)) + (next_left, next_right, diverged || chain_diverged)) + (joint (left, right) token)) + terminals + done; + let explored = Hashtbl.length parents in + match !candidate with + | Some tokens -> Abstract_candidate (tokens, explored) + | None -> if !overflow then Pair_overflow explored else Proven explored + +type outcome = { + witnesses : ((int * string) list * string list) list; + explored : int; + unique : int; + deepest : int; + stopped : string option; +} + +let () = Random.self_init () + +let rec temporary_directory () = + let path = + Filename.concat (Filename.get_temp_dir_name ()) + (Printf.sprintf "zane-ambiguity-%d-%08x" (Unix.getpid ()) (Random.bits ())) + in + try + Unix.mkdir path 0o700; + path + with Unix.Unix_error (Unix.EEXIST, _, _) -> temporary_directory () + +let rec remove_tree path = + if Sys.is_directory path then begin + Array.iter (fun name -> remove_tree (Filename.concat path name)) + (Sys.readdir path); + Unix.rmdir path + end + else Sys.remove path + +let render automaton tokens = + tokens + |> List.filter (fun token -> token <> "EOF") + |> List.map (fun token -> + Option.value (Hashtbl.find_opt automaton.aliases token) + ~default:("<" ^ token ^ ">")) + |> String.concat " " + +let conflict_profile engine tokens = + let frontier = ref (IntMap.singleton engine.stacks.root.id 1) in + let conflicts = ref ConflictSet.empty in + let inspect token = + let reduced = closure engine !frontier token in + IntMap.iter + (fun stack_id _ -> + let stack = Stack_pool.find engine.stacks stack_id in + let state = engine.automaton.states.(stack.state) in + let reductions = reductions state token in + if + List.length reductions > 1 + || (reductions <> [] && Hashtbl.mem state.transitions token) + then conflicts := ConflictSet.add (stack.state, token) !conflicts) + reduced + in + List.iter + (fun token -> + inspect token; + frontier := shift engine !frontier token) + tokens; + inspect "#"; + ConflictSet.elements !conflicts + +let compare_witness (_, left) (_, right) = + match compare (List.length left) (List.length right) with + | 0 -> compare left right + | order -> order + +let merge_witnesses limit lists = + let by_profile = Hashtbl.create 128 in + List.iter + (fun (profile, tokens) -> + match Hashtbl.find_opt by_profile profile with + | Some previous when List.length previous <= List.length tokens -> () + | _ -> Hashtbl.replace by_profile profile tokens) + (List.concat lists); + Hashtbl.fold (fun profile tokens result -> (profile, tokens) :: result) + by_profile [] + |> List.sort compare_witness + |> List.to_seq |> Seq.take limit |> List.of_seq + +type directed_item = { + tokens_rev : string list; + depth : int; + frontier : frontier; + branched : bool; +} + +let unified_search engine initial ~max_tokens ~timeout ~max_frontiers + ~max_witnesses conflict_distance accept_distance = + let deadline = Unix.gettimeofday () +. timeout in + let buckets = Array.init (max_tokens + 1) (fun _ -> Queue.create ()) in + let seen_plain = Hashtbl.create 16_384 in + let seen_branched = Hashtbl.create 16_384 in + let unique_count () = + Hashtbl.length seen_plain + Hashtbl.length seen_branched + in + let add item = + if item.depth <= max_tokens then + if derivations item.frontier >= 2 && accepted_count engine item.frontier >= 2 + then Queue.add item buckets.(item.depth) + else + let seen = if item.branched then seen_branched else seen_plain in + let key = signature item.frontier in + match Hashtbl.find_opt seen key with + | Some depth when depth <= item.depth -> () + | _ when unique_count () < max_frontiers -> + Hashtbl.replace seen key item.depth; + Queue.add item buckets.(item.depth) + | _ -> () + in + List.iter add initial; + let explored = ref 0 in + let deepest = ref 0 in + let conflict_seeds = ref 0 in + let witnesses = Hashtbl.create max_witnesses in + let stopped = ref None in + let depth = ref 0 in + while + Hashtbl.length witnesses < max_witnesses + && !depth <= max_tokens + && !explored < max_frontiers + && unique_count () < max_frontiers + && Unix.gettimeofday () < deadline + do + if Queue.is_empty buckets.(!depth) then incr depth + else begin + let item = Queue.take buckets.(!depth) in + incr explored; + deepest := max !deepest item.depth; + if accepted_count engine item.frontier >= 2 then begin + let tokens = List.rev item.tokens_rev in + let profile = conflict_profile engine tokens in + if not (Hashtbl.mem witnesses profile) then + Hashtbl.add witnesses profile tokens + end + else if item.depth < max_tokens then + StringSet.iter + (fun token -> + let next = shift engine item.frontier token in + if not (IntMap.is_empty next) then begin + let branched = item.branched || derivations next >= 2 in + if branched && not item.branched then incr conflict_seeds; + let distance = + if branched then accept_distance else conflict_distance + in + let next_depth = item.depth + 1 in + let lower = frontier_lower_bound engine distance next in + if next_depth + lower <= max_tokens then + add + { + tokens_rev = token :: item.tokens_rev; + depth = next_depth; + frontier = next; + branched; + } + end) + (possible_tokens engine item.frontier) + end + done; + if !explored >= max_frontiers || unique_count () >= max_frontiers then + stopped := Some "the frontier limit was reached" + else if Unix.gettimeofday () >= deadline then + stopped := Some "the timeout was reached" + else if Hashtbl.length witnesses >= max_witnesses then + stopped := Some "the witness limit was reached"; + ( { + witnesses = + Hashtbl.fold + (fun profile tokens result -> (profile, tokens) :: result) + witnesses []; + explored = !explored; + unique = unique_count (); + deepest = !deepest; + stopped = !stopped; + }, + !conflict_seeds ) + +let initial_partitions engine jobs max_tokens = + let root = IntMap.singleton engine.stacks.root.id 1 in + if jobs <= 1 || max_tokens = 0 then + ( [| [ { tokens_rev = []; depth = 0; frontier = root; branched = false } ] |], + 0, + 0, + 0 ) + else begin + let split_depth = min 3 max_tokens in + let current = ref [ { tokens_rev = []; depth = 0; frontier = root; branched = false } ] in + let explored = ref 0 in + let unique = ref 1 in + let conflict_seeds = ref 0 in + for _ = 1 to split_depth do + explored := !explored + List.length !current; + let seen = Hashtbl.create 1024 in + let next = ref [] in + List.iter + (fun item -> + if accepted_count engine item.frontier >= 2 then + next := item :: !next + else + StringSet.iter + (fun token -> + let frontier = shift engine item.frontier token in + if not (IntMap.is_empty frontier) then begin + let branched = item.branched || derivations frontier >= 2 in + if branched && not item.branched then incr conflict_seeds; + let item = + { + tokens_rev = token :: item.tokens_rev; + depth = item.depth + 1; + frontier; + branched; + } + in + let key = (branched, signature frontier) in + if not (Hashtbl.mem seen key) then begin + Hashtbl.add seen key (); + next := item :: !next + end + end) + (possible_tokens engine item.frontier)) + !current; + unique := !unique + Hashtbl.length seen; + current := !next + done; + let buckets = Array.make jobs [] in + List.iter + (fun item -> + let hash = Hashtbl.hash (item.branched, signature item.frontier) land max_int in + let bucket = hash mod jobs in + buckets.(bucket) <- item :: buckets.(bucket)) + !current; + (buckets, !explored, !unique, !conflict_seeds) + end + +let parallel_unified_search engine ~jobs ~max_tokens ~timeout ~max_frontiers + ~max_witnesses conflict_distance accept_distance temporary = + let partitions, prefix_explored, prefix_unique, prefix_seeds = + initial_partitions engine (max 1 jobs) max_tokens + in + if Array.length partitions = 1 then + let outcome, seeds = + unified_search engine partitions.(0) ~max_tokens ~timeout ~max_frontiers + ~max_witnesses conflict_distance accept_distance + in + ( { + outcome with + explored = prefix_explored + outcome.explored; + unique = prefix_unique + outcome.unique; + }, + prefix_seeds + seeds ) + else begin + let children = ref [] in + Array.iteri + (fun index initial -> + let output = Filename.concat temporary (Printf.sprintf "worker-%d" index) in + match Unix.fork () with + | 0 -> + let result = + unified_search engine initial ~max_tokens ~timeout ~max_frontiers + ~max_witnesses conflict_distance accept_distance + in + let channel = open_out_bin output in + Marshal.to_channel channel result []; + close_out channel; + exit 0 + | pid -> children := (pid, output) :: !children) + partitions; + let outcomes = + List.map + (fun (pid, output) -> + let rec wait () = + try Unix.waitpid [] pid + with Unix.Unix_error (Unix.EINTR, _, _) -> wait () + in + match wait () with + | _, Unix.WEXITED 0 -> + let channel = open_in_bin output in + Fun.protect ~finally:(fun () -> close_in channel) (fun () -> + (Marshal.from_channel channel : outcome * int)) + | _, Unix.WEXITED code -> + failwith (Printf.sprintf "ambiguity-search worker %d exited with status %d" pid code) + | _, Unix.WSIGNALED signal -> + failwith (Printf.sprintf "ambiguity-search worker %d was killed by signal %d" pid signal) + | _, Unix.WSTOPPED signal -> + failwith (Printf.sprintf "ambiguity-search worker %d stopped on signal %d" pid signal)) + !children + in + let outcome, seeds = List.fold_left + (fun (combined, seeds) (outcome, worker_seeds) -> + ( { + witnesses = outcome.witnesses @ combined.witnesses; + explored = combined.explored + outcome.explored; + unique = combined.unique + outcome.unique; + deepest = max combined.deepest outcome.deepest; + stopped = + (match (combined.stopped, outcome.stopped) with + | None, None -> None + | _ -> Some "one or more workers reached a search limit"); + }, + seeds + worker_seeds )) + ( { witnesses = []; explored = 0; unique = 0; deepest = 0; stopped = None }, + 0 ) + outcomes + in + ( { + outcome with + witnesses = merge_witnesses max_witnesses [ outcome.witnesses ]; + explored = prefix_explored + outcome.explored; + unique = prefix_unique + outcome.unique; + }, + prefix_seeds + seeds ) + end + +let grammar = ref "" +let menhir = ref "menhir" +let max_tokens = ref 20 +let max_frontiers = ref 500_000 +let timeout = ref 60. +let jobs = ref 1 +let max_witnesses = ref 20 +let check_tokens = ref [] +let prove_level = ref 0 + +let options = + [ + ("--menhir", Arg.Set_string menhir, "PATH Menhir executable"); + ("--max-tokens", Arg.Set_int max_tokens, "N maximum tokens, including EOF"); + ("--max-frontiers", Arg.Set_int max_frontiers, "N search-state limit per worker"); + ("--timeout", Arg.Set_float timeout, "SECONDS time limit per search phase"); + ("--jobs", Arg.Set_int jobs, "N worker processes"); + ("--max-witnesses", Arg.Set_int max_witnesses, "N ambiguity families to report"); + ( "--check-tokens", + Arg.String (fun value -> check_tokens := words value), + "TOKENS check one space-separated token sequence" ); + ( "--prove", + Arg.Set_int prove_level, + "K attempt an unambiguity proof with a top-K stack abstraction; \ + exit 0 proven unambiguous, 1 ambiguous, 3 not proven \ + (--max-frontiers also bounds the abstract pair count)" ); + ] + +let main () = + Arg.parse options (fun value -> grammar := value) + "ambiguity_search [options] GRAMMAR"; + if !grammar = "" then begin + Arg.usage options "ambiguity_search [options] GRAMMAR"; + exit 2 + end; + if !max_tokens < 0 then invalid_arg "--max-tokens must be at least 0"; + if !max_frontiers < 1 then invalid_arg "--max-frontiers must be at least 1"; + if !timeout < 0. then invalid_arg "--timeout must be non-negative"; + if !jobs < 1 then invalid_arg "--jobs must be at least 1"; + if !max_witnesses < 1 then invalid_arg "--max-witnesses must be at least 1"; + let grammar_path = Unix.realpath !grammar in + let temporary = temporary_directory () in + Fun.protect + ~finally:(fun () -> remove_tree temporary) + (fun () -> + let terminals, aliases = parse_tokens grammar_path in + let automaton_path = + prepare_automaton ~menhir:!menhir ~grammar:grammar_path + ~directory:temporary + in + let automaton = parse_automaton automaton_path terminals aliases in + let stacks = Stack_pool.create () in + let engine = + { automaton; stacks; closure_cache = Hashtbl.create 16_384 } + in + if !check_tokens <> [] then begin + let frontier = + List.fold_left (shift engine) + (IntMap.singleton engine.stacks.root.id 1) + !check_tokens + in + let count = accepted_count engine frontier in + Printf.printf "Accepting derivations: %d\n" count; + exit (if count >= 2 then 1 else 0) + end; + if !prove_level > 0 then begin + match prove engine !prove_level !max_frontiers with + | Proven pairs -> + Printf.printf + "PROVEN UNAMBIGUOUS: no diverging pair of accepting parses \ + exists in the top-%d stack abstraction (%d abstract pairs \ + explored).\n" + !prove_level pairs; + exit 0 + | Pair_overflow pairs -> + Printf.printf + "NOT PROVEN: the abstract pair limit (%d) was reached at \ + abstraction level %d. Raise --max-frontiers or lower --prove.\n" + pairs !prove_level; + exit 3 + | Abstract_candidate (tokens, pairs) -> + Printf.printf + "Abstract ambiguity candidate at level %d after %d pairs \ + (possibly spurious): %s\n" + !prove_level pairs + (String.concat " " tokens); + Printf.printf + "Attempting to concretize with the bounded search...\n\n" + end; + let conflicts = conflict_states automaton in + let conflict_distance = reverse_distances automaton conflicts in + let accept_targets = + Array.map + (fun state -> StringSet.mem "#" state.accepts) + automaton.states + in + let accept_distance = reverse_distances automaton accept_targets in + let outcome, conflict_seeds = + parallel_unified_search engine ~jobs:!jobs ~max_tokens:!max_tokens + ~timeout:!timeout ~max_frontiers:!max_frontiers + ~max_witnesses:!max_witnesses conflict_distance accept_distance + temporary + in + match outcome.witnesses with + | [] -> + (match outcome.stopped with + | None -> + Printf.printf + "No complete ambiguity found through %d tokens after exploring %d frontiers (%d unique).\n" + !max_tokens outcome.explored outcome.unique + | Some reason -> + Printf.printf + "Search stopped at depth %d because %s; no complete ambiguity was found in %d explored frontiers (%d unique).\n" + outcome.deepest reason outcome.explored outcome.unique); + if !prove_level > 0 then begin + Printf.printf + "NOT PROVEN: the abstract candidate could not be concretized \ + within the search bounds; the grammar is neither proven \ + unambiguous nor shown ambiguous. Raising --prove may remove \ + the spurious candidate.\n"; + exit 3 + end; + Printf.printf "This is a bounded result, not a proof of unambiguity.\n"; + exit 0 + | witnesses -> + Printf.printf "Found %d complete ambiguity %s.\n" + (List.length witnesses) + (if List.length witnesses = 1 then "family" else "families"); + List.iteri + (fun index (profile, witness) -> + Printf.printf "\n%d. Tokens (%d): %s\n Source: %s\n" + (index + 1) (List.length witness) (String.concat " " witness) + (render automaton witness); + Printf.printf " Conflict origins: %s\n" + (profile + |> List.map (fun (state, token) -> + Printf.sprintf "state %d on %s" state token) + |> String.concat ", ")) + witnesses; + Printf.printf "\n"; + Printf.printf "Explored %d frontiers (%d unique); %d conflict seeds.\n" + outcome.explored outcome.unique conflict_seeds; + Option.iter + (fun reason -> + Printf.printf "Search stopped because %s.\n" reason) + outcome.stopped; + exit 1) + +let () = + try main () + with + | Failure message | Invalid_argument message | Sys_error message + | Unix.Unix_error (_, _, message) -> + prerr_endline ("error: " ^ message); + exit 2 diff --git a/tools/dune b/tools/dune new file mode 100644 index 00000000..de423c2b --- /dev/null +++ b/tools/dune @@ -0,0 +1,3 @@ +(executable + (name ambiguity_search) + (libraries unix str)) diff --git a/tools/find_ambiguity.py b/tools/find_ambiguity.py new file mode 100644 index 00000000..0693e8fc --- /dev/null +++ b/tools/find_ambiguity.py @@ -0,0 +1,374 @@ +#!/usr/bin/env python3 +"""Find short, complete ambiguities in a Menhir grammar. + +The search is bounded by token count. It asks Menhir for a fully expanded +grammar and LR(1) automaton, then explores that automaton as a GLR parser would: +all shift and reduce actions are retained. Equivalent LR stacks are merged, +but their number of derivations is retained (and capped at two, because that is +enough to prove ambiguity). + +This is a bounded search, not a proof of unambiguity. If it finishes without a +witness, it proves only that no witness was found within the requested bounds. +""" + +from __future__ import annotations + +import argparse +import ast +from collections import defaultdict, deque +from dataclasses import dataclass, field +from pathlib import Path +import re +import shutil +import subprocess +import sys +import tempfile +import time +from typing import Mapping + + +Stack = tuple[int, ...] +Frontier = dict[Stack, int] +FrontierKey = frozenset[tuple[Stack, int]] + + +@dataclass +class State: + transitions: dict[str, int] = field(default_factory=dict) + reductions: dict[str, list[tuple[str, int]]] = field( + default_factory=lambda: defaultdict(list) + ) + accepts: set[str] = field(default_factory=set) + + +@dataclass +class Automaton: + states: dict[int, State] + terminals: tuple[str, ...] + + +STATE_RE = re.compile(r"^State (\d+):$") +TRANSITION_RE = re.compile(r"^-- On (\S+) shift to state (\d+)$") +LOOKAHEAD_RE = re.compile(r"^-- On (.+)$") +REDUCTION_RE = re.compile(r"^-- reduce production (.+?) ->(?: (.*))?$") +ACCEPT_RE = re.compile(r"^-- accept (\S+)$") +TOKEN_DECL_RE = re.compile(r"^\s*%token(?:\s*<[^>]+>)?\s+(.*)$") +TOKEN_AND_ALIAS_RE = re.compile( + r'\b([A-Z][A-Z0-9_]*)(?:\s*("(?:[^"\\]|\\.)*"))?' +) + + +def cap_add(left: int, right: int) -> int: + return min(2, left + right) + + +def key(frontier: Mapping[Stack, int]) -> FrontierKey: + return frozenset(frontier.items()) + + +def strip_comments(source: str) -> str: + """Strip nested OCaml and non-nested C comments, preserving line breaks.""" + result: list[str] = [] + index = 0 + while index < len(source): + if source.startswith("(*", index): + depth = 1 + index += 2 + while index < len(source) and depth: + if source.startswith("(*", index): + depth += 1 + index += 2 + elif source.startswith("*)", index): + depth -= 1 + index += 2 + else: + if source[index] == "\n": + result.append("\n") + index += 1 + elif source.startswith("/*", index): + index += 2 + while index < len(source): + if source.startswith("*/", index): + index += 2 + break + if source[index] == "\n": + result.append("\n") + index += 1 + else: + result.append(source[index]) + index += 1 + return "".join(result) + + +def parse_aliases(grammar: Path) -> tuple[set[str], dict[str, str]]: + terminals: set[str] = set() + aliases: dict[str, str] = {} + source = strip_comments(grammar.read_text(encoding="utf-8")) + for line in source.splitlines(): + match = TOKEN_DECL_RE.match(line) + if not match: + continue + for token, quoted_alias in TOKEN_AND_ALIAS_RE.findall(match.group(1)): + terminals.add(token) + if quoted_alias: + try: + aliases[token] = ast.literal_eval(quoted_alias) + except (SyntaxError, ValueError): + aliases[token] = quoted_alias[1:-1] + return terminals, aliases + + +def run_menhir(menhir: str, grammar: Path, directory: Path) -> Path: + expanded = directory / "expanded.mly" + preprocess = subprocess.run( + [menhir, "--only-preprocess-uu", str(grammar)], + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + if preprocess.returncode != 0: + sys.stderr.write(preprocess.stderr) + raise RuntimeError("Menhir failed to preprocess the grammar") + expanded.write_text(preprocess.stdout, encoding="utf-8") + + base = directory / "automaton" + build = subprocess.run( + [menhir, "--dump", "--base", str(base), str(expanded)], + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + automaton = base.with_suffix(".automaton") + if not automaton.exists(): + sys.stderr.write(build.stderr) + raise RuntimeError("Menhir did not produce an LR automaton") + # Some Menhir versions exit unsuccessfully after emitting the complete + # automaton when unresolved reduce/reduce conflicts exist. That automaton + # is exactly what this tool needs, so the exit status is intentionally not + # treated as fatal here. + return automaton + + +def parse_automaton(path: Path, terminals: set[str]) -> Automaton: + states: dict[int, State] = {} + current: State | None = None + lookaheads: tuple[str, ...] = () + + for line in path.read_text(encoding="utf-8").splitlines(): + if match := STATE_RE.match(line): + current = states.setdefault(int(match.group(1)), State()) + lookaheads = () + continue + if current is None: + continue + if match := TRANSITION_RE.match(line): + symbol, target = match.groups() + current.transitions[symbol] = int(target) + lookaheads = () + continue + if match := LOOKAHEAD_RE.match(line): + lookaheads = tuple(match.group(1).split()) + continue + if match := REDUCTION_RE.match(line): + lhs, rhs = match.groups() + rhs_length = 0 if not rhs else len(rhs.split()) + for token in lookaheads: + current.reductions[token].append((lhs, rhs_length)) + continue + if ACCEPT_RE.match(line): + current.accepts.update(lookaheads) + + if 0 not in states: + raise RuntimeError("could not find initial state 0 in Menhir automaton") + return Automaton(states, tuple(sorted(terminals))) + + +def add_count(frontier: Frontier, stack: Stack, count: int) -> int: + old = frontier.get(stack, 0) + new = cap_add(old, count) + frontier[stack] = new + return new - old + + +def reduction_closure( + automaton: Automaton, frontier: Mapping[Stack, int], lookahead: str +) -> Frontier: + """Apply zero or more reductions while preserving derivation counts.""" + closure: Frontier = dict(frontier) + propagated: Frontier = {} + queue: deque[Stack] = deque(closure) + + while queue: + stack = queue.popleft() + available = closure[stack] - propagated.get(stack, 0) + if available <= 0: + continue + propagated[stack] = closure[stack] + state = automaton.states[stack[-1]] + + for lhs, rhs_length in state.reductions.get(lookahead, ()): + if rhs_length >= len(stack): + continue + base = stack if rhs_length == 0 else stack[:-rhs_length] + goto = automaton.states[base[-1]].transitions.get(lhs) + if goto is None: + continue + reduced = base + (goto,) + if add_count(closure, reduced, available): + queue.append(reduced) + return closure + + +def shift( + automaton: Automaton, frontier: Mapping[Stack, int], token: str +) -> Frontier: + shifted: Frontier = {} + for stack, count in reduction_closure(automaton, frontier, token).items(): + target = automaton.states[stack[-1]].transitions.get(token) + if target is not None: + add_count(shifted, stack + (target,), count) + return shifted + + +def accepted_count(automaton: Automaton, frontier: Mapping[Stack, int]) -> int: + total = 0 + for stack, count in reduction_closure(automaton, frontier, "#").items(): + if "#" in automaton.states[stack[-1]].accepts: + total = cap_add(total, count) + return total + + +def possible_tokens(automaton: Automaton, frontier: Mapping[Stack, int]) -> set[str]: + """Return exact lookaheads on which at least one stack has an action.""" + tokens: set[str] = set() + terminals = set(automaton.terminals) + for stack in frontier: + state = automaton.states[stack[-1]] + tokens.update(symbol for symbol in state.transitions if symbol in terminals) + tokens.update(state.reductions) + tokens.discard("#") + return tokens + + +def render(tokens: tuple[str, ...], aliases: Mapping[str, str]) -> str: + concrete = [aliases.get(token, f"<{token}>") for token in tokens if token != "EOF"] + return " ".join(concrete) + + +def search( + automaton: Automaton, + max_tokens: int, + max_frontiers: int, + timeout: float, + progress: bool, +) -> tuple[tuple[str, ...] | None, int, int, int, str | None]: + initial: Frontier = {(0,): 1} + queue: deque[tuple[tuple[str, ...], Frontier]] = deque([((), initial)]) + seen: set[FrontierKey] = {key(initial)} + explored = 0 + started = time.monotonic() + current_depth = -1 + deepest = 0 + stopped: str | None = None + + while queue: + tokens, frontier = queue.popleft() + explored += 1 + depth = len(tokens) + deepest = max(deepest, depth) + + if progress and depth != current_depth: + current_depth = depth + print( + f"depth {depth}: explored {explored:,}, queued {len(queue):,}, " + f"unique frontiers {len(seen):,}", + file=sys.stderr, + ) + + if accepted_count(automaton, frontier) >= 2: + return tokens, explored, len(seen), deepest, None + if depth >= max_tokens: + continue + if explored >= max_frontiers: + stopped = f"the {max_frontiers:,}-frontier limit was reached" + break + if timeout and time.monotonic() - started >= timeout: + stopped = f"the {timeout:g}-second timeout was reached" + break + + for token in possible_tokens(automaton, frontier): + next_frontier = shift(automaton, frontier, token) + if not next_frontier: + continue + signature = key(next_frontier) + if signature in seen: + continue + seen.add(signature) + queue.append((tokens + (token,), next_frontier)) + + return None, explored, len(seen), deepest, stopped + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("grammar", type=Path, help="Menhir .mly grammar") + parser.add_argument("--menhir", default="menhir", help="Menhir executable") + parser.add_argument( + "--max-tokens", type=int, default=20, help="maximum tokens, including EOF" + ) + parser.add_argument( + "--max-frontiers", type=int, default=500_000, help="search-state limit" + ) + parser.add_argument( + "--timeout", type=float, default=60.0, help="time limit in seconds; 0 disables" + ) + parser.add_argument("--quiet", action="store_true", help="hide depth progress") + args = parser.parse_args() + + grammar = args.grammar.resolve() + menhir = shutil.which(args.menhir) + if menhir is None: + parser.error(f"Menhir executable not found: {args.menhir!r}") + if not grammar.is_file(): + parser.error(f"grammar does not exist: {grammar}") + + terminals, aliases = parse_aliases(grammar) + try: + with tempfile.TemporaryDirectory(prefix="zane-ambiguity-") as temporary: + automaton_path = run_menhir(menhir, grammar, Path(temporary)) + automaton = parse_automaton(automaton_path, terminals) + witness, explored, unique, deepest, stopped = search( + automaton, + max(0, args.max_tokens), + max(1, args.max_frontiers), + max(0.0, args.timeout), + not args.quiet, + ) + except (OSError, RuntimeError) as error: + print(f"error: {error}", file=sys.stderr) + return 2 + + if witness is None: + if stopped is None: + print( + f"No complete ambiguity found through {args.max_tokens} tokens " + f"after exploring {explored:,} frontiers ({unique:,} unique)." + ) + else: + print( + f"Search stopped at depth {deepest} because {stopped}; no complete " + f"ambiguity was found in {explored:,} explored frontiers " + f"({unique:,} unique)." + ) + print("This is a bounded result, not a proof of unambiguity.") + return 0 + + print("Complete ambiguity found.") + print(f"Tokens ({len(witness)}): {' '.join(witness)}") + print(f"Source: {render(witness, aliases)}") + print(f"Explored {explored:,} frontiers ({unique:,} unique).") + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/syntax_experiments.py b/tools/syntax_experiments.py new file mode 100644 index 00000000..6d334ccb --- /dev/null +++ b/tools/syntax_experiments.py @@ -0,0 +1,1089 @@ +#!/usr/bin/env python3 +"""Compare small, controlled syntax changes with the ambiguity search. + +Each variant is an explicit composition of named grammar transformations. The +harness emits temporary Menhir grammars, replays known ambiguity witnesses, runs +the bounded complete-ambiguity search, and writes JSON and Markdown reports. + +The result is experimental evidence, not a proof that a grammar is unambiguous. +""" + +from __future__ import annotations + +import argparse +from concurrent.futures import ThreadPoolExecutor, as_completed +from dataclasses import asdict, dataclass, replace +import json +import os +from pathlib import Path +import re +import shlex +import subprocess +import sys +import tempfile +import time +from typing import Callable, Iterable + + +Transform = Callable[[str], str] + + +@dataclass(frozen=True) +class Variant: + name: str + description: str + transforms: tuple[str, ...] + edit_cost: int + + +@dataclass(frozen=True) +class Spelling: + """How a variant spells the surface syntax the known cases depend on. + + Call and grouping delimiters are (opening, closing) token-name pairs; a + ``None`` group means the variant removed general grouping. Separators and + terminators are token sequences placed between or after statements and + after top-level declarations. + """ + + group: tuple[tuple[str, ...], tuple[str, ...]] | None + named_call: tuple[tuple[str, ...], tuple[str, ...]] + computed_call: tuple[tuple[str, ...], tuple[str, ...]] + computed_call_statement: bool + stat_separator: tuple[str, ...] + stat_terminator: tuple[str, ...] + decl_terminator: tuple[str, ...] + + +BASELINE_SPELLING = Spelling( + group=(("LPAREN",), ("RPAREN",)), + named_call=(("LPAREN",), ("RPAREN",)), + computed_call=(("LPAREN",), ("RPAREN",)), + computed_call_statement=True, + stat_separator=(), + stat_terminator=(), + decl_terminator=(), +) + + +@dataclass(frozen=True) +class KnownCase: + name: str + description: str + spell: Callable[[Spelling], list[str] | None] + + +@dataclass +class CaseResult: + name: str + derivations: int | None + seconds: float + error: str | None = None + tokens: str | None = None + expressible: bool = True + + +@dataclass +class SearchResult: + families: int | None + explored: int | None + unique: int | None + conflict_seeds: int | None + deepest: int | None + stopped: str | None + sources: list[str] + seconds: float + error: str | None = None + + +@dataclass +class VariantResult: + name: str + description: str + transforms: list[str] + edit_cost: int + known_cases: list[CaseResult] + search: SearchResult + rejected_known: int + ambiguous_known: int + pareto: bool = False + + +def spelled_statements(spelling: Spelling, statements: list[list[str]]) -> list[str]: + result: list[str] = [] + for index, statement in enumerate(statements): + if index and not spelling.stat_terminator: + result.extend(spelling.stat_separator) + result.extend(statement) + result.extend(spelling.stat_terminator) + return result + + +def spelled_constructor_decl(spelling: Spelling, body: list[str]) -> list[str]: + """A `Main() { ... }` constructor declaration; its parens are decl syntax, + untouched by the call transforms, so they always stay LPAREN/RPAREN.""" + return [ + "UIDENT", "LPAREN", "RPAREN", "LCURLY", + *body, + "RCURLY", *spelling.decl_terminator, "EOF", + ] + + +def spell_nullable_array_binding(spelling: Spelling) -> list[str] | None: + return [ + "ALIAS", "UIDENT", "EQUAL", "UIDENT", "QSTNMARK", "UIDENT", + "LBRACKET", "RBRACKET", "LBRACKET", "RBRACKET", + *spelling.decl_terminator, "EOF", + ] + + +def spell_adjacent_computed_call(spelling: Spelling) -> list[str] | None: + if spelling.group is None or not spelling.computed_call_statement: + return None + group_open, group_close = spelling.group + named_open, named_close = spelling.named_call + computed_open, computed_close = spelling.computed_call + named = ["LIDENT", *named_open, *named_close] + computed = [*group_open, "LIDENT", *group_close, *computed_open, *computed_close] + return spelled_constructor_decl( + spelling, spelled_statements(spelling, [named, computed]) + ) + + +def spell_abort_handler_attachment(spelling: Spelling) -> list[str] | None: + named_open, named_close = spelling.named_call + statement = [ + "LIDENT", *named_open, + "TILDE", "TILDE", "LIDENT", "QSTNQSTN", "LIDENT", + *named_close, + ] + return spelled_constructor_decl( + spelling, spelled_statements(spelling, [statement]) + ) + + +def spell_named_call_statement(spelling: Spelling) -> list[str] | None: + named_open, named_close = spelling.named_call + statement = ["LIDENT", *named_open, "STRING", *named_close] + return spelled_constructor_decl( + spelling, spelled_statements(spelling, [statement]) + ) + + +KNOWN_CASES = ( + KnownCase( + "nullable-array-binding", + "T ? U[] must bind the array to U, not the nullable result", + spell_nullable_array_binding, + ), + KnownCase( + "adjacent-computed-call", + "f() followed by (x)() must not have both one- and two-statement parses", + spell_adjacent_computed_call, + ), + KnownCase( + "abort-handler-attachment", + "the abort handler must attach to the outer expression", + spell_abort_handler_attachment, + ), + KnownCase( + "named-call-statement", + 'an ordinary named call statement such as print("hello") must keep exactly one parse', + spell_named_call_statement, + ), +) + + +PRIMARY_GROUP = ' | "(" e=expr ")" { Nodes.Expr.Parenthized e }\n' + +VERB_CALL = '''verb_call: + | receiver=app part=ioption(meth_part) "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) { + match part with + | None -> Nodes.Verb_call.Func { callee = receiver; args; abort_handle } + | Some (is_mut, name) -> + Nodes.Verb_call.Meth { this = receiver; callee = name; args; abort_handle; is_mut } + } + | name_type=name_type "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) { + Nodes.Verb_call.Constructor { name_type; args; abort_handle } + } +''' + +STAT_CALL = ''' | verb_call=verb_call { + Nodes.Stat.VerbCall verb_call + } +''' + + +def replace_once(source: str, old: str, new: str, transform: str) -> str: + count = source.count(old) + if count != 1: + raise ValueError( + f"{transform}: expected one grammar anchor, found {count}: {old[:70]!r}" + ) + return source.replace(old, new, 1) + + +def replace_statement_lists(source: str, helper: str, transform: str) -> str: + source = replace_once( + source, + " | decls=list(decl) EOF", + " | decls=decl_sequence EOF", + transform, + ) + if "list(stat)" not in source: + raise ValueError(f"{transform}: no statement-list anchors found") + source = source.replace("list(stat)", "stat_sequence") + return replace_once(source, "\nbody:\n", f"\n{helper}\nbody:\n", transform) + + +def semicolon_separated(source: str) -> str: + helper = '''decl_sequence: + | values=separated_list(";", decl) ioption(";") { values } + +stat_sequence: + | values=separated_list(";", stat) ioption(";") { values } +''' + return replace_statement_lists(source, helper, "semicolon-separated") + + +def semicolon_terminated(source: str) -> str: + helper = '''decl_sequence: + | values=list(terminated(decl, ";")) { values } + +stat_sequence: + | values=list(terminated(stat, ";")) { values } +''' + return replace_statement_lists(source, helper, "semicolon-terminated") + + +def newline_separated(source: str) -> str: + source = replace_once( + source, + '%token SEMICOLON ";"\n', + '%token SEMICOLON ";"\n%token NEWLINE ""\n', + "newline-separated", + ) + helper = '''decl_sequence: + | { [] } + | NEWLINE { [] } + | boption(NEWLINE) first=decl rest=list(preceded(NEWLINE, decl)) boption(NEWLINE) { + first :: rest + } + +stat_sequence: + | { [] } + | NEWLINE { [] } + | boption(NEWLINE) first=stat rest=list(preceded(NEWLINE, stat)) boption(NEWLINE) { + first :: rest + } +''' + return replace_statement_lists(source, helper, "newline-separated") + + +def named_statement_calls(source: str) -> str: + helper = '''statement_verb_call: + | callee=name_expr "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) { + Nodes.Verb_call.Func { + callee = Nodes.Expr.NameExpr callee; + args; + abort_handle; + } + } + | receiver=app is_mut=meth_marker callee=name_expr + "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) { + Nodes.Verb_call.Meth { + this = receiver; + callee = Nodes.Expr.NameExpr callee; + args; + abort_handle; + is_mut; + } + } + | name_type=name_type "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) { + Nodes.Verb_call.Constructor { name_type; args; abort_handle } + } + +''' + source = replace_once(source, "\nstat:\n", f"\n{helper}stat:\n", "named-statement-calls") + return replace_once( + source, + STAT_CALL, + ''' | verb_call=statement_verb_call { + Nodes.Stat.VerbCall verb_call + } +''', + "named-statement-calls", + ) + + +def bracket_grouping(source: str) -> str: + return replace_once( + source, + PRIMARY_GROUP, + ' | "[" e=expr "]" { Nodes.Expr.Parenthized e }\n', + "bracket-grouping", + ) + + +def brace_grouping(source: str) -> str: + return replace_once( + source, + PRIMARY_GROUP, + ' | "{" e=expr "}" { Nodes.Expr.Parenthized e }\n', + "brace-grouping", + ) + + +def keyword_grouping(source: str) -> str: + source = replace_once( + source, + '%token LPAREN "("\n', + '%token GROUP "group"\n%token LPAREN "("\n', + "keyword-grouping", + ) + return replace_once( + source, + PRIMARY_GROUP, + ' | GROUP "(" e=expr ")" { Nodes.Expr.Parenthized e }\n', + "keyword-grouping", + ) + + +def no_grouping(source: str) -> str: + return replace_once(source, PRIMARY_GROUP, "", "no-grouping") + + +def transform_all_calls(source: str, kind: str) -> str: + if kind == "bracket": + replacement = VERB_CALL.replace( + '"(" args=separated_list(COMMA, expr) ")"', + '"[" args=separated_list(COMMA, expr) "]"', + ) + elif kind in {"marked", "dotted"}: + marker = '"@"' if kind == "marked" else '"."' + replacement = VERB_CALL.replace( + '"(" args=separated_list(COMMA, expr) ")"', + f'{marker} "(" args=separated_list(COMMA, expr) ")"', + ) + else: + raise AssertionError(kind) + return replace_once(source, VERB_CALL, replacement, f"{kind}-calls") + + +def bracket_calls(source: str) -> str: + return transform_all_calls(source, "bracket") + + +def marked_calls(source: str) -> str: + return transform_all_calls(source, "marked") + + +def dotted_calls(source: str) -> str: + return transform_all_calls(source, "dotted") + + +def computed_calls(source: str, kind: str) -> str: + if kind == "marked": + opening, closing = '"@" "("', '")"' + elif kind == "bracket": + opening, closing = '"["', '"]"' + else: + raise AssertionError(kind) + replacement = f'''verb_call: + | callee=name_expr "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) {{ + Nodes.Verb_call.Func {{ + callee = Nodes.Expr.NameExpr callee; + args; + abort_handle; + }} + }} + | receiver=app {opening} args=separated_list(COMMA, expr) {closing} abort_handle=ioption(abort_handle) {{ + Nodes.Verb_call.Func {{ callee = receiver; args; abort_handle }} + }} + | receiver=app part=meth_part "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) {{ + let (is_mut, name) = part in + Nodes.Verb_call.Meth {{ this = receiver; callee = name; args; abort_handle; is_mut }} + }} + | name_type=name_type "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) {{ + Nodes.Verb_call.Constructor {{ name_type; args; abort_handle }} + }} +''' + return replace_once(source, VERB_CALL, replacement, f"{kind}-computed-calls") + + +OP_HANDLE_SLOTS = ( + ("comparison_op", "EQEQ"), + ("additive_op", "PLUS"), + ("multiplicative_op", "STAR"), +) + +HANDLED_EXPR = '''handled_expr: + | e=expr { e } + | e=expr abort_handle=abort_handle { + Nodes.Expr.WithAbortHandle { value = e; abort_handle } + } + +''' + + +def anchored_abort_handles(source: str) -> str: + """Abort handlers may only attach at delimited boundaries: statement + calls, declaration values, return/resolve/abort values, call arguments, + and grouping parentheses — never inside an undelimited expression.""" + name = "anchored-abort-handles" + for rule, prec in OP_HANDLE_SLOTS: + source = replace_once( + source, + f" | left=expr op={rule} right=expr abort_handle=ioption(abort_handle) %prec {prec} {{\n" + " Nodes.Expr.VerbCall (Nodes.Verb_call.Op { op; left; right; abort_handle })\n" + " }\n", + f" | left=expr op={rule} right=expr %prec {prec} {{\n" + " Nodes.Expr.VerbCall (Nodes.Verb_call.Op { op; left; right; abort_handle = None })\n" + " }\n", + name, + ) + source = replace_once( + source, + ' | "~" value=expr abort_handle=ioption(abort_handle) %prec TILDE {\n' + " Nodes.Expr.VerbCall (Nodes.Verb_call.Flip { value; abort_handle })\n" + " }\n", + ' | "~" value=expr %prec TILDE {\n' + " Nodes.Expr.VerbCall (Nodes.Verb_call.Flip { value; abort_handle = None })\n" + " }\n", + name, + ) + source = replace_once( + source, + VERB_CALL, + '''verb_call: + | receiver=app part=ioption(meth_part) "(" args=separated_list(COMMA, handled_expr) ")" { + match part with + | None -> Nodes.Verb_call.Func { callee = receiver; args; abort_handle = None } + | Some (is_mut, name) -> + Nodes.Verb_call.Meth { this = receiver; callee = name; args; abort_handle = None; is_mut } + } + | name_type=name_type "(" args=separated_list(COMMA, handled_expr) ")" { + Nodes.Verb_call.Constructor { name_type; args; abort_handle = None } + } +''', + name, + ) + source = replace_once( + source, + STAT_CALL, + ''' | verb_call=verb_call abort_handle=ioption(abort_handle) { + Nodes.Stat.VerbCall (Nodes.with_statement_handle verb_call abort_handle) + } +''', + name, + ) + source = replace_once( + source, + ' | name=LIDENT type_=type_expr "=" value=expr {\n', + ' | name=LIDENT type_=type_expr "=" value=handled_expr {\n', + name, + ) + source = replace_once( + source, + ' | name=LIDENT constructor=name_type "(" args=separated_list(COMMA, expr) ")" {\n', + ' | name=LIDENT constructor=name_type "(" args=separated_list(COMMA, handled_expr) ")" {\n', + name, + ) + for keyword in ("ABORT", "RETURN", "RESOLVE"): + source = replace_once( + source, + f" | {keyword} value=expr {{\n", + f" | {keyword} value=handled_expr {{\n", + name, + ) + source = replace_once( + source, + PRIMARY_GROUP, + ' | "(" e=handled_expr ")" { Nodes.Expr.Parenthized e }\n', + name, + ) + return replace_once(source, "\nexpr:\n", f"\n{HANDLED_EXPR}expr:\n", name) + + +def marked_computed_calls(source: str) -> str: + return computed_calls(source, "marked") + + +def bracket_computed_calls(source: str) -> str: + return computed_calls(source, "bracket") + + +TRANSFORMS: dict[str, Transform] = { + "semicolon-separated": semicolon_separated, + "semicolon-terminated": semicolon_terminated, + "newline-separated": newline_separated, + "named-statement-calls": named_statement_calls, + "bracket-grouping": bracket_grouping, + "brace-grouping": brace_grouping, + "keyword-grouping": keyword_grouping, + "no-grouping": no_grouping, + "bracket-calls": bracket_calls, + "marked-calls": marked_calls, + "dotted-calls": dotted_calls, + "marked-computed-calls": marked_computed_calls, + "bracket-computed-calls": bracket_computed_calls, + "anchored-abort-handles": anchored_abort_handles, +} + + +BRACKET_CALL = (("LBRACKET",), ("RBRACKET",)) +MARKED_CALL = (("AT", "LPAREN"), ("RPAREN",)) +DOTTED_CALL = (("DOT", "LPAREN"), ("RPAREN",)) + +SPELLINGS: dict[str, Callable[[Spelling], Spelling]] = { + "semicolon-separated": lambda s: replace(s, stat_separator=("SEMICOLON",)), + "semicolon-terminated": lambda s: replace( + s, stat_terminator=("SEMICOLON",), decl_terminator=("SEMICOLON",) + ), + "newline-separated": lambda s: replace(s, stat_separator=("NEWLINE",)), + "named-statement-calls": lambda s: replace(s, computed_call_statement=False), + "bracket-grouping": lambda s: replace(s, group=(("LBRACKET",), ("RBRACKET",))), + "brace-grouping": lambda s: replace(s, group=(("LCURLY",), ("RCURLY",))), + "keyword-grouping": lambda s: replace(s, group=(("GROUP", "LPAREN"), ("RPAREN",))), + "no-grouping": lambda s: replace(s, group=None), + "bracket-calls": lambda s: replace( + s, named_call=BRACKET_CALL, computed_call=BRACKET_CALL + ), + "marked-calls": lambda s: replace(s, named_call=MARKED_CALL, computed_call=MARKED_CALL), + "dotted-calls": lambda s: replace(s, named_call=DOTTED_CALL, computed_call=DOTTED_CALL), + "marked-computed-calls": lambda s: replace(s, computed_call=MARKED_CALL), + "bracket-computed-calls": lambda s: replace(s, computed_call=BRACKET_CALL), + # The witnesses spell their abort handlers at positions that stay legal + # (call arguments and declaration values), so the spelling is unchanged. + "anchored-abort-handles": lambda s: s, +} + + +def variant_spelling(variant: Variant) -> Spelling: + spelling = BASELINE_SPELLING + for name in variant.transforms: + spelling = SPELLINGS[name](spelling) + return spelling + + +def case_tokens(case: KnownCase, variant: Variant) -> str | None: + tokens = case.spell(variant_spelling(variant)) + return None if tokens is None else " ".join(tokens) + + +VARIANTS = ( + Variant("baseline", "Current Zane syntax", (), 0), + Variant( + "semicolon-separated", + "Require semicolons between adjacent declarations and statements", + ("semicolon-separated",), + 1, + ), + Variant( + "semicolon-terminated", + "Require every declaration and statement to end in a semicolon", + ("semicolon-terminated",), + 1, + ), + Variant( + "named-statement-calls", + "Only direct named functions, named methods, and constructors may be call statements", + ("named-statement-calls",), + 1, + ), + Variant( + "semicolons-and-named-statements", + "Require separators and restrict call statements to statically named calls", + ("semicolon-separated", "named-statement-calls"), + 2, + ), + Variant( + "terminated-and-named-statements", + "Require terminators and restrict call statements to statically named calls", + ("semicolon-terminated", "named-statement-calls"), + 2, + ), + Variant( + "newline-separated", + "Make newlines grammatical statement separators", + ("newline-separated",), + 2, + ), + Variant( + "newline-and-named-statements", + "Use significant newlines and statically named call statements", + ("newline-separated", "named-statement-calls"), + 3, + ), + Variant("bracket-grouping", "Use [expression] for grouping", ("bracket-grouping",), 1), + Variant("brace-grouping", "Use {expression} for grouping", ("brace-grouping",), 1), + Variant( + "keyword-grouping", + "Use group(expression) for explicit grouping", + ("keyword-grouping",), + 1, + ), + Variant("no-grouping", "Remove general expression grouping", ("no-grouping",), 1), + Variant("bracket-calls", "Use receiver[arguments] for every call", ("bracket-calls",), 1), + Variant("marked-calls", "Use receiver@(arguments) for every call", ("marked-calls",), 1), + Variant("dotted-calls", "Use receiver.(arguments) for every call", ("dotted-calls",), 1), + Variant( + "marked-computed-calls", + "Keep f(args), but require value@(args) for computed callees", + ("marked-computed-calls",), + 2, + ), + Variant( + "bracket-computed-calls", + "Keep f(args), but require value[args] for computed callees", + ("bracket-computed-calls",), + 2, + ), + Variant( + "semicolons-and-marked-computed-calls", + "Combine statement separators with marked computed invocation", + ("semicolon-separated", "marked-computed-calls"), + 3, + ), + Variant( + "named-statements-and-marked-computed-calls", + "Mark computed invocation and forbid it as a standalone statement", + ("named-statement-calls", "marked-computed-calls"), + 3, + ), + Variant( + "bracket-grouping-and-semicolons", + "Combine bracket grouping with statement separators", + ("bracket-grouping", "semicolon-separated"), + 2, + ), + Variant( + "bracket-grouping-and-named-statements", + "Combine bracket grouping with named-only call statements", + ("bracket-grouping", "named-statement-calls"), + 2, + ), + Variant( + "bracket-grouping-semicolons-and-named-statements", + "Combine bracket grouping, separators, and named-only call statements", + ("bracket-grouping", "semicolon-separated", "named-statement-calls"), + 3, + ), + Variant( + "keyword-grouping-and-semicolons", + "Combine keyword grouping with statement separators", + ("keyword-grouping", "semicolon-separated"), + 2, + ), + Variant( + "keyword-grouping-and-named-statements", + "Combine keyword grouping with named-only call statements", + ("keyword-grouping", "named-statement-calls"), + 2, + ), + Variant( + "anchored-abort-handles", + "Attach abort handlers only at delimited boundaries, not inside expressions", + ("anchored-abort-handles",), + 2, + ), + Variant( + "anchored-handles-and-semicolons", + "Combine anchored abort handlers with statement separators", + ("anchored-abort-handles", "semicolon-separated"), + 3, + ), +) + + +DERIVATIONS_RE = re.compile(r"Accepting derivations: (\d+)") +FAMILIES_RE = re.compile(r"Found (\d+) complete ambiguity") +EXPLORED_RE = re.compile(r"Explored (\d+) frontiers \((\d+) unique\); (\d+) conflict seeds") +NO_WITNESS_RE = re.compile( + r"(?:after exploring|found in) (\d+) (?:explored )?frontiers \((\d+) unique\)" +) +DEPTH_RE = re.compile(r"Search stopped at depth (\d+)") +STOPPED_RE = re.compile(r"Search stopped (?:because|at depth \d+ because) ([^.;]+)") +SOURCE_RE = re.compile(r"^\s*Source: (.*)$", re.MULTILINE) + + +def apply_variant(source: str, variant: Variant) -> str: + result = source + for name in variant.transforms: + result = TRANSFORMS[name](result) + header = ( + "(* Generated by tools/syntax_experiments.py.\n" + f" Variant: {variant.name}\n" + f" Transformations: {', '.join(variant.transforms) or 'none'} *)\n" + ) + return header + result + + +def run_process(command: list[str]) -> tuple[int, str, str, float]: + started = time.monotonic() + completed = subprocess.run(command, text=True, capture_output=True) + return completed.returncode, completed.stdout, completed.stderr, time.monotonic() - started + + +def base_command(args: argparse.Namespace, grammar: Path) -> list[str]: + return [*shlex.split(args.search_command), str(grammar), "--menhir", args.menhir] + + +def check_case(args: argparse.Namespace, grammar: Path, case: KnownCase, variant: Variant) -> CaseResult: + tokens = case_tokens(case, variant) + if tokens is None: + return CaseResult(case.name, None, 0.0, expressible=False) + command = [*base_command(args, grammar), "--check-tokens", tokens] + code, stdout, stderr, seconds = run_process(command) + match = DERIVATIONS_RE.search(stdout) + if code not in {0, 1} or match is None: + message = (stderr or stdout or f"search exited with status {code}").strip() + return CaseResult(case.name, None, seconds, message, tokens) + return CaseResult(case.name, int(match.group(1)), seconds, tokens=tokens) + + +def search_variant(args: argparse.Namespace, grammar: Path) -> SearchResult: + command = [ + *base_command(args, grammar), + "--max-tokens", + str(args.max_tokens), + "--timeout", + str(args.timeout), + "--max-frontiers", + str(args.max_frontiers), + "--jobs", + str(args.search_jobs), + "--max-witnesses", + str(args.max_witnesses), + ] + code, stdout, stderr, seconds = run_process(command) + if code not in {0, 1}: + message = (stderr or stdout or f"search exited with status {code}").strip() + return SearchResult(None, None, None, None, None, None, [], seconds, message) + + family_match = FAMILIES_RE.search(stdout) + families = int(family_match.group(1)) if family_match else 0 + explored_match = EXPLORED_RE.search(stdout) + no_witness_match = NO_WITNESS_RE.search(stdout) + if explored_match: + explored, unique, seeds = map(int, explored_match.groups()) + elif no_witness_match: + explored, unique = map(int, no_witness_match.groups()) + seeds = None + else: + explored = unique = seeds = None + depth_match = DEPTH_RE.search(stdout) + stopped_match = STOPPED_RE.search(stdout) + return SearchResult( + families, + explored, + unique, + seeds, + int(depth_match.group(1)) if depth_match else None, + stopped_match.group(1) if stopped_match else None, + SOURCE_RE.findall(stdout)[:5], + seconds, + ) + + +def evaluate_variant( + args: argparse.Namespace, source: str, variant: Variant, directory: Path +) -> VariantResult: + grammar = directory / f"{variant.name}.mly" + try: + grammar.write_text(apply_variant(source, variant), encoding="utf-8") + except ValueError as error: + failed = SearchResult(None, None, None, None, None, None, [], 0.0, str(error)) + return VariantResult( + variant.name, + variant.description, + list(variant.transforms), + variant.edit_cost, + [], + failed, + 0, + 0, + ) + + if args.emit_only: + empty = SearchResult(None, None, None, None, None, None, [], 0.0) + return VariantResult( + variant.name, + variant.description, + list(variant.transforms), + variant.edit_cost, + [], + empty, + 0, + 0, + ) + + cases = ( + [] + if args.skip_known + else [check_case(args, grammar, case, variant) for case in KNOWN_CASES] + ) + search = search_variant(args, grammar) + rejected = sum(not case.expressible or case.derivations == 0 for case in cases) + ambiguous = sum( + case.derivations is not None and case.derivations >= 2 for case in cases + ) + return VariantResult( + variant.name, + variant.description, + list(variant.transforms), + variant.edit_cost, + cases, + search, + rejected, + ambiguous, + ) + + +def metric(result: VariantResult) -> tuple[int, int, int, int, int]: + failed = int(result.search.error is not None or any(case.error for case in result.known_cases)) + uncertain_clean = int(result.search.families == 0 and result.search.stopped is not None) + families = result.search.families if result.search.families is not None else 10**9 + return ( + failed, + result.rejected_known, + result.ambiguous_known, + uncertain_clean, + families + result.edit_cost, + ) + + +def mark_pareto(results: list[VariantResult]) -> None: + def objectives(result: VariantResult) -> tuple[int, int, int, int, int, int]: + failed, rejected, ambiguous, uncertain, _ = metric(result) + families = result.search.families if result.search.families is not None else 10**9 + return failed, rejected, ambiguous, uncertain, families, result.edit_cost + + for candidate in results: + values = objectives(candidate) + candidate.pareto = not any( + other is not candidate + and all(left <= right for left, right in zip(objectives(other), values)) + and any(left < right for left, right in zip(objectives(other), values)) + for other in results + ) + + +def render_markdown(args: argparse.Namespace, results: list[VariantResult]) -> str: + lines = [ + "# Zane syntax experiment report", + "", + ( + f"Bounds: {args.max_tokens} tokens, {args.timeout:g}s, " + f"{args.max_frontiers:,} frontiers, {args.max_witnesses} witnesses per variant." + ), + "", + "A Pareto mark means no tested candidate was at least as good on every measured axis. " + "An interrupted zero-witness search is treated as uncertain, not clean.", + "", + "Known witnesses are respelled in each variant's own syntax before checking, so " + "a rejection means the intended program genuinely cannot be parsed, not that an " + "old spelling became illegal. A case a variant cannot express at all counts as " + "rejected and is labeled explicitly.", + "", + "| Pareto | Variant | Edit cost | Rejected known | Ambiguous known | Families | Search stop | Seconds |", + "|---:|---|---:|---:|---:|---:|---|---:|", + ] + for result in sorted(results, key=metric): + search = result.search + families = "error" if search.families is None else str(search.families) + stop = search.error or search.stopped or "bound completed" + stop = stop.replace("|", "\\|").replace("\n", " ")[:100] + lines.append( + f"| {'✓' if result.pareto else ''} | `{result.name}` | {result.edit_cost} | " + f"{result.rejected_known} | {result.ambiguous_known} | {families} | {stop} | " + f"{search.seconds:.2f} |" + ) + + lines.extend(["", "## Candidate details", ""]) + descriptions = {case.name: case.description for case in KNOWN_CASES} + for result in sorted(results, key=metric): + lines.extend( + [ + f"### {result.name}", + "", + result.description, + "", + f"Transforms: `{', '.join(result.transforms) or 'none'}`", + "", + ] + ) + if result.known_cases: + lines.append("Known cases:") + lines.append("") + for case in result.known_cases: + if not case.expressible: + lines.append( + f"- `{case.name}`: not expressible in this variant — " + f"{descriptions[case.name]}" + ) + continue + value = "error" if case.derivations is None else str(case.derivations) + lines.append( + f"- `{case.name}`: {value} accepting derivations — {descriptions[case.name]}" + ) + lines.append("") + if result.search.sources: + lines.append("Shortest reported examples:") + lines.append("") + lines.extend(f"- `{source}`" for source in result.search.sources) + lines.append("") + if result.search.error: + lines.extend(["Error:", "", f"```text\n{result.search.error}\n```", ""]) + return "\n".join(lines) + + +def select_variants(names: list[str] | None) -> list[Variant]: + by_name = {variant.name: variant for variant in VARIANTS} + if not names: + return list(VARIANTS) + unknown = sorted(set(names) - by_name.keys()) + if unknown: + raise ValueError(f"unknown variants: {', '.join(unknown)}") + return [by_name[name] for name in names] + + +def parser() -> argparse.ArgumentParser: + result = argparse.ArgumentParser(description=__doc__) + result.add_argument("grammar", nargs="?", type=Path, default=Path("lib/cst/parser.mly")) + result.add_argument("--variant", action="append", help="variant to run; repeatable") + result.add_argument("--list", action="store_true", help="list variants and exit") + result.add_argument("--emit-only", action="store_true", help="only materialize grammars") + result.add_argument("--emit-dir", type=Path, help="keep generated grammars in this directory") + result.add_argument( + "--search-command", + default="_build/default/tools/ambiguity_search.exe", + help="command prefix used to invoke the ambiguity search; the default" + " expects a prior `dune build tools/ambiguity_search.exe`", + ) + result.add_argument("--menhir", default="menhir", help="Menhir executable") + result.add_argument("--max-tokens", type=int, default=12) + result.add_argument("--timeout", type=float, default=15.0) + result.add_argument("--max-frontiers", type=int, default=150_000) + result.add_argument("--max-witnesses", type=int, default=10) + result.add_argument("--jobs", type=int, default=min(4, os.cpu_count() or 1)) + result.add_argument("--search-jobs", type=int, default=1) + result.add_argument("--skip-known", action="store_true") + result.add_argument( + "--output", + type=Path, + default=Path("_build/syntax-experiments/report"), + help="report path without extension", + ) + return result + + +def validate_args(args: argparse.Namespace, cli: argparse.ArgumentParser) -> None: + if not args.grammar.is_file(): + cli.error(f"grammar does not exist: {args.grammar}") + search_words = shlex.split(args.search_command) + if not search_words: + cli.error("--search-command must not be empty") + executable = search_words[0] + if not args.emit_only and os.path.dirname(executable) and not Path(executable).is_file(): + cli.error( + f"search executable does not exist: {executable};" + " run `dune build tools/ambiguity_search.exe` first" + ) + if args.max_tokens < 0: + cli.error("--max-tokens must be at least 0") + if args.timeout < 0: + cli.error("--timeout must be non-negative") + if args.max_frontiers < 1 or args.max_witnesses < 1: + cli.error("frontier and witness limits must be at least 1") + if args.jobs < 1 or args.search_jobs < 1: + cli.error("worker counts must be at least 1") + + +def main() -> int: + cli = parser() + args = cli.parse_args() + if args.list: + for variant in VARIANTS: + transforms = ", ".join(variant.transforms) or "baseline" + print(f"{variant.name:52} cost={variant.edit_cost} {transforms}") + print(f" {variant.description}") + return 0 + validate_args(args, cli) + try: + variants = select_variants(args.variant) + except ValueError as error: + cli.error(str(error)) + + source = args.grammar.read_text(encoding="utf-8") + temporary: tempfile.TemporaryDirectory[str] | None = None + if args.emit_dir: + directory = args.emit_dir + directory.mkdir(parents=True, exist_ok=True) + else: + temporary = tempfile.TemporaryDirectory(prefix="zane-syntax-") + directory = Path(temporary.name) + + try: + results: list[VariantResult] = [] + with ThreadPoolExecutor(max_workers=args.jobs) as executor: + futures = { + executor.submit(evaluate_variant, args, source, variant, directory): variant + for variant in variants + } + for future in as_completed(futures): + variant = futures[future] + try: + result = future.result() + except Exception as error: # keep other experiments running + search = SearchResult( + None, None, None, None, None, None, [], 0.0, str(error) + ) + result = VariantResult( + variant.name, + variant.description, + list(variant.transforms), + variant.edit_cost, + [], + search, + 0, + 0, + ) + results.append(result) + status = "generated" if args.emit_only else ( + f"{result.search.families} families" + if result.search.error is None + else "error" + ) + print(f"[{len(results):02d}/{len(variants):02d}] {variant.name}: {status}", file=sys.stderr) + + mark_pareto(results) + results.sort(key=metric) + args.output.parent.mkdir(parents=True, exist_ok=True) + payload = { + "bounds": { + "max_tokens": args.max_tokens, + "timeout": args.timeout, + "max_frontiers": args.max_frontiers, + "max_witnesses": args.max_witnesses, + }, + "known_cases": [ + {"name": case.name, "description": case.description} + for case in KNOWN_CASES + ], + "results": [asdict(result) for result in results], + } + json_path = args.output.with_suffix(".json") + markdown_path = args.output.with_suffix(".md") + json_path.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8") + markdown_path.write_text(render_markdown(args, results) + "\n", encoding="utf-8") + print(f"JSON: {json_path}") + print(f"Markdown: {markdown_path}") + return 0 if all(result.search.error is None for result in results) else 2 + finally: + if temporary is not None: + temporary.cleanup() + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/test_syntax_experiments.py b/tools/test_syntax_experiments.py new file mode 100644 index 00000000..165f7e71 --- /dev/null +++ b/tools/test_syntax_experiments.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +import unittest +from pathlib import Path + +from tools import syntax_experiments as experiments + + +class SyntaxExperimentTests(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.source = Path("lib/cst/parser.mly").read_text(encoding="utf-8") + + def test_every_predefined_variant_applies(self) -> None: + names = set() + for variant in experiments.VARIANTS: + self.assertNotIn(variant.name, names) + names.add(variant.name) + grammar = experiments.apply_variant(self.source, variant) + self.assertIn(f"Variant: {variant.name}", grammar) + + def test_semicolon_variants_replace_every_statement_list(self) -> None: + for transform in ( + experiments.semicolon_separated, + experiments.semicolon_terminated, + ): + grammar = transform(self.source) + self.assertNotIn("decls=list(decl)", grammar) + self.assertNotIn("list(stat)", grammar) + self.assertIn("decls=decl_sequence", grammar) + self.assertIn("statements=stat_sequence", grammar) + + def test_named_statement_variant_keeps_computed_calls_in_expressions(self) -> None: + grammar = experiments.named_statement_calls(self.source) + self.assertIn("verb_call:\n | receiver=app", grammar) + self.assertIn("verb_call=statement_verb_call", grammar) + self.assertNotIn(experiments.STAT_CALL, grammar) + + def test_anchored_abort_handles_leave_no_expression_slots(self) -> None: + grammar = experiments.anchored_abort_handles(self.source) + self.assertNotIn("abort_handle=ioption(abort_handle) %prec", grammar) + self.assertIn("handled_expr:", grammar) + self.assertIn( + "| verb_call=verb_call abort_handle=ioption(abort_handle) {", grammar + ) + self.assertIn('value=handled_expr', grammar) + self.assertIn('"(" e=handled_expr ")"', grammar) + self.assertEqual(grammar.count("separated_list(COMMA, handled_expr)"), 3) + + def test_grouping_variants_are_mutually_distinct(self) -> None: + bracket = experiments.bracket_grouping(self.source) + keyword = experiments.keyword_grouping(self.source) + none = experiments.no_grouping(self.source) + self.assertIn('| "[" e=expr "]"', bracket) + self.assertIn('| GROUP "(" e=expr ")"', keyword) + self.assertNotIn("Nodes.Expr.Parenthized", none) + + +class WitnessSpellingTests(unittest.TestCase): + @staticmethod + def variant(name: str) -> experiments.Variant: + return next(v for v in experiments.VARIANTS if v.name == name) + + @staticmethod + def tokens(case_name: str, variant_name: str) -> str | None: + case = next(c for c in experiments.KNOWN_CASES if c.name == case_name) + return experiments.case_tokens( + case, WitnessSpellingTests.variant(variant_name) + ) + + def test_every_transform_has_a_spelling_update(self) -> None: + self.assertEqual( + set(experiments.TRANSFORMS), set(experiments.SPELLINGS) + ) + + def test_baseline_spelling_reproduces_original_witnesses(self) -> None: + expected = { + "nullable-array-binding": "ALIAS UIDENT EQUAL UIDENT QSTNMARK UIDENT " + "LBRACKET RBRACKET LBRACKET RBRACKET EOF", + "adjacent-computed-call": "UIDENT LPAREN RPAREN LCURLY LIDENT LPAREN " + "RPAREN LPAREN LIDENT RPAREN LPAREN RPAREN RCURLY EOF", + "abort-handler-attachment": "UIDENT LPAREN RPAREN LCURLY LIDENT LPAREN " + "TILDE TILDE LIDENT QSTNQSTN LIDENT RPAREN RCURLY EOF", + "named-call-statement": "UIDENT LPAREN RPAREN LCURLY LIDENT LPAREN " + "STRING RPAREN RCURLY EOF", + } + for name, tokens in expected.items(): + self.assertEqual(self.tokens(name, "baseline"), tokens) + + def test_bracket_calls_spell_print_hello_with_brackets(self) -> None: + self.assertEqual( + self.tokens("named-call-statement", "bracket-calls"), + "UIDENT LPAREN RPAREN LCURLY LIDENT LBRACKET STRING RBRACKET RCURLY EOF", + ) + + def test_semicolon_terminated_terminates_statements_and_decls(self) -> None: + self.assertEqual( + self.tokens("named-call-statement", "semicolon-terminated"), + "UIDENT LPAREN RPAREN LCURLY LIDENT LPAREN STRING RPAREN SEMICOLON " + "RCURLY SEMICOLON EOF", + ) + self.assertEqual( + self.tokens("nullable-array-binding", "semicolon-terminated"), + "ALIAS UIDENT EQUAL UIDENT QSTNMARK UIDENT LBRACKET RBRACKET " + "LBRACKET RBRACKET SEMICOLON EOF", + ) + + def test_semicolon_separated_splits_the_two_statement_reading(self) -> None: + self.assertEqual( + self.tokens("adjacent-computed-call", "semicolon-separated"), + "UIDENT LPAREN RPAREN LCURLY LIDENT LPAREN RPAREN SEMICOLON " + "LPAREN LIDENT RPAREN LPAREN RPAREN RCURLY EOF", + ) + + def test_computed_call_statements_can_be_inexpressible(self) -> None: + self.assertIsNone(self.tokens("adjacent-computed-call", "named-statement-calls")) + self.assertIsNone(self.tokens("adjacent-computed-call", "no-grouping")) + + def test_marked_computed_calls_keep_named_calls_plain(self) -> None: + self.assertEqual( + self.tokens("named-call-statement", "marked-computed-calls"), + "UIDENT LPAREN RPAREN LCURLY LIDENT LPAREN STRING RPAREN RCURLY EOF", + ) + self.assertEqual( + self.tokens("adjacent-computed-call", "marked-computed-calls"), + "UIDENT LPAREN RPAREN LCURLY LIDENT LPAREN RPAREN " + "LPAREN LIDENT RPAREN AT LPAREN RPAREN RCURLY EOF", + ) + + def test_transform_spellings_compose(self) -> None: + self.assertEqual( + self.tokens( + "adjacent-computed-call", "bracket-grouping-and-semicolons" + ), + "UIDENT LPAREN RPAREN LCURLY LIDENT LPAREN RPAREN SEMICOLON " + "LBRACKET LIDENT RBRACKET LPAREN RPAREN RCURLY EOF", + ) + + +if __name__ == "__main__": + unittest.main() From e62026f645b5b2eddcb3e2ff5bb4cbdcaa66c744 Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:31:46 +0200 Subject: [PATCH 141/154] Fix ambiguity tool build failure in dev profile (#39) 'just ambiguities' (and 'just prove' / 'just syntax-experiments') never ran: they build via 'dune exec', whose default dev profile treats warning 34 as an error, and the 'signature' type was declared but never referenced because the function of the same name shadowed every use. Annotate that function with the type so the dev-profile build succeeds. Also flush stdout/stderr before forking search workers so buffered output (e.g. the --prove candidate report) is not replayed once per worker at exit. Claude-Session: https://claude.ai/code/session_01BmybBm68SKByiXbHszu2Cn Co-authored-by: Claude --- tools/ambiguity_search.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/ambiguity_search.ml b/tools/ambiguity_search.ml index 2bc0e22d..8d7286d4 100644 --- a/tools/ambiguity_search.ml +++ b/tools/ambiguity_search.ml @@ -334,7 +334,7 @@ let add_count stack_id count frontier = let updated = cap_add old count in (IntMap.add stack_id updated frontier, updated - old) -let signature frontier = IntMap.bindings frontier +let signature frontier : signature = IntMap.bindings frontier let derivations frontier = IntMap.fold (fun _ count total -> cap_add total count) frontier 0 @@ -1030,6 +1030,9 @@ let parallel_unified_search engine ~jobs ~max_tokens ~timeout ~max_frontiers }, prefix_seeds + seeds ) else begin + (* Anything still buffered would be replayed by every child's exit. *) + flush stdout; + flush stderr; let children = ref [] in Array.iteri (fun index initial -> From 37590401e585d17cccd31cf64e575a158a68e920 Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Tue, 21 Jul 2026 19:57:32 +0200 Subject: [PATCH 142/154] Claude/ambiguity tool finder crash 750oe3 (#40) * Fix ambiguity tool build failure in dev profile 'just ambiguities' (and 'just prove' / 'just syntax-experiments') never ran: they build via 'dune exec', whose default dev profile treats warning 34 as an error, and the 'signature' type was declared but never referenced because the function of the same name shadowed every use. Annotate that function with the type so the dev-profile build succeeds. Also flush stdout/stderr before forking search workers so buffered output (e.g. the --prove candidate report) is not replayed once per worker at exit. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01BmybBm68SKByiXbHszu2Cn * Bound search memory instead of stopping at the frontier limit The searcher previously halted outright when the dedup table reached --max-frontiers, and its stack pool and closure cache grew without bound for as long as the search ran, which is how long runs ended in OOM kills. Deduplication is pruning, not correctness, so the table is now a bounded two-generation cache that forgets stale entries instead of stopping the search. The same budget caps the number of queued frontiers - a full queue drops new discoveries and the run reports itself as interrupted - and the stack pool is periodically compacted against the live queue (clearing the closure cache) on a geometric schedule. Resident memory is now roughly 2 KB per --max-frontiers unit per worker and stays flat over time, so the depth reached is bounded by --timeout and --max-tokens rather than by RAM; on the current grammar the same budget that previously stopped at 11-token witnesses reaches 15-token ones. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01BmybBm68SKByiXbHszu2Cn * Key the dedup cache on 124-bit digests; drop the Python search Storing full frontier signatures cost 100-200 bytes per dedup entry; hashing them through two independently seeded 62-bit mix lanes stores a 16-byte digest instead, so the same memory budget remembers four times as many frontiers and the search re-explores less (about a third more frontiers per second at deep settings). A digest collision could only skip a frontier wrongly, never fabricate a witness; the docs now state the completed-bound theorem is up to that astronomically unlikely case. tools/find_ambiguity.py was the slower Python reference implementation of the old algorithm and no longer matches the OCaml search's behavior; remove it and its ambiguities-python recipe. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01BmybBm68SKByiXbHszu2Cn * Address review: exact unique count, document 64-bit requirement Rediscovering a cached frontier at a shallower depth went through Seen_cache.insert and inflated the unique-frontier statistic; split the match so only genuinely new digests count as insertions. The digest mixer's constants need OCaml's 63-bit native int; state that the tool requires a 64-bit platform rather than boxing the hot path with Int64. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01BmybBm68SKByiXbHszu2Cn --------- Co-authored-by: Claude --- docs/ambiguity.md | 9 +- justfile | 4 - tools/ambiguity_search.ml | 177 +++++++++++++++--- tools/find_ambiguity.py | 374 -------------------------------------- 4 files changed, 161 insertions(+), 403 deletions(-) delete mode 100644 tools/find_ambiguity.py diff --git a/docs/ambiguity.md b/docs/ambiguity.md index bc86781a..53861b0d 100644 --- a/docs/ambiguity.md +++ b/docs/ambiguity.md @@ -35,8 +35,13 @@ the state is triaged into one of these categories. - `just ambiguities` — bounded, parallel GLR search for complete ambiguous sentences (`tools/ambiguity_search.ml`). A completed bound is a theorem - ("no ambiguous sentence of at most N tokens"); an interrupted bound is - evidence only. Witnesses are grouped by the conflict states they + ("no ambiguous sentence of at most N tokens"), up to the astronomically + unlikely collision of the 124-bit frontier digests used for + deduplication; an interrupted bound is evidence only. `--max-frontiers` + bounds resident memory per worker (an evicting digest cache plus a cap + on queued frontiers, roughly 2 KB per unit); the search itself is + bounded by `--max-tokens` and `--timeout`, and a run that had to drop + part of the space reports itself as interrupted. Witnesses are grouped by the conflict states they traverse, which maps each finding directly onto an obligation above. - `just prove` — conservative unambiguity prover (`--prove K`). It abstracts GLR stacks to their top-K states and exhaustively explores pairs of diff --git a/justfile b/justfile index 6632ab08..b5e9f1a6 100644 --- a/justfile +++ b/justfile @@ -27,10 +27,6 @@ ambiguities max_tokens="20" timeout="60" max_frontiers="500000" jobs="4" max_wit prove level="2" max_tokens="12" timeout="120" max_frontiers="2000000" jobs="4" menhir="menhir": dune exec tools/ambiguity_search.exe -- {{ grammarFile }} --prove {{ level }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --jobs {{ jobs }} -# Slower reference implementation, useful for cross-checking the OCaml search. -ambiguities-python max_tokens="20" timeout="60" max_frontiers="500000" menhir="menhir": - python3 tools/find_ambiguity.py {{ grammarFile }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} - # Compare all controlled syntax variants and write Markdown/JSON reports. syntax-experiments max_tokens="12" timeout="15" max_frontiers="150000" max_witnesses="10" jobs="4" menhir="menhir": dune build tools/ambiguity_search.exe diff --git a/tools/ambiguity_search.ml b/tools/ambiguity_search.ml index 8d7286d4..a6af76c5 100644 --- a/tools/ambiguity_search.ml +++ b/tools/ambiguity_search.ml @@ -324,6 +324,32 @@ module Stack_pool = struct match node.parent with | None -> None | Some parent -> pop parent (count - 1) + + let size pool = Hashtbl.length pool.by_id + + (* Drop every node not reachable from the root or from [iter_live]'s nodes. + Ids keep increasing across compactions, so a swept node re-created later + gets a fresh id and stale signatures in the dedup cache simply age out. *) + let compact pool iter_live = + let keep : (int, node) Hashtbl.t = Hashtbl.create 16_384 in + let rec mark node = + if not (Hashtbl.mem keep node.id) then begin + Hashtbl.add keep node.id node; + Option.iter mark node.parent + end + in + mark pool.root; + iter_live mark; + Hashtbl.reset pool.by_edge; + Hashtbl.reset pool.by_id; + Hashtbl.iter + (fun _ node -> + Hashtbl.add pool.by_id node.id node; + Option.iter + (fun parent -> + Hashtbl.add pool.by_edge (parent.id, node.state) node) + node.parent) + keep end type frontier = int IntMap.t @@ -866,28 +892,106 @@ type directed_item = { branched : bool; } +(* Bounded two-generation dedup cache over 124-bit frontier digests. Inserts + and hits go to the young generation; when it fills, the old generation is + dropped and the generations flip, so recently touched entries survive and + stale ones are forgotten. Deduplication is pruning, not correctness - a + forgotten entry costs re-exploration, never a missed witness - so a full + cache degrades the search instead of stopping it or exhausting memory. *) +module Seen_cache = struct + type digest = int * int + + (* The mix constants (and the lane seeds below) need OCaml's 63-bit native + int, so this tool requires a 64-bit platform; Int64 would box every + operation on this hot path. *) + let mix hash value = + let hash = hash + value in + let hash = (hash lxor (hash lsr 30)) * 0x3F58476D1CE4E5B9 in + let hash = (hash lxor (hash lsr 27)) * 0x14D049BB133111EB in + hash lxor (hash lsr 31) + + (* Two independently seeded 62-bit lanes make colliding distinct frontiers + astronomically unlikely even across billions of entries. A collision + could only skip a frontier wrongly, never produce a false witness. *) + let digest branched frontier = + let lane seed = + IntMap.fold + (fun stack_id count hash -> mix (mix hash stack_id) count) + frontier + (mix seed (Bool.to_int branched)) + in + (lane 0x2545F4914F6CDD1D, lane 0x27220A95FE4D1D65) + + type t = { + generation_capacity : int; + mutable young : (digest, int) Hashtbl.t; + mutable old : (digest, int) Hashtbl.t; + mutable inserted : int; + } + + (* Digest entries are an order of magnitude smaller than the queued items + the memory budget is sized for, so the cache can afford to remember + four times the budget: two generations of twice the budget each. *) + let create capacity = + { + generation_capacity = max 1 (2 * capacity); + young = Hashtbl.create 4_096; + old = Hashtbl.create 4_096; + inserted = 0; + } + + let find cache key = + match Hashtbl.find_opt cache.young key with + | Some _ as found -> found + | None -> Hashtbl.find_opt cache.old key + + let refresh cache key depth = + if + (not (Hashtbl.mem cache.young key)) + && Hashtbl.length cache.young >= cache.generation_capacity + then begin + cache.old <- cache.young; + cache.young <- Hashtbl.create 4_096 + end; + Hashtbl.replace cache.young key depth + + let insert cache key depth = + cache.inserted <- cache.inserted + 1; + refresh cache key depth +end + let unified_search engine initial ~max_tokens ~timeout ~max_frontiers ~max_witnesses conflict_distance accept_distance = let deadline = Unix.gettimeofday () +. timeout in let buckets = Array.init (max_tokens + 1) (fun _ -> Queue.create ()) in - let seen_plain = Hashtbl.create 16_384 in - let seen_branched = Hashtbl.create 16_384 in - let unique_count () = - Hashtbl.length seen_plain + Hashtbl.length seen_branched + let seen = Seen_cache.create max_frontiers in + let queued = ref 0 in + let dropped = ref false in + let enqueue item = + incr queued; + Queue.add item buckets.(item.depth) in + (* max_frontiers is a memory budget: it caps both the dedup cache and the + number of queued items. A full queue drops new discoveries (recorded so + the result is reported as incomplete) instead of growing without bound; + a dropped frontier can still be rediscovered once the queue drains, + because only enqueued frontiers enter the dedup cache. *) let add item = if item.depth <= max_tokens then if derivations item.frontier >= 2 && accepted_count engine item.frontier >= 2 - then Queue.add item buckets.(item.depth) + then enqueue item else - let seen = if item.branched then seen_branched else seen_plain in - let key = signature item.frontier in - match Hashtbl.find_opt seen key with - | Some depth when depth <= item.depth -> () - | _ when unique_count () < max_frontiers -> - Hashtbl.replace seen key item.depth; - Queue.add item buckets.(item.depth) - | _ -> () + let key = Seen_cache.digest item.branched item.frontier in + match Seen_cache.find seen key with + | Some depth when depth <= item.depth -> + Seen_cache.refresh seen key depth + | Some _ when !queued < max_frontiers -> + Seen_cache.refresh seen key item.depth; + enqueue item + | None when !queued < max_frontiers -> + Seen_cache.insert seen key item.depth; + enqueue item + | _ -> dropped := true in List.iter add initial; let explored = ref 0 in @@ -896,16 +1000,40 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers let witnesses = Hashtbl.create max_witnesses in let stopped = ref None in let depth = ref 0 in + (* The stack pool and closure cache also grow with the search; sweep them + against the live queue on a geometric schedule so total memory stays + proportional to max_frontiers plus the queue itself. *) + let stack_budget = max 65_536 (4 * max_frontiers) in + let compact_floor = ref stack_budget in + let mark_live mark = + Array.iter + (fun bucket -> + Queue.iter + (fun item -> + IntMap.iter + (fun stack_id _ -> + mark (Stack_pool.find engine.stacks stack_id)) + item.frontier) + bucket) + buckets + in + let maybe_compact () = + if Stack_pool.size engine.stacks > !compact_floor then begin + Stack_pool.compact engine.stacks mark_live; + Hashtbl.reset engine.closure_cache; + compact_floor := max stack_budget (2 * Stack_pool.size engine.stacks) + end + in while Hashtbl.length witnesses < max_witnesses && !depth <= max_tokens - && !explored < max_frontiers - && unique_count () < max_frontiers && Unix.gettimeofday () < deadline do if Queue.is_empty buckets.(!depth) then incr depth else begin + maybe_compact (); let item = Queue.take buckets.(!depth) in + decr queued; incr explored; deepest := max !deepest item.depth; if accepted_count engine item.frontier >= 2 then begin @@ -938,19 +1066,19 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers (possible_tokens engine item.frontier) end done; - if !explored >= max_frontiers || unique_count () >= max_frontiers then - stopped := Some "the frontier limit was reached" - else if Unix.gettimeofday () >= deadline then - stopped := Some "the timeout was reached" - else if Hashtbl.length witnesses >= max_witnesses then - stopped := Some "the witness limit was reached"; + if Unix.gettimeofday () >= deadline then + stopped := Some "the timeout was reached" + else if Hashtbl.length witnesses >= max_witnesses then + stopped := Some "the witness limit was reached" + else if !dropped then + stopped := Some "the memory budget dropped part of the search space"; ( { witnesses = Hashtbl.fold (fun profile tokens result -> (profile, tokens) :: result) witnesses []; explored = !explored; - unique = unique_count (); + unique = seen.Seen_cache.inserted; deepest = !deepest; stopped = !stopped; }, @@ -1109,7 +1237,10 @@ let options = [ ("--menhir", Arg.Set_string menhir, "PATH Menhir executable"); ("--max-tokens", Arg.Set_int max_tokens, "N maximum tokens, including EOF"); - ("--max-frontiers", Arg.Set_int max_frontiers, "N search-state limit per worker"); + ( "--max-frontiers", + Arg.Set_int max_frontiers, + "N dedup-cache entries per worker; bounds memory, not the search \ + (and the abstract pair count under --prove)" ); ("--timeout", Arg.Set_float timeout, "SECONDS time limit per search phase"); ("--jobs", Arg.Set_int jobs, "N worker processes"); ("--max-witnesses", Arg.Set_int max_witnesses, "N ambiguity families to report"); diff --git a/tools/find_ambiguity.py b/tools/find_ambiguity.py deleted file mode 100644 index 0693e8fc..00000000 --- a/tools/find_ambiguity.py +++ /dev/null @@ -1,374 +0,0 @@ -#!/usr/bin/env python3 -"""Find short, complete ambiguities in a Menhir grammar. - -The search is bounded by token count. It asks Menhir for a fully expanded -grammar and LR(1) automaton, then explores that automaton as a GLR parser would: -all shift and reduce actions are retained. Equivalent LR stacks are merged, -but their number of derivations is retained (and capped at two, because that is -enough to prove ambiguity). - -This is a bounded search, not a proof of unambiguity. If it finishes without a -witness, it proves only that no witness was found within the requested bounds. -""" - -from __future__ import annotations - -import argparse -import ast -from collections import defaultdict, deque -from dataclasses import dataclass, field -from pathlib import Path -import re -import shutil -import subprocess -import sys -import tempfile -import time -from typing import Mapping - - -Stack = tuple[int, ...] -Frontier = dict[Stack, int] -FrontierKey = frozenset[tuple[Stack, int]] - - -@dataclass -class State: - transitions: dict[str, int] = field(default_factory=dict) - reductions: dict[str, list[tuple[str, int]]] = field( - default_factory=lambda: defaultdict(list) - ) - accepts: set[str] = field(default_factory=set) - - -@dataclass -class Automaton: - states: dict[int, State] - terminals: tuple[str, ...] - - -STATE_RE = re.compile(r"^State (\d+):$") -TRANSITION_RE = re.compile(r"^-- On (\S+) shift to state (\d+)$") -LOOKAHEAD_RE = re.compile(r"^-- On (.+)$") -REDUCTION_RE = re.compile(r"^-- reduce production (.+?) ->(?: (.*))?$") -ACCEPT_RE = re.compile(r"^-- accept (\S+)$") -TOKEN_DECL_RE = re.compile(r"^\s*%token(?:\s*<[^>]+>)?\s+(.*)$") -TOKEN_AND_ALIAS_RE = re.compile( - r'\b([A-Z][A-Z0-9_]*)(?:\s*("(?:[^"\\]|\\.)*"))?' -) - - -def cap_add(left: int, right: int) -> int: - return min(2, left + right) - - -def key(frontier: Mapping[Stack, int]) -> FrontierKey: - return frozenset(frontier.items()) - - -def strip_comments(source: str) -> str: - """Strip nested OCaml and non-nested C comments, preserving line breaks.""" - result: list[str] = [] - index = 0 - while index < len(source): - if source.startswith("(*", index): - depth = 1 - index += 2 - while index < len(source) and depth: - if source.startswith("(*", index): - depth += 1 - index += 2 - elif source.startswith("*)", index): - depth -= 1 - index += 2 - else: - if source[index] == "\n": - result.append("\n") - index += 1 - elif source.startswith("/*", index): - index += 2 - while index < len(source): - if source.startswith("*/", index): - index += 2 - break - if source[index] == "\n": - result.append("\n") - index += 1 - else: - result.append(source[index]) - index += 1 - return "".join(result) - - -def parse_aliases(grammar: Path) -> tuple[set[str], dict[str, str]]: - terminals: set[str] = set() - aliases: dict[str, str] = {} - source = strip_comments(grammar.read_text(encoding="utf-8")) - for line in source.splitlines(): - match = TOKEN_DECL_RE.match(line) - if not match: - continue - for token, quoted_alias in TOKEN_AND_ALIAS_RE.findall(match.group(1)): - terminals.add(token) - if quoted_alias: - try: - aliases[token] = ast.literal_eval(quoted_alias) - except (SyntaxError, ValueError): - aliases[token] = quoted_alias[1:-1] - return terminals, aliases - - -def run_menhir(menhir: str, grammar: Path, directory: Path) -> Path: - expanded = directory / "expanded.mly" - preprocess = subprocess.run( - [menhir, "--only-preprocess-uu", str(grammar)], - text=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - if preprocess.returncode != 0: - sys.stderr.write(preprocess.stderr) - raise RuntimeError("Menhir failed to preprocess the grammar") - expanded.write_text(preprocess.stdout, encoding="utf-8") - - base = directory / "automaton" - build = subprocess.run( - [menhir, "--dump", "--base", str(base), str(expanded)], - text=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - automaton = base.with_suffix(".automaton") - if not automaton.exists(): - sys.stderr.write(build.stderr) - raise RuntimeError("Menhir did not produce an LR automaton") - # Some Menhir versions exit unsuccessfully after emitting the complete - # automaton when unresolved reduce/reduce conflicts exist. That automaton - # is exactly what this tool needs, so the exit status is intentionally not - # treated as fatal here. - return automaton - - -def parse_automaton(path: Path, terminals: set[str]) -> Automaton: - states: dict[int, State] = {} - current: State | None = None - lookaheads: tuple[str, ...] = () - - for line in path.read_text(encoding="utf-8").splitlines(): - if match := STATE_RE.match(line): - current = states.setdefault(int(match.group(1)), State()) - lookaheads = () - continue - if current is None: - continue - if match := TRANSITION_RE.match(line): - symbol, target = match.groups() - current.transitions[symbol] = int(target) - lookaheads = () - continue - if match := LOOKAHEAD_RE.match(line): - lookaheads = tuple(match.group(1).split()) - continue - if match := REDUCTION_RE.match(line): - lhs, rhs = match.groups() - rhs_length = 0 if not rhs else len(rhs.split()) - for token in lookaheads: - current.reductions[token].append((lhs, rhs_length)) - continue - if ACCEPT_RE.match(line): - current.accepts.update(lookaheads) - - if 0 not in states: - raise RuntimeError("could not find initial state 0 in Menhir automaton") - return Automaton(states, tuple(sorted(terminals))) - - -def add_count(frontier: Frontier, stack: Stack, count: int) -> int: - old = frontier.get(stack, 0) - new = cap_add(old, count) - frontier[stack] = new - return new - old - - -def reduction_closure( - automaton: Automaton, frontier: Mapping[Stack, int], lookahead: str -) -> Frontier: - """Apply zero or more reductions while preserving derivation counts.""" - closure: Frontier = dict(frontier) - propagated: Frontier = {} - queue: deque[Stack] = deque(closure) - - while queue: - stack = queue.popleft() - available = closure[stack] - propagated.get(stack, 0) - if available <= 0: - continue - propagated[stack] = closure[stack] - state = automaton.states[stack[-1]] - - for lhs, rhs_length in state.reductions.get(lookahead, ()): - if rhs_length >= len(stack): - continue - base = stack if rhs_length == 0 else stack[:-rhs_length] - goto = automaton.states[base[-1]].transitions.get(lhs) - if goto is None: - continue - reduced = base + (goto,) - if add_count(closure, reduced, available): - queue.append(reduced) - return closure - - -def shift( - automaton: Automaton, frontier: Mapping[Stack, int], token: str -) -> Frontier: - shifted: Frontier = {} - for stack, count in reduction_closure(automaton, frontier, token).items(): - target = automaton.states[stack[-1]].transitions.get(token) - if target is not None: - add_count(shifted, stack + (target,), count) - return shifted - - -def accepted_count(automaton: Automaton, frontier: Mapping[Stack, int]) -> int: - total = 0 - for stack, count in reduction_closure(automaton, frontier, "#").items(): - if "#" in automaton.states[stack[-1]].accepts: - total = cap_add(total, count) - return total - - -def possible_tokens(automaton: Automaton, frontier: Mapping[Stack, int]) -> set[str]: - """Return exact lookaheads on which at least one stack has an action.""" - tokens: set[str] = set() - terminals = set(automaton.terminals) - for stack in frontier: - state = automaton.states[stack[-1]] - tokens.update(symbol for symbol in state.transitions if symbol in terminals) - tokens.update(state.reductions) - tokens.discard("#") - return tokens - - -def render(tokens: tuple[str, ...], aliases: Mapping[str, str]) -> str: - concrete = [aliases.get(token, f"<{token}>") for token in tokens if token != "EOF"] - return " ".join(concrete) - - -def search( - automaton: Automaton, - max_tokens: int, - max_frontiers: int, - timeout: float, - progress: bool, -) -> tuple[tuple[str, ...] | None, int, int, int, str | None]: - initial: Frontier = {(0,): 1} - queue: deque[tuple[tuple[str, ...], Frontier]] = deque([((), initial)]) - seen: set[FrontierKey] = {key(initial)} - explored = 0 - started = time.monotonic() - current_depth = -1 - deepest = 0 - stopped: str | None = None - - while queue: - tokens, frontier = queue.popleft() - explored += 1 - depth = len(tokens) - deepest = max(deepest, depth) - - if progress and depth != current_depth: - current_depth = depth - print( - f"depth {depth}: explored {explored:,}, queued {len(queue):,}, " - f"unique frontiers {len(seen):,}", - file=sys.stderr, - ) - - if accepted_count(automaton, frontier) >= 2: - return tokens, explored, len(seen), deepest, None - if depth >= max_tokens: - continue - if explored >= max_frontiers: - stopped = f"the {max_frontiers:,}-frontier limit was reached" - break - if timeout and time.monotonic() - started >= timeout: - stopped = f"the {timeout:g}-second timeout was reached" - break - - for token in possible_tokens(automaton, frontier): - next_frontier = shift(automaton, frontier, token) - if not next_frontier: - continue - signature = key(next_frontier) - if signature in seen: - continue - seen.add(signature) - queue.append((tokens + (token,), next_frontier)) - - return None, explored, len(seen), deepest, stopped - - -def main() -> int: - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("grammar", type=Path, help="Menhir .mly grammar") - parser.add_argument("--menhir", default="menhir", help="Menhir executable") - parser.add_argument( - "--max-tokens", type=int, default=20, help="maximum tokens, including EOF" - ) - parser.add_argument( - "--max-frontiers", type=int, default=500_000, help="search-state limit" - ) - parser.add_argument( - "--timeout", type=float, default=60.0, help="time limit in seconds; 0 disables" - ) - parser.add_argument("--quiet", action="store_true", help="hide depth progress") - args = parser.parse_args() - - grammar = args.grammar.resolve() - menhir = shutil.which(args.menhir) - if menhir is None: - parser.error(f"Menhir executable not found: {args.menhir!r}") - if not grammar.is_file(): - parser.error(f"grammar does not exist: {grammar}") - - terminals, aliases = parse_aliases(grammar) - try: - with tempfile.TemporaryDirectory(prefix="zane-ambiguity-") as temporary: - automaton_path = run_menhir(menhir, grammar, Path(temporary)) - automaton = parse_automaton(automaton_path, terminals) - witness, explored, unique, deepest, stopped = search( - automaton, - max(0, args.max_tokens), - max(1, args.max_frontiers), - max(0.0, args.timeout), - not args.quiet, - ) - except (OSError, RuntimeError) as error: - print(f"error: {error}", file=sys.stderr) - return 2 - - if witness is None: - if stopped is None: - print( - f"No complete ambiguity found through {args.max_tokens} tokens " - f"after exploring {explored:,} frontiers ({unique:,} unique)." - ) - else: - print( - f"Search stopped at depth {deepest} because {stopped}; no complete " - f"ambiguity was found in {explored:,} explored frontiers " - f"({unique:,} unique)." - ) - print("This is a bounded result, not a proof of unambiguity.") - return 0 - - print("Complete ambiguity found.") - print(f"Tokens ({len(witness)}): {' '.join(witness)}") - print(f"Source: {render(witness, aliases)}") - print(f"Explored {explored:,} frontiers ({unique:,} unique).") - return 1 - - -if __name__ == "__main__": - raise SystemExit(main()) From 45b2a4352d237b37043928487ce7b1ad4aaf4af2 Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:10:37 +0200 Subject: [PATCH 143/154] Decouple ambiguity search reach from dedup memory budget (#41) Since the memory-bounding change, --max-frontiers did double duty: it sized the dedup cache (memory) and also capped the work queue (search reach). Lowering it to fit RAM therefore shrank the queue, so deep frontiers were dropped and the depth-bucket BFS terminated early, well before the timeout. Split the queue cap into its own --max-queue knob (defaulting to --max-frontiers, so existing invocations are unchanged). The queue is the live set that drives stack-pool memory, so the stack budget now tracks --max-queue; --max-frontiers is left as the independent dedup-cache budget, where a smaller table simply prunes less. This lets a run hold a deep queue without paying the 4x dedup over-provision, or shrink the dedup table without capping reach. Thread --max-queue through the just recipe and document both budgets. Claude-Session: https://claude.ai/code/session_016ratmfeMyTD7pMxaHDMiR6 Co-authored-by: Claude --- docs/ambiguity.md | 14 ++++++++----- justfile | 4 ++-- tools/ambiguity_search.ml | 42 ++++++++++++++++++++++++--------------- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/docs/ambiguity.md b/docs/ambiguity.md index 53861b0d..3ce92662 100644 --- a/docs/ambiguity.md +++ b/docs/ambiguity.md @@ -37,11 +37,15 @@ the state is triaged into one of these categories. sentences (`tools/ambiguity_search.ml`). A completed bound is a theorem ("no ambiguous sentence of at most N tokens"), up to the astronomically unlikely collision of the 124-bit frontier digests used for - deduplication; an interrupted bound is evidence only. `--max-frontiers` - bounds resident memory per worker (an evicting digest cache plus a cap - on queued frontiers, roughly 2 KB per unit); the search itself is - bounded by `--max-tokens` and `--timeout`, and a run that had to drop - part of the space reports itself as interrupted. Witnesses are grouped by the conflict states they + deduplication; an interrupted bound is evidence only. Two independent + per-worker budgets control the search: `--max-queue` caps the number of + queued frontiers — the search reach, and the live set that stack memory + tracks — while `--max-frontiers` sizes the evicting digest cache that + prunes redundant work (`--max-queue` defaults to `--max-frontiers`). + Together they run at roughly 2 KB per unit of resident memory; the search + itself is bounded by `--max-tokens` and `--timeout`, and a run whose queue + filled and had to drop part of the space reports itself as interrupted. + Witnesses are grouped by the conflict states they traverse, which maps each finding directly onto an obligation above. - `just prove` — conservative unambiguity prover (`--prove K`). It abstracts GLR stacks to their top-K states and exhaustively explores pairs of diff --git a/justfile b/justfile index b5e9f1a6..e5bb5feb 100644 --- a/justfile +++ b/justfile @@ -20,8 +20,8 @@ conflicts: menhir {{ grammarFile }} --random-sentence-concrete package --random-seed 1 --random-sentence-length 16 # Find a short complete ambiguity within a bounded, parallel GLR search. -ambiguities max_tokens="20" timeout="60" max_frontiers="500000" jobs="4" max_witnesses="20" menhir="menhir": - dune exec tools/ambiguity_search.exe -- {{ grammarFile }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --jobs {{ jobs }} --max-witnesses {{ max_witnesses }} +ambiguities max_tokens="20" timeout="60" max_frontiers="500000" jobs="4" max_witnesses="20" menhir="menhir" max_queue="0": + dune exec tools/ambiguity_search.exe -- {{ grammarFile }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --jobs {{ jobs }} --max-witnesses {{ max_witnesses }} --max-queue {{ max_queue }} # Conservative unambiguity proof attempt: exit 0 proven, 1 ambiguous, 3 not proven. prove level="2" max_tokens="12" timeout="120" max_frontiers="2000000" jobs="4" menhir="menhir": diff --git a/tools/ambiguity_search.ml b/tools/ambiguity_search.ml index a6af76c5..f8597460 100644 --- a/tools/ambiguity_search.ml +++ b/tools/ambiguity_search.ml @@ -961,7 +961,7 @@ module Seen_cache = struct end let unified_search engine initial ~max_tokens ~timeout ~max_frontiers - ~max_witnesses conflict_distance accept_distance = + ~max_queue ~max_witnesses conflict_distance accept_distance = let deadline = Unix.gettimeofday () +. timeout in let buckets = Array.init (max_tokens + 1) (fun _ -> Queue.create ()) in let seen = Seen_cache.create max_frontiers in @@ -971,11 +971,12 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers incr queued; Queue.add item buckets.(item.depth) in - (* max_frontiers is a memory budget: it caps both the dedup cache and the - number of queued items. A full queue drops new discoveries (recorded so - the result is reported as incomplete) instead of growing without bound; - a dropped frontier can still be rediscovered once the queue drains, - because only enqueued frontiers enter the dedup cache. *) + (* max_queue caps the number of queued items - the search reach. A full + queue drops new discoveries (recorded so the result is reported as + incomplete) instead of growing without bound; a dropped frontier can + still be rediscovered once the queue drains, because only enqueued + frontiers enter the dedup cache. max_frontiers is the independent dedup + memory budget (see Seen_cache above): a smaller table simply prunes less. *) let add item = if item.depth <= max_tokens then if derivations item.frontier >= 2 && accepted_count engine item.frontier >= 2 @@ -985,10 +986,10 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers match Seen_cache.find seen key with | Some depth when depth <= item.depth -> Seen_cache.refresh seen key depth - | Some _ when !queued < max_frontiers -> + | Some _ when !queued < max_queue -> Seen_cache.refresh seen key item.depth; enqueue item - | None when !queued < max_frontiers -> + | None when !queued < max_queue -> Seen_cache.insert seen key item.depth; enqueue item | _ -> dropped := true @@ -1002,8 +1003,9 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers let depth = ref 0 in (* The stack pool and closure cache also grow with the search; sweep them against the live queue on a geometric schedule so total memory stays - proportional to max_frontiers plus the queue itself. *) - let stack_budget = max 65_536 (4 * max_frontiers) in + proportional to the queue itself (the live set marked below), whose size + is bounded by max_queue. *) + let stack_budget = max 65_536 (4 * max_queue) in let compact_floor = ref stack_budget in let mark_live mark = Array.iter @@ -1142,14 +1144,14 @@ let initial_partitions engine jobs max_tokens = end let parallel_unified_search engine ~jobs ~max_tokens ~timeout ~max_frontiers - ~max_witnesses conflict_distance accept_distance temporary = + ~max_queue ~max_witnesses conflict_distance accept_distance temporary = let partitions, prefix_explored, prefix_unique, prefix_seeds = initial_partitions engine (max 1 jobs) max_tokens in if Array.length partitions = 1 then let outcome, seeds = unified_search engine partitions.(0) ~max_tokens ~timeout ~max_frontiers - ~max_witnesses conflict_distance accept_distance + ~max_queue ~max_witnesses conflict_distance accept_distance in ( { outcome with @@ -1169,7 +1171,7 @@ let parallel_unified_search engine ~jobs ~max_tokens ~timeout ~max_frontiers | 0 -> let result = unified_search engine initial ~max_tokens ~timeout ~max_frontiers - ~max_witnesses conflict_distance accept_distance + ~max_queue ~max_witnesses conflict_distance accept_distance in let channel = open_out_bin output in Marshal.to_channel channel result []; @@ -1227,6 +1229,7 @@ let grammar = ref "" let menhir = ref "menhir" let max_tokens = ref 20 let max_frontiers = ref 500_000 +let max_queue = ref 0 let timeout = ref 60. let jobs = ref 1 let max_witnesses = ref 20 @@ -1239,8 +1242,13 @@ let options = ("--max-tokens", Arg.Set_int max_tokens, "N maximum tokens, including EOF"); ( "--max-frontiers", Arg.Set_int max_frontiers, - "N dedup-cache entries per worker; bounds memory, not the search \ + "N dedup-cache entries per worker; bounds dedup memory, not the search \ (and the abstract pair count under --prove)" ); + ( "--max-queue", + Arg.Set_int max_queue, + "N queued frontiers per worker; the search reach (a full queue drops \ + discoveries and reports the run incomplete). Its live set drives stack \ + memory. Defaults to --max-frontiers" ); ("--timeout", Arg.Set_float timeout, "SECONDS time limit per search phase"); ("--jobs", Arg.Set_int jobs, "N worker processes"); ("--max-witnesses", Arg.Set_int max_witnesses, "N ambiguity families to report"); @@ -1263,6 +1271,8 @@ let main () = end; if !max_tokens < 0 then invalid_arg "--max-tokens must be at least 0"; if !max_frontiers < 1 then invalid_arg "--max-frontiers must be at least 1"; + if !max_queue < 0 then invalid_arg "--max-queue must be non-negative"; + if !max_queue = 0 then max_queue := !max_frontiers; if !timeout < 0. then invalid_arg "--timeout must be non-negative"; if !jobs < 1 then invalid_arg "--jobs must be at least 1"; if !max_witnesses < 1 then invalid_arg "--max-witnesses must be at least 1"; @@ -1326,8 +1336,8 @@ let main () = let outcome, conflict_seeds = parallel_unified_search engine ~jobs:!jobs ~max_tokens:!max_tokens ~timeout:!timeout ~max_frontiers:!max_frontiers - ~max_witnesses:!max_witnesses conflict_distance accept_distance - temporary + ~max_queue:!max_queue ~max_witnesses:!max_witnesses conflict_distance + accept_distance temporary in match outcome.witnesses with | [] -> From 9ff6d12002efe3d6c0547cc98da0a55fe15eb27e Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:36:30 +0200 Subject: [PATCH 144/154] Claude/ambiguity finder config t3a4aw (#42) * Decouple ambiguity search reach from dedup memory budget Since the memory-bounding change, --max-frontiers did double duty: it sized the dedup cache (memory) and also capped the work queue (search reach). Lowering it to fit RAM therefore shrank the queue, so deep frontiers were dropped and the depth-bucket BFS terminated early, well before the timeout. Split the queue cap into its own --max-queue knob (defaulting to --max-frontiers, so existing invocations are unchanged). The queue is the live set that drives stack-pool memory, so the stack budget now tracks --max-queue; --max-frontiers is left as the independent dedup-cache budget, where a smaller table simply prunes less. This lets a run hold a deep queue without paying the 4x dedup over-provision, or shrink the dedup table without capping reach. Thread --max-queue through the just recipe and document both budgets. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_016ratmfeMyTD7pMxaHDMiR6 * add first run --------- Co-authored-by: Claude --- ambiguity-report.txt | 204 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 ambiguity-report.txt diff --git a/ambiguity-report.txt b/ambiguity-report.txt new file mode 100644 index 00000000..d3bcbbc8 --- /dev/null +++ b/ambiguity-report.txt @@ -0,0 +1,204 @@ +Found 50 complete ambiguity families. + +1. Tokens (9): LIDENT UIDENT EQUAL TILDE TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = ~ ~ false ?? false + Conflict origins: state 564 on QSTNQSTN + +2. Tokens (10): LIDENT UIDENT EQUAL FALSE EQEQ TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false == ~ false ?? false + Conflict origins: state 189 on QSTNQSTN, state 564 on QSTNQSTN + +3. Tokens (10): LIDENT UIDENT EQUAL FALSE LESS TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false < ~ false ?? false + Conflict origins: state 181 on QSTNQSTN, state 564 on QSTNQSTN + +4. Tokens (10): LIDENT UIDENT EQUAL FALSE LESSEQ TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false <= ~ false ?? false + Conflict origins: state 173 on QSTNQSTN, state 564 on QSTNQSTN + +5. Tokens (10): LIDENT UIDENT EQUAL FALSE MINUS TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false - ~ false ?? false + Conflict origins: state 153 on QSTNQSTN, state 564 on QSTNQSTN + +6. Tokens (10): LIDENT UIDENT EQUAL FALSE MORE TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false > ~ false ?? false + Conflict origins: state 165 on QSTNQSTN, state 564 on QSTNQSTN + +7. Tokens (10): LIDENT UIDENT EQUAL FALSE MOREEQ TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false >= ~ false ?? false + Conflict origins: state 149 on QSTNQSTN, state 564 on QSTNQSTN + +8. Tokens (10): LIDENT UIDENT EQUAL FALSE PLUS TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false + ~ false ?? false + Conflict origins: state 141 on QSTNQSTN, state 564 on QSTNQSTN + +9. Tokens (10): LIDENT UIDENT EQUAL FALSE SLASH TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false / ~ false ?? false + Conflict origins: state 133 on QSTNQSTN, state 564 on QSTNQSTN + +10. Tokens (10): LIDENT UIDENT EQUAL FALSE STAR TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false * ~ false ?? false + Conflict origins: state 123 on QSTNQSTN, state 564 on QSTNQSTN + +11. Tokens (10): LIDENT UIDENT EQUAL TILDE FALSE LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = ~ false ( ) ?? false + Conflict origins: state 126 on LPAREN, state 129 on QSTNQSTN, state 564 on QSTNQSTN + +12. Tokens (10): LIDENT UIDENT EQUAL TILDE TILDE FALSE QSTNMARK LCURLY RCURLY EOF + Source: length Int = ~ ~ false ? { } + Conflict origins: state 564 on QSTNMARK + +13. Tokens (10): LIDENT UIDENT EQUAL TILDE UIDENT LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = ~ Int ( ) ?? false + Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 564 on QSTNQSTN + +14. Tokens (10): LIDENT UIDENT LPAREN TILDE TILDE FALSE QSTNQSTN FALSE RPAREN EOF + Source: length Int ( ~ ~ false ?? false ) + Conflict origins: state 311 on LPAREN, state 564 on QSTNQSTN + +15. Tokens (11): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNQSTN FALSE DOT LIDENT EOF + Source: length Int = false ( ) ?? false . length + Conflict origins: state 126 on DOT, state 126 on LPAREN, state 129 on QSTNQSTN + +16. Tokens (11): LIDENT UIDENT EQUAL TILDE TILDE FALSE QSTNQSTN FALSE DOT LIDENT EOF + Source: length Int = ~ ~ false ?? false . length + Conflict origins: state 126 on DOT, state 564 on QSTNQSTN + +17. Tokens (11): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNQSTN FALSE DOT LIDENT EOF + Source: length Int = Int ( ) ?? false . length + Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 126 on DOT + +18. Tokens (11): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN THICK_ARROW FALSE DOT LIDENT EOF + Source: length Int = Int ( ) => false . length + Conflict origins: state 80 on LPAREN, state 126 on DOT + +19. Tokens (11): LIDENT UIDENT QSTNMARK UIDENT LBRACKET RBRACKET LPAREN RPAREN LCURLY RCURLY EOF + Source: length Int ? Int [ ] ( ) { } + Conflict origins: state 57 on LPAREN + +20. Tokens (11): LTYPE UIDENT EQUAL UIDENT QSTNMARK UIDENT LBRACKET RBRACKET LBRACKET RBRACKET EOF + Source: type Int = Int ? Int [ ] [ ] + Conflict origins: state 57 on LBRACKET + +21. Tokens (12): LIDENT UIDENT EQUAL FALSE EQEQ TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF + Source: length Int = false == ~ false ?? "john" . length + Conflict origins: state 126 on DOT, state 189 on QSTNQSTN, state 564 on QSTNQSTN + +22. Tokens (12): LIDENT UIDENT EQUAL FALSE LESS TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF + Source: length Int = false < ~ false ?? "john" . length + Conflict origins: state 126 on DOT, state 181 on QSTNQSTN, state 564 on QSTNQSTN + +23. Tokens (12): LIDENT UIDENT EQUAL FALSE LESSEQ TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF + Source: length Int = false <= ~ false ?? "john" . length + Conflict origins: state 126 on DOT, state 173 on QSTNQSTN, state 564 on QSTNQSTN + +24. Tokens (12): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = false ( ) ? => 8.647 . length + Conflict origins: state 126 on DOT, state 126 on LPAREN, state 129 on QSTNMARK + +25. Tokens (12): LIDENT UIDENT EQUAL FALSE MINUS TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF + Source: length Int = false - ~ false ?? "john" . length + Conflict origins: state 126 on DOT, state 153 on QSTNQSTN, state 564 on QSTNQSTN + +26. Tokens (12): LIDENT UIDENT EQUAL FALSE MORE TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF + Source: length Int = false > ~ false ?? "john" . length + Conflict origins: state 126 on DOT, state 165 on QSTNQSTN, state 564 on QSTNQSTN + +27. Tokens (12): LIDENT UIDENT EQUAL FALSE MOREEQ TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF + Source: length Int = false >= ~ false ?? "john" . length + Conflict origins: state 126 on DOT, state 149 on QSTNQSTN, state 564 on QSTNQSTN + +28. Tokens (12): LIDENT UIDENT EQUAL FALSE PLUS TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF + Source: length Int = false + ~ false ?? "john" . length + Conflict origins: state 126 on DOT, state 141 on QSTNQSTN, state 564 on QSTNQSTN + +29. Tokens (12): LIDENT UIDENT EQUAL FALSE SLASH TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF + Source: length Int = false / ~ false ?? "john" . length + Conflict origins: state 126 on DOT, state 133 on QSTNQSTN, state 564 on QSTNQSTN + +30. Tokens (12): LIDENT UIDENT EQUAL FALSE STAR TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF + Source: length Int = false * ~ false ?? "john" . length + Conflict origins: state 123 on QSTNQSTN, state 126 on DOT, state 564 on QSTNQSTN + +31. Tokens (12): LIDENT UIDENT EQUAL TILDE FALSE LPAREN RPAREN QSTNQSTN STRING DOT LIDENT EOF + Source: length Int = ~ false ( ) ?? "john" . length + Conflict origins: state 126 on DOT, state 126 on LPAREN, state 129 on QSTNQSTN, state 564 on QSTNQSTN + +32. Tokens (12): LIDENT UIDENT EQUAL TILDE TILDE FALSE QSTNMARK THICK_ARROW STRING DOT LIDENT EOF + Source: length Int = ~ ~ false ? => "john" . length + Conflict origins: state 126 on DOT, state 564 on QSTNMARK + +33. Tokens (12): LIDENT UIDENT EQUAL TILDE UIDENT LPAREN RPAREN QSTNQSTN STRING DOT LIDENT EOF + Source: length Int = ~ Int ( ) ?? "john" . length + Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 126 on DOT, state 564 on QSTNQSTN + +34. Tokens (12): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = Int ( ) ? => 8.647 . length + Conflict origins: state 80 on LPAREN, state 119 on QSTNMARK, state 126 on DOT + +35. Tokens (13): LIDENT UIDENT LPAREN FALSE EQEQ TILDE FALSE QSTNQSTN LIDENT DOLLAR LIDENT RPAREN EOF + Source: length Int ( false == ~ false ?? length $ length ) + Conflict origins: state 189 on QSTNQSTN, state 311 on LPAREN, state 564 on QSTNQSTN + +36. Tokens (13): LIDENT UIDENT QSTNMARK UIDENT LBRACKET RBRACKET LPAREN RPAREN THICK_ARROW STRING DOT LIDENT EOF + Source: length Int ? Int [ ] ( ) => "john" . length + Conflict origins: state 57 on LPAREN, state 126 on DOT + +37. Tokens (15): LIDENT UIDENT EQUAL TILDE FALSE QSTNMARK THICK_ARROW FALSE EQEQ AND AT LIDENT DOLLAR LIDENT EOF + Source: length Int = ~ false ? => false == & @ length $ length + Conflict origins: state 564 on QSTNMARK, state 571 on EQEQ + +38. Tokens (16): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNQSTN FALSE LESS AND AND AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false ( ) ?? false < & & @ length $ length + Conflict origins: state 126 on LPAREN, state 129 on QSTNQSTN, state 131 on LESS + +39. Tokens (16): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNQSTN FALSE LESS AND AND AT LIDENT DOLLAR LIDENT EOF + Source: length Int = Int ( ) ?? false < & & @ length $ length + Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 121 on LESS + +40. Tokens (16): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN THICK_ARROW FALSE LESS AND AND AT LIDENT DOLLAR LIDENT EOF + Source: length Int = Int ( ) => false < & & @ length $ length + Conflict origins: state 80 on LPAREN, state 571 on LESS + +41. Tokens (16): LIDENT UIDENT LPAREN AND TILDE TILDE FALSE QSTNQSTN AT LIDENT DOLLAR LIDENT DOT LIDENT RPAREN EOF + Source: length Int ( & ~ ~ false ?? @ length $ length . length ) + Conflict origins: state 126 on DOT, state 311 on LPAREN, state 564 on QSTNQSTN + +42. Tokens (16): LIDENT UIDENT QSTNMARK UIDENT LBRACKET RBRACKET LBRACKET RBRACKET EQUAL AT LIDENT DOLLAR LIDENT DOT LIDENT EOF + Source: length Int ? Int [ ] [ ] = @ length $ length . length + Conflict origins: state 57 on LBRACKET, state 126 on DOT + +43. Tokens (17): LIDENT UIDENT EQUAL AND FALSE LPAREN RPAREN QSTNQSTN LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = & false ( ) ?? length $ length <= @ length $ length + Conflict origins: state 126 on LPAREN, state 129 on QSTNQSTN, state 131 on LESSEQ + +44. Tokens (17): LIDENT UIDENT EQUAL AND UIDENT LPAREN RPAREN QSTNQSTN LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = & Int ( ) ?? length $ length <= @ length $ length + Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 121 on LESSEQ + +45. Tokens (17): LIDENT UIDENT EQUAL AND UIDENT LPAREN RPAREN THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = & Int ( ) => length $ length <= @ length $ length + Conflict origins: state 80 on LPAREN, state 571 on LESSEQ + +46. Tokens (17): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false ( ) ? => length $ length <= @ length $ length + Conflict origins: state 126 on LPAREN, state 129 on QSTNMARK, state 571 on LESSEQ + +47. Tokens (17): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNQSTN AND LIDENT DOLLAR LIDENT EQEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false ( ) ?? & length $ length == @ length $ length + Conflict origins: state 126 on LPAREN, state 129 on QSTNQSTN, state 131 on EQEQ + +48. Tokens (17): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = Int ( ) ? => length $ length <= @ length $ length + Conflict origins: state 80 on LPAREN, state 119 on QSTNMARK, state 571 on LESSEQ + +49. Tokens (17): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNQSTN AND LIDENT DOLLAR LIDENT EQEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = Int ( ) ?? & length $ length == @ length $ length + Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 121 on EQEQ + +50. Tokens (17): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN THICK_ARROW AND LIDENT DOLLAR LIDENT EQEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = Int ( ) => & length $ length == @ length $ length + Conflict origins: state 80 on LPAREN, state 571 on EQEQ + +Explored 6298445 frontiers (6417598 unique); 65028 conflict seeds. +Search stopped because one or more workers reached a search limit. From 46ff1fd583148da91b20938c3fac258fe4723706 Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Wed, 22 Jul 2026 23:14:43 +0200 Subject: [PATCH 145/154] Fix call and verb-type precedence --- lib/cst/nodes.ml | 2 ++ lib/cst/parser.mly | 71 ++++++++++++++++++++++++++----------- lib/cst/to_tree_graph.ml | 2 ++ tools/syntax_experiments.py | 4 +-- 4 files changed, 57 insertions(+), 22 deletions(-) diff --git a/lib/cst/nodes.ml b/lib/cst/nodes.ml index e5d37af4..9ef13cbd 100644 --- a/lib/cst/nodes.ml +++ b/lib/cst/nodes.ml @@ -135,6 +135,7 @@ and Type_expr : sig type t = | Path of { name : Name_type.t; generics : Generic_arg.t list } | Verb of Verb_type.t + | Parenthesized of t end = Type_expr and Param_type : sig @@ -195,6 +196,7 @@ and Ret_type : sig type t = | Safe of Type_expr.t | Abort of { ok : Type_expr.t; abort : Type_expr.t } + | Parenthesized of t end = Ret_type and Func_lambda : sig diff --git a/lib/cst/parser.mly b/lib/cst/parser.mly index 601cef46..f5200b0c 100644 --- a/lib/cst/parser.mly +++ b/lib/cst/parser.mly @@ -62,7 +62,9 @@ %nonassoc EQEQ LESSEQ MOREEQ LESS MORE /* comparisons */ %left PLUS MINUS %left STAR SLASH +%left DOT /* field access */ %nonassoc TILDE AND /* prefix ~ and & */ +%left LPAREN /* function application */ %start package @@ -110,12 +112,46 @@ package: generics } -type_expr: +%inline type_atom: | name=name_type generics=loption(generics) { Nodes.Type_expr.Path { name; generics } } - | verb_type=verb_type { - Nodes.Type_expr.Verb verb_type + | "(" type_=type_expr ")" { + Nodes.Type_expr.Parenthesized type_ + } + +%inline verb_type_suffix: + | "[" params=separated_list(",", param_type) "]" { + fun ret_type -> + Nodes.Type_expr.Verb (Nodes.Verb_type.Func { params; ret_type }) + } + | "[" THIS this_type=type_expr + params=loption(preceded(",", separated_nonempty_list(",", param_type))) + "]" is_mut=boption(MUT) { + fun ret_type -> + Nodes.Type_expr.Verb (Nodes.Verb_type.Meth { + this_type; + params; + ret_type; + is_mut; + }) + } + +(* Verb-type brackets bind more tightly than an unparenthesized abort return: + `Int ? Error[]` is `Int ? (Error[])`. To make the abort return feed the + verb type instead, group it explicitly: `(Int ? Error)[]`. *) +type_expr: + | atom=type_atom suffixes=list(verb_type_suffix) { + List.fold_left + (fun type_ suffix -> suffix (Nodes.Ret_type.Safe type_)) + atom suffixes + } + | "(" ret_type=abort_ret_type ")" + first=verb_type_suffix rest=list(verb_type_suffix) { + let type_ = first (Nodes.Ret_type.Parenthesized ret_type) in + List.fold_left + (fun type_ suffix -> suffix (Nodes.Ret_type.Safe type_)) + type_ rest } %inline generic_param: @@ -249,12 +285,13 @@ primary: | func_lambda=func_lambda { Nodes.Expr.FuncLambda func_lambda } | meth_lambda=meth_lambda { Nodes.Expr.MethLambda meth_lambda } -(* postfix chain: calls, method calls, field access. binds tighter than the - binary operators, so `a!b(c) * d(e)` is `(a!b(c)) * (d(e))`, unambiguously. *) +(* Calls bind tighter than prefix operators, while field access binds just + below them. Thus `~value().field` is `(~value()).field`. Both remain tighter + than binary operators, so `a!b(c) * d(e)` is `(a!b(c)) * (d(e))`. *) app: | primary=primary { primary } | verb_call=verb_call { Nodes.Expr.VerbCall verb_call } - | target=app "." field=LIDENT { + | target=expr "." field=LIDENT { Nodes.Expr.DotAccess { target; field } } @@ -311,10 +348,15 @@ expr: Nodes.Type_or_moulded.Moulded moulded } -%inline ret_type: +ret_type: | ret_type=type_expr { Nodes.Ret_type.Safe ret_type } + | ret_type=abort_ret_type { + ret_type + } + +abort_ret_type: | ok=type_expr "?" abort=type_expr { Nodes.Ret_type.Abort { ok; abort } } @@ -348,13 +390,13 @@ body: part. no method part => function call; a method part => method call, with the receiver as `this` and the (primary) name as the callee. *) verb_call: - | receiver=app part=ioption(meth_part) "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) { + | receiver=app part=ioption(meth_part) "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) %prec LPAREN { match part with | None -> Nodes.Verb_call.Func { callee = receiver; args; abort_handle } | Some (is_mut, name) -> Nodes.Verb_call.Meth { this = receiver; callee = name; args; abort_handle; is_mut } } - | name_type=name_type "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) { + | name_type=name_type "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) %prec LPAREN { Nodes.Verb_call.Constructor { name_type; args; abort_handle } } @@ -422,14 +464,3 @@ stat: | name=UIDENT { Nodes.Name_type.Ident name } | pkg=LIDENT "$" name=UIDENT { Nodes.Name_type.Qualified { package = pkg; ident = name } } | "@" pkg=LIDENT "$" name=UIDENT { Nodes.Name_type.Intrinsic { package = pkg; ident = name } } - -%inline verb_type: - | ret=ret_type "[" params=separated_list(",", param_type) "]" { - Nodes.Verb_type.Func { params; ret_type = ret } - } - | ret=ret_type "[" THIS this_type=type_expr - params=loption(preceded(",", separated_nonempty_list(",", param_type))) - "]" is_mut=boption(MUT) { - Nodes.Verb_type.Meth { this_type; params; ret_type = ret; is_mut } - } - diff --git a/lib/cst/to_tree_graph.ml b/lib/cst/to_tree_graph.ml index 00ed3af7..3063ac45 100644 --- a/lib/cst/to_tree_graph.ml +++ b/lib/cst/to_tree_graph.ml @@ -74,6 +74,7 @@ and generic_arg_to_node (x: Nodes.Generic_arg.t) = match x with and type_to_node (x: Nodes.Type_expr.t) = match x with | Verb x -> verb_type_to_node x + | Parenthesized x -> group "parenthesized" (type_to_node x) | Path { name; generics } -> fields [ ("qualifier", name_type_to_node name); @@ -223,6 +224,7 @@ and ret_to_node (x: Nodes.Ret_type.t) = match x with ("safe_type", type_to_node ok); ("abort_type", type_to_node abort); ] + | Parenthesized ret -> group "parenthesized" (ret_to_node ret) and func_lambda_to_node (x: Nodes.Func_lambda.t) = fields [ diff --git a/tools/syntax_experiments.py b/tools/syntax_experiments.py index 6d334ccb..7f898bbd 100644 --- a/tools/syntax_experiments.py +++ b/tools/syntax_experiments.py @@ -197,13 +197,13 @@ def spell_named_call_statement(spelling: Spelling) -> list[str] | None: PRIMARY_GROUP = ' | "(" e=expr ")" { Nodes.Expr.Parenthized e }\n' VERB_CALL = '''verb_call: - | receiver=app part=ioption(meth_part) "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) { + | receiver=app part=ioption(meth_part) "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) %prec LPAREN { match part with | None -> Nodes.Verb_call.Func { callee = receiver; args; abort_handle } | Some (is_mut, name) -> Nodes.Verb_call.Meth { this = receiver; callee = name; args; abort_handle; is_mut } } - | name_type=name_type "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) { + | name_type=name_type "(" args=separated_list(COMMA, expr) ")" abort_handle=ioption(abort_handle) %prec LPAREN { Nodes.Verb_call.Constructor { name_type; args; abort_handle } } ''' From 2cba02173d6f17482546cef652ae4596f4a9156e Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Wed, 22 Jul 2026 23:25:04 +0200 Subject: [PATCH 146/154] update --- .gitignore | 1 + ambiguity-report.txt | 251 ++++++++++++++++++++++--------------------- justfile | 2 +- 3 files changed, 128 insertions(+), 126 deletions(-) diff --git a/.gitignore b/.gitignore index bf49ceef..030d471b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ parser/ vcpkg_installed/ __pycache__/ .devbox/ +*.term diff --git a/ambiguity-report.txt b/ambiguity-report.txt index d3bcbbc8..5e7b1b12 100644 --- a/ambiguity-report.txt +++ b/ambiguity-report.txt @@ -1,204 +1,205 @@ +Welcome to devbox! Found 50 complete ambiguity families. 1. Tokens (9): LIDENT UIDENT EQUAL TILDE TILDE FALSE QSTNQSTN FALSE EOF Source: length Int = ~ ~ false ?? false - Conflict origins: state 564 on QSTNQSTN + Conflict origins: state 496 on QSTNQSTN 2. Tokens (10): LIDENT UIDENT EQUAL FALSE EQEQ TILDE FALSE QSTNQSTN FALSE EOF Source: length Int = false == ~ false ?? false - Conflict origins: state 189 on QSTNQSTN, state 564 on QSTNQSTN + Conflict origins: state 214 on QSTNQSTN, state 496 on QSTNQSTN 3. Tokens (10): LIDENT UIDENT EQUAL FALSE LESS TILDE FALSE QSTNQSTN FALSE EOF Source: length Int = false < ~ false ?? false - Conflict origins: state 181 on QSTNQSTN, state 564 on QSTNQSTN + Conflict origins: state 206 on QSTNQSTN, state 496 on QSTNQSTN 4. Tokens (10): LIDENT UIDENT EQUAL FALSE LESSEQ TILDE FALSE QSTNQSTN FALSE EOF Source: length Int = false <= ~ false ?? false - Conflict origins: state 173 on QSTNQSTN, state 564 on QSTNQSTN + Conflict origins: state 198 on QSTNQSTN, state 496 on QSTNQSTN 5. Tokens (10): LIDENT UIDENT EQUAL FALSE MINUS TILDE FALSE QSTNQSTN FALSE EOF Source: length Int = false - ~ false ?? false - Conflict origins: state 153 on QSTNQSTN, state 564 on QSTNQSTN + Conflict origins: state 178 on QSTNQSTN, state 496 on QSTNQSTN 6. Tokens (10): LIDENT UIDENT EQUAL FALSE MORE TILDE FALSE QSTNQSTN FALSE EOF Source: length Int = false > ~ false ?? false - Conflict origins: state 165 on QSTNQSTN, state 564 on QSTNQSTN + Conflict origins: state 190 on QSTNQSTN, state 496 on QSTNQSTN 7. Tokens (10): LIDENT UIDENT EQUAL FALSE MOREEQ TILDE FALSE QSTNQSTN FALSE EOF Source: length Int = false >= ~ false ?? false - Conflict origins: state 149 on QSTNQSTN, state 564 on QSTNQSTN + Conflict origins: state 174 on QSTNQSTN, state 496 on QSTNQSTN 8. Tokens (10): LIDENT UIDENT EQUAL FALSE PLUS TILDE FALSE QSTNQSTN FALSE EOF Source: length Int = false + ~ false ?? false - Conflict origins: state 141 on QSTNQSTN, state 564 on QSTNQSTN + Conflict origins: state 166 on QSTNQSTN, state 496 on QSTNQSTN 9. Tokens (10): LIDENT UIDENT EQUAL FALSE SLASH TILDE FALSE QSTNQSTN FALSE EOF Source: length Int = false / ~ false ?? false - Conflict origins: state 133 on QSTNQSTN, state 564 on QSTNQSTN + Conflict origins: state 158 on QSTNQSTN, state 496 on QSTNQSTN 10. Tokens (10): LIDENT UIDENT EQUAL FALSE STAR TILDE FALSE QSTNQSTN FALSE EOF Source: length Int = false * ~ false ?? false - Conflict origins: state 123 on QSTNQSTN, state 564 on QSTNQSTN + Conflict origins: state 148 on QSTNQSTN, state 496 on QSTNQSTN 11. Tokens (10): LIDENT UIDENT EQUAL TILDE FALSE LPAREN RPAREN QSTNQSTN FALSE EOF Source: length Int = ~ false ( ) ?? false - Conflict origins: state 126 on LPAREN, state 129 on QSTNQSTN, state 564 on QSTNQSTN + Conflict origins: state 135 on LPAREN, state 138 on QSTNQSTN, state 496 on QSTNQSTN 12. Tokens (10): LIDENT UIDENT EQUAL TILDE TILDE FALSE QSTNMARK LCURLY RCURLY EOF Source: length Int = ~ ~ false ? { } - Conflict origins: state 564 on QSTNMARK + Conflict origins: state 496 on QSTNMARK 13. Tokens (10): LIDENT UIDENT EQUAL TILDE UIDENT LPAREN RPAREN QSTNQSTN FALSE EOF Source: length Int = ~ Int ( ) ?? false - Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 564 on QSTNQSTN + Conflict origins: state 93 on LPAREN, state 132 on QSTNQSTN, state 496 on QSTNQSTN -14. Tokens (10): LIDENT UIDENT LPAREN TILDE TILDE FALSE QSTNQSTN FALSE RPAREN EOF - Source: length Int ( ~ ~ false ?? false ) - Conflict origins: state 311 on LPAREN, state 564 on QSTNQSTN +14. Tokens (11): LIDENT UIDENT EQUAL TILDE FALSE QSTNMARK THICK_ARROW FALSE DOT LIDENT EOF + Source: length Int = ~ false ? => false . length + Conflict origins: state 496 on QSTNMARK, state 503 on DOT -15. Tokens (11): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNQSTN FALSE DOT LIDENT EOF - Source: length Int = false ( ) ?? false . length - Conflict origins: state 126 on DOT, state 126 on LPAREN, state 129 on QSTNQSTN +15. Tokens (11): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN THICK_ARROW FALSE DOT LIDENT EOF + Source: length Int = Int ( ) => false . length + Conflict origins: state 93 on LPAREN, state 503 on DOT -16. Tokens (11): LIDENT UIDENT EQUAL TILDE TILDE FALSE QSTNQSTN FALSE DOT LIDENT EOF - Source: length Int = ~ ~ false ?? false . length - Conflict origins: state 126 on DOT, state 564 on QSTNQSTN +16. Tokens (12): LIDENT UIDENT EQUAL FALSE EQEQ FALSE QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = false == false ? => 8.647 . length + Conflict origins: state 214 on QSTNMARK, state 503 on DOT -17. Tokens (11): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNQSTN FALSE DOT LIDENT EOF - Source: length Int = Int ( ) ?? false . length - Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 126 on DOT +17. Tokens (12): LIDENT UIDENT EQUAL FALSE LESS FALSE QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = false < false ? => 8.647 . length + Conflict origins: state 206 on QSTNMARK, state 503 on DOT -18. Tokens (11): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN THICK_ARROW FALSE DOT LIDENT EOF - Source: length Int = Int ( ) => false . length - Conflict origins: state 80 on LPAREN, state 126 on DOT +18. Tokens (12): LIDENT UIDENT EQUAL FALSE LESSEQ FALSE QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = false <= false ? => 8.647 . length + Conflict origins: state 198 on QSTNMARK, state 503 on DOT -19. Tokens (11): LIDENT UIDENT QSTNMARK UIDENT LBRACKET RBRACKET LPAREN RPAREN LCURLY RCURLY EOF - Source: length Int ? Int [ ] ( ) { } - Conflict origins: state 57 on LPAREN +19. Tokens (12): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = false ( ) ? => 8.647 . length + Conflict origins: state 135 on LPAREN, state 138 on QSTNMARK, state 503 on DOT -20. Tokens (11): LTYPE UIDENT EQUAL UIDENT QSTNMARK UIDENT LBRACKET RBRACKET LBRACKET RBRACKET EOF - Source: type Int = Int ? Int [ ] [ ] - Conflict origins: state 57 on LBRACKET +20. Tokens (12): LIDENT UIDENT EQUAL FALSE MINUS FALSE QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = false - false ? => 8.647 . length + Conflict origins: state 178 on QSTNMARK, state 503 on DOT -21. Tokens (12): LIDENT UIDENT EQUAL FALSE EQEQ TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF - Source: length Int = false == ~ false ?? "john" . length - Conflict origins: state 126 on DOT, state 189 on QSTNQSTN, state 564 on QSTNQSTN +21. Tokens (12): LIDENT UIDENT EQUAL FALSE MORE FALSE QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = false > false ? => 8.647 . length + Conflict origins: state 190 on QSTNMARK, state 503 on DOT -22. Tokens (12): LIDENT UIDENT EQUAL FALSE LESS TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF - Source: length Int = false < ~ false ?? "john" . length - Conflict origins: state 126 on DOT, state 181 on QSTNQSTN, state 564 on QSTNQSTN +22. Tokens (12): LIDENT UIDENT EQUAL FALSE MOREEQ FALSE QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = false >= false ? => 8.647 . length + Conflict origins: state 174 on QSTNMARK, state 503 on DOT -23. Tokens (12): LIDENT UIDENT EQUAL FALSE LESSEQ TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF - Source: length Int = false <= ~ false ?? "john" . length - Conflict origins: state 126 on DOT, state 173 on QSTNQSTN, state 564 on QSTNQSTN +23. Tokens (12): LIDENT UIDENT EQUAL FALSE PLUS FALSE QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = false + false ? => 8.647 . length + Conflict origins: state 166 on QSTNMARK, state 503 on DOT -24. Tokens (12): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF - Source: length Int = false ( ) ? => 8.647 . length - Conflict origins: state 126 on DOT, state 126 on LPAREN, state 129 on QSTNMARK +24. Tokens (12): LIDENT UIDENT EQUAL FALSE SLASH FALSE QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = false / false ? => 8.647 . length + Conflict origins: state 158 on QSTNMARK, state 503 on DOT -25. Tokens (12): LIDENT UIDENT EQUAL FALSE MINUS TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF - Source: length Int = false - ~ false ?? "john" . length - Conflict origins: state 126 on DOT, state 153 on QSTNQSTN, state 564 on QSTNQSTN +25. Tokens (12): LIDENT UIDENT EQUAL FALSE STAR FALSE QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = false * false ? => 8.647 . length + Conflict origins: state 148 on QSTNMARK, state 503 on DOT -26. Tokens (12): LIDENT UIDENT EQUAL FALSE MORE TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF - Source: length Int = false > ~ false ?? "john" . length - Conflict origins: state 126 on DOT, state 165 on QSTNQSTN, state 564 on QSTNQSTN +26. Tokens (12): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF + Source: length Int = Int ( ) ? => 8.647 . length + Conflict origins: state 93 on LPAREN, state 132 on QSTNMARK, state 503 on DOT -27. Tokens (12): LIDENT UIDENT EQUAL FALSE MOREEQ TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF - Source: length Int = false >= ~ false ?? "john" . length - Conflict origins: state 126 on DOT, state 149 on QSTNQSTN, state 564 on QSTNQSTN +27. Tokens (13): LIDENT UIDENT LPAREN AND TILDE TILDE FALSE QSTNQSTN LIDENT DOLLAR LIDENT RPAREN EOF + Source: length Int ( & ~ ~ false ?? length $ length ) + Conflict origins: state 325 on LPAREN, state 496 on QSTNQSTN -28. Tokens (12): LIDENT UIDENT EQUAL FALSE PLUS TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF - Source: length Int = false + ~ false ?? "john" . length - Conflict origins: state 126 on DOT, state 141 on QSTNQSTN, state 564 on QSTNQSTN +28. Tokens (13): UIDENT PLUS LPAREN RPAREN THICK_ARROW TILDE TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF + Source: Int + ( ) => ~ ~ false ?? "john" . length + Conflict origins: state 496 on QSTNQSTN, state 503 on DOT -29. Tokens (12): LIDENT UIDENT EQUAL FALSE SLASH TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF - Source: length Int = false / ~ false ?? "john" . length - Conflict origins: state 126 on DOT, state 133 on QSTNQSTN, state 564 on QSTNQSTN +29. Tokens (16): LIDENT UIDENT EQUAL TILDE FALSE QSTNMARK THICK_ARROW FALSE LESS AND AND AT LIDENT DOLLAR LIDENT EOF + Source: length Int = ~ false ? => false < & & @ length $ length + Conflict origins: state 496 on QSTNMARK, state 503 on LESS -30. Tokens (12): LIDENT UIDENT EQUAL FALSE STAR TILDE FALSE QSTNQSTN STRING DOT LIDENT EOF - Source: length Int = false * ~ false ?? "john" . length - Conflict origins: state 123 on QSTNQSTN, state 126 on DOT, state 564 on QSTNQSTN +30. Tokens (16): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN THICK_ARROW FALSE LESS AND AND AT LIDENT DOLLAR LIDENT EOF + Source: length Int = Int ( ) => false < & & @ length $ length + Conflict origins: state 93 on LPAREN, state 503 on LESS -31. Tokens (12): LIDENT UIDENT EQUAL TILDE FALSE LPAREN RPAREN QSTNQSTN STRING DOT LIDENT EOF - Source: length Int = ~ false ( ) ?? "john" . length - Conflict origins: state 126 on DOT, state 126 on LPAREN, state 129 on QSTNQSTN, state 564 on QSTNQSTN +31. Tokens (17): LIDENT UIDENT EQUAL FALSE EQEQ FALSE QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false == false ? => length $ length <= @ length $ length + Conflict origins: state 214 on QSTNMARK, state 503 on LESSEQ -32. Tokens (12): LIDENT UIDENT EQUAL TILDE TILDE FALSE QSTNMARK THICK_ARROW STRING DOT LIDENT EOF - Source: length Int = ~ ~ false ? => "john" . length - Conflict origins: state 126 on DOT, state 564 on QSTNMARK +32. Tokens (17): LIDENT UIDENT EQUAL FALSE LESS FALSE QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false < false ? => length $ length <= @ length $ length + Conflict origins: state 206 on QSTNMARK, state 503 on LESSEQ -33. Tokens (12): LIDENT UIDENT EQUAL TILDE UIDENT LPAREN RPAREN QSTNQSTN STRING DOT LIDENT EOF - Source: length Int = ~ Int ( ) ?? "john" . length - Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 126 on DOT, state 564 on QSTNQSTN +33. Tokens (17): LIDENT UIDENT EQUAL FALSE LESSEQ FALSE QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false <= false ? => length $ length <= @ length $ length + Conflict origins: state 198 on QSTNMARK, state 503 on LESSEQ -34. Tokens (12): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNMARK THICK_ARROW FLOAT DOT LIDENT EOF - Source: length Int = Int ( ) ? => 8.647 . length - Conflict origins: state 80 on LPAREN, state 119 on QSTNMARK, state 126 on DOT +34. Tokens (17): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false ( ) ? => length $ length <= @ length $ length + Conflict origins: state 135 on LPAREN, state 138 on QSTNMARK, state 503 on LESSEQ -35. Tokens (13): LIDENT UIDENT LPAREN FALSE EQEQ TILDE FALSE QSTNQSTN LIDENT DOLLAR LIDENT RPAREN EOF - Source: length Int ( false == ~ false ?? length $ length ) - Conflict origins: state 189 on QSTNQSTN, state 311 on LPAREN, state 564 on QSTNQSTN +35. Tokens (17): LIDENT UIDENT EQUAL FALSE MINUS FALSE QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false - false ? => length $ length <= @ length $ length + Conflict origins: state 178 on QSTNMARK, state 503 on LESSEQ -36. Tokens (13): LIDENT UIDENT QSTNMARK UIDENT LBRACKET RBRACKET LPAREN RPAREN THICK_ARROW STRING DOT LIDENT EOF - Source: length Int ? Int [ ] ( ) => "john" . length - Conflict origins: state 57 on LPAREN, state 126 on DOT +36. Tokens (17): LIDENT UIDENT EQUAL FALSE MORE FALSE QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false > false ? => length $ length <= @ length $ length + Conflict origins: state 190 on QSTNMARK, state 503 on LESSEQ -37. Tokens (15): LIDENT UIDENT EQUAL TILDE FALSE QSTNMARK THICK_ARROW FALSE EQEQ AND AT LIDENT DOLLAR LIDENT EOF - Source: length Int = ~ false ? => false == & @ length $ length - Conflict origins: state 564 on QSTNMARK, state 571 on EQEQ +37. Tokens (17): LIDENT UIDENT EQUAL FALSE MOREEQ FALSE QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false >= false ? => length $ length <= @ length $ length + Conflict origins: state 174 on QSTNMARK, state 503 on LESSEQ -38. Tokens (16): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNQSTN FALSE LESS AND AND AT LIDENT DOLLAR LIDENT EOF - Source: length Int = false ( ) ?? false < & & @ length $ length - Conflict origins: state 126 on LPAREN, state 129 on QSTNQSTN, state 131 on LESS +38. Tokens (17): LIDENT UIDENT EQUAL FALSE PLUS FALSE QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false + false ? => length $ length <= @ length $ length + Conflict origins: state 166 on QSTNMARK, state 503 on LESSEQ -39. Tokens (16): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNQSTN FALSE LESS AND AND AT LIDENT DOLLAR LIDENT EOF - Source: length Int = Int ( ) ?? false < & & @ length $ length - Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 121 on LESS +39. Tokens (17): LIDENT UIDENT EQUAL FALSE SLASH FALSE QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false / false ? => length $ length <= @ length $ length + Conflict origins: state 158 on QSTNMARK, state 503 on LESSEQ -40. Tokens (16): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN THICK_ARROW FALSE LESS AND AND AT LIDENT DOLLAR LIDENT EOF - Source: length Int = Int ( ) => false < & & @ length $ length - Conflict origins: state 80 on LPAREN, state 571 on LESS +40. Tokens (17): LIDENT UIDENT EQUAL FALSE STAR FALSE QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = false * false ? => length $ length <= @ length $ length + Conflict origins: state 148 on QSTNMARK, state 503 on LESSEQ -41. Tokens (16): LIDENT UIDENT LPAREN AND TILDE TILDE FALSE QSTNQSTN AT LIDENT DOLLAR LIDENT DOT LIDENT RPAREN EOF - Source: length Int ( & ~ ~ false ?? @ length $ length . length ) - Conflict origins: state 126 on DOT, state 311 on LPAREN, state 564 on QSTNQSTN +41. Tokens (17): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: length Int = Int ( ) ? => length $ length <= @ length $ length + Conflict origins: state 93 on LPAREN, state 132 on QSTNMARK, state 503 on LESSEQ -42. Tokens (16): LIDENT UIDENT QSTNMARK UIDENT LBRACKET RBRACKET LBRACKET RBRACKET EQUAL AT LIDENT DOLLAR LIDENT DOT LIDENT EOF - Source: length Int ? Int [ ] [ ] = @ length $ length . length - Conflict origins: state 57 on LBRACKET, state 126 on DOT +42. Tokens (17): UIDENT LPAREN RPAREN THICK_ARROW TILDE FALSE QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: Int ( ) => ~ false ? => length $ length <= @ length $ length + Conflict origins: state 496 on QSTNMARK, state 503 on LESSEQ -43. Tokens (17): LIDENT UIDENT EQUAL AND FALSE LPAREN RPAREN QSTNQSTN LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF - Source: length Int = & false ( ) ?? length $ length <= @ length $ length - Conflict origins: state 126 on LPAREN, state 129 on QSTNQSTN, state 131 on LESSEQ +43. Tokens (17): UIDENT LPAREN RPAREN THICK_ARROW UIDENT LPAREN RPAREN THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF + Source: Int ( ) => Int ( ) => length $ length <= @ length $ length + Conflict origins: state 93 on LPAREN, state 503 on LESSEQ -44. Tokens (17): LIDENT UIDENT EQUAL AND UIDENT LPAREN RPAREN QSTNQSTN LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF - Source: length Int = & Int ( ) ?? length $ length <= @ length $ length - Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 121 on LESSEQ +44. Tokens (19): UIDENT LPAREN RPAREN THICK_ARROW FALSE EQEQ FALSE SLASH FLOAT DOT LIDENT QSTNQSTN AND AND AT LIDENT DOLLAR LIDENT EOF + Source: Int ( ) => false == false / 8.647 . length ?? & & @ length $ length + Conflict origins: state 158 on QSTNQSTN, state 214 on QSTNQSTN, state 503 on EQEQ -45. Tokens (17): LIDENT UIDENT EQUAL AND UIDENT LPAREN RPAREN THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF - Source: length Int = & Int ( ) => length $ length <= @ length $ length - Conflict origins: state 80 on LPAREN, state 571 on LESSEQ +45. Tokens (19): UIDENT LPAREN RPAREN THICK_ARROW FALSE EQEQ FALSE STAR FLOAT DOT LIDENT QSTNQSTN AND AND AT LIDENT DOLLAR LIDENT EOF + Source: Int ( ) => false == false * 8.647 . length ?? & & @ length $ length + Conflict origins: state 148 on QSTNQSTN, state 214 on QSTNQSTN, state 503 on EQEQ -46. Tokens (17): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF - Source: length Int = false ( ) ? => length $ length <= @ length $ length - Conflict origins: state 126 on LPAREN, state 129 on QSTNMARK, state 571 on LESSEQ +46. Tokens (19): UIDENT LPAREN RPAREN THICK_ARROW FALSE LESS FALSE SLASH FLOAT DOT LIDENT QSTNQSTN AND AND AT LIDENT DOLLAR LIDENT EOF + Source: Int ( ) => false < false / 8.647 . length ?? & & @ length $ length + Conflict origins: state 158 on QSTNQSTN, state 206 on QSTNQSTN, state 503 on LESS -47. Tokens (17): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNQSTN AND LIDENT DOLLAR LIDENT EQEQ AT LIDENT DOLLAR LIDENT EOF - Source: length Int = false ( ) ?? & length $ length == @ length $ length - Conflict origins: state 126 on LPAREN, state 129 on QSTNQSTN, state 131 on EQEQ +47. Tokens (19): UIDENT LPAREN RPAREN THICK_ARROW FALSE LESS FALSE STAR FLOAT DOT LIDENT QSTNQSTN AND AND AT LIDENT DOLLAR LIDENT EOF + Source: Int ( ) => false < false * 8.647 . length ?? & & @ length $ length + Conflict origins: state 148 on QSTNQSTN, state 206 on QSTNQSTN, state 503 on LESS -48. Tokens (17): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNMARK THICK_ARROW LIDENT DOLLAR LIDENT LESSEQ AT LIDENT DOLLAR LIDENT EOF - Source: length Int = Int ( ) ? => length $ length <= @ length $ length - Conflict origins: state 80 on LPAREN, state 119 on QSTNMARK, state 571 on LESSEQ +48. Tokens (19): UIDENT LPAREN RPAREN THICK_ARROW FALSE LESSEQ FALSE SLASH FLOAT DOT LIDENT QSTNQSTN AND AND AT LIDENT DOLLAR LIDENT EOF + Source: Int ( ) => false <= false / 8.647 . length ?? & & @ length $ length + Conflict origins: state 158 on QSTNQSTN, state 198 on QSTNQSTN, state 503 on LESSEQ -49. Tokens (17): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN QSTNQSTN AND LIDENT DOLLAR LIDENT EQEQ AT LIDENT DOLLAR LIDENT EOF - Source: length Int = Int ( ) ?? & length $ length == @ length $ length - Conflict origins: state 80 on LPAREN, state 119 on QSTNQSTN, state 121 on EQEQ +49. Tokens (19): UIDENT LPAREN RPAREN THICK_ARROW FALSE LESSEQ FALSE STAR FLOAT DOT LIDENT QSTNQSTN AND AND AT LIDENT DOLLAR LIDENT EOF + Source: Int ( ) => false <= false * 8.647 . length ?? & & @ length $ length + Conflict origins: state 148 on QSTNQSTN, state 198 on QSTNQSTN, state 503 on LESSEQ -50. Tokens (17): LIDENT UIDENT EQUAL UIDENT LPAREN RPAREN THICK_ARROW AND LIDENT DOLLAR LIDENT EQEQ AT LIDENT DOLLAR LIDENT EOF - Source: length Int = Int ( ) => & length $ length == @ length $ length - Conflict origins: state 80 on LPAREN, state 571 on EQEQ +50. Tokens (19): UIDENT LPAREN RPAREN THICK_ARROW FALSE MINUS FALSE SLASH FLOAT DOT LIDENT QSTNQSTN AND AND AT LIDENT DOLLAR LIDENT EOF + Source: Int ( ) => false - false / 8.647 . length ?? & & @ length $ length + Conflict origins: state 158 on QSTNQSTN, state 178 on QSTNQSTN, state 503 on MINUS -Explored 6298445 frontiers (6417598 unique); 65028 conflict seeds. +Explored 10029149 frontiers (10028786 unique); 65138 conflict seeds. Search stopped because one or more workers reached a search limit. diff --git a/justfile b/justfile index e5bb5feb..9a7a7954 100644 --- a/justfile +++ b/justfile @@ -20,7 +20,7 @@ conflicts: menhir {{ grammarFile }} --random-sentence-concrete package --random-seed 1 --random-sentence-length 16 # Find a short complete ambiguity within a bounded, parallel GLR search. -ambiguities max_tokens="20" timeout="60" max_frontiers="500000" jobs="4" max_witnesses="20" menhir="menhir" max_queue="0": +ambiguities max_tokens="50" timeout="1800" max_frontiers="60000" jobs="4" max_witnesses="50" menhir="menhir" max_queue="60000": dune exec tools/ambiguity_search.exe -- {{ grammarFile }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --jobs {{ jobs }} --max-witnesses {{ max_witnesses }} --max-queue {{ max_queue }} # Conservative unambiguity proof attempt: exit 0 proven, 1 ambiguous, 3 not proven. From 8d78591c893aec55564dd0922b225e229fbb784c Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Thu, 23 Jul 2026 00:58:36 +0200 Subject: [PATCH 147/154] Simplify ambiguity tooling configuration (#43) * Simplify ambiguity tooling configuration * Reserve just for parameterless commands * Read machine settings from the environment * Use one ambiguity tool for proof mode * Require explicit ambiguity configuration * Keep ambiguity search within its memory budget * Keep memory pressure within a narrow plateau * add new run --- .gitignore | 1 + README.md | 31 ++- ...guity-report.txt => ambiguities-report.txt | 0 dev/bin/ambiguities | 11 + dev/bin/compiler | 6 + dev/bin/grammar-conflicts | 12 + dev/bin/grammar-stats | 11 + dev/bin/syntax-experiments | 12 + dev/lib/ambiguity-config.sh | 21 ++ devbox.json | 1 + docs/ambiguity.md | 65 +++-- enter | 12 + justfile | 32 --- machine-config.example | 6 + new-ambiguities-report.txt | 205 ++++++++++++++ tools/ambiguity_search.ml | 251 ++++++++++++++---- tools/syntax_experiments.py | 93 +++++-- 17 files changed, 644 insertions(+), 126 deletions(-) rename ambiguity-report.txt => ambiguities-report.txt (100%) create mode 100755 dev/bin/ambiguities create mode 100755 dev/bin/compiler create mode 100755 dev/bin/grammar-conflicts create mode 100755 dev/bin/grammar-stats create mode 100755 dev/bin/syntax-experiments create mode 100644 dev/lib/ambiguity-config.sh create mode 100755 enter create mode 100644 machine-config.example create mode 100644 new-ambiguities-report.txt diff --git a/.gitignore b/.gitignore index 030d471b..d4c3f0dc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ vcpkg_installed/ __pycache__/ .devbox/ *.term +machine-config.txt diff --git a/README.md b/README.md index 189c347a..86602bc2 100644 --- a/README.md +++ b/README.md @@ -3,20 +3,43 @@ This repository contains the Zane language compiler and CLI. ## Setup + To setup this project in a new environment or sandbox, run: ```sh curl -fsSL https://get.jetify.com/devbox | bash ``` +Then enter the project development shell: + +```sh +./enter +``` + +The shell provides the project toolchain and adds `dev/bin` to `PATH`. Product +executable sources remain under `bin/`, while development-only command wrappers +live under `dev/bin/`. + ## Building ```sh -devbox shell -just init # initialize submodules, vcpkg dependencies, and meson -just build +./enter +dune build ``` ## Usage -Checkout the `justfile` for all available commands. +Common tools are available directly inside the development shell: + +```sh +compiler +ambiguities --max-tokens 100 --timeout 3600 --max-witnesses 50 +ambiguities --prove 3 --max-tokens 16 --timeout 120 --max-witnesses 20 +syntax-experiments --max-tokens 12 --timeout 15 --max-witnesses 10 +syntax-experiments --variant semicolon-separated --max-tokens 12 --timeout 15 --max-witnesses 10 +grammar-stats +grammar-conflicts +``` + +The `justfile` is reserved for parameterless project actions such as rebuilding, +watching, and running the syntax-experiment tests. diff --git a/ambiguity-report.txt b/ambiguities-report.txt similarity index 100% rename from ambiguity-report.txt rename to ambiguities-report.txt diff --git a/dev/bin/ambiguities b/dev/bin/ambiguities new file mode 100755 index 00000000..413e9dc0 --- /dev/null +++ b/dev/bin/ambiguities @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# shellcheck source=../lib/ambiguity-config.sh +. "$ROOT/dev/lib/ambiguity-config.sh" + +dune build --root "$ROOT" tools/ambiguity_search.exe +exec "$ROOT/_build/default/tools/ambiguity_search.exe" \ + "$ROOT/lib/cst/parser.mly" \ + "$@" diff --git a/dev/bin/compiler b/dev/bin/compiler new file mode 100755 index 00000000..fbb9034d --- /dev/null +++ b/dev/bin/compiler @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +cd "$ROOT" +exec dune exec bin/compiler/main.exe -- "$@" diff --git a/dev/bin/grammar-conflicts b/dev/bin/grammar-conflicts new file mode 100755 index 00000000..1c4c753f --- /dev/null +++ b/dev/bin/grammar-conflicts @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# shellcheck source=../lib/ambiguity-config.sh +. "$ROOT/dev/lib/ambiguity-config.sh" + +exec "$AMBIGUITY_MENHIR" "$ROOT/lib/cst/parser.mly" \ + --random-sentence-concrete package \ + --random-seed 1 \ + --random-sentence-length 16 \ + "$@" diff --git a/dev/bin/grammar-stats b/dev/bin/grammar-stats new file mode 100755 index 00000000..3323fe74 --- /dev/null +++ b/dev/bin/grammar-stats @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# shellcheck source=../lib/ambiguity-config.sh +. "$ROOT/dev/lib/ambiguity-config.sh" + +exec "$AMBIGUITY_MENHIR" "$ROOT/lib/cst/parser.mly" \ + --no-code-generation \ + --infer \ + "$@" diff --git a/dev/bin/syntax-experiments b/dev/bin/syntax-experiments new file mode 100755 index 00000000..0cdd7242 --- /dev/null +++ b/dev/bin/syntax-experiments @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +# shellcheck source=../lib/ambiguity-config.sh +. "$ROOT/dev/lib/ambiguity-config.sh" + +dune build --root "$ROOT" tools/ambiguity_search.exe +exec python3 "$ROOT/tools/syntax_experiments.py" \ + "$ROOT/lib/cst/parser.mly" \ + --search-command "$ROOT/_build/default/tools/ambiguity_search.exe" \ + "$@" diff --git a/dev/lib/ambiguity-config.sh b/dev/lib/ambiguity-config.sh new file mode 100644 index 00000000..392710b2 --- /dev/null +++ b/dev/lib/ambiguity-config.sh @@ -0,0 +1,21 @@ +if [[ -f "$ROOT/machine-config.txt" ]]; then + # machine-config.txt uses shell-compatible KEY=VALUE assignments. + # shellcheck source=/dev/null + . "$ROOT/machine-config.txt" +fi + +for name in \ + AMBIGUITY_MEMORY_MB \ + AMBIGUITY_MAX_FRONTIER_RATIO \ + AMBIGUITY_JOBS \ + AMBIGUITY_MENHIR; do + if [[ -z "${!name:-}" ]]; then + echo "ambiguities: $name must be set in machine-config.txt or the environment" >&2 + exit 2 + fi +done + +export AMBIGUITY_MEMORY_MB +export AMBIGUITY_MAX_FRONTIER_RATIO +export AMBIGUITY_JOBS +export AMBIGUITY_MENHIR diff --git a/devbox.json b/devbox.json index e10e822c..57494d06 100644 --- a/devbox.json +++ b/devbox.json @@ -20,6 +20,7 @@ "shell": { "init_hook": [ "echo 'Welcome to devbox!'", + "export PATH=\"$DEVBOX_PROJECT_ROOT/dev/bin:$PATH\"", "eval $(opam env)", "export LLVM_CONFIG=$(realpath $DEVBOX_PROJECT_ROOT/.devbox/nix/profile/default/bin/llvm-config)", "export LD_LIBRARY_PATH=/nix/store/s7vmxmhkq439cjb7ag9w198p6dk7kl0w-zstd-1.5.7/lib:$LD_LIBRARY_PATH" diff --git a/docs/ambiguity.md b/docs/ambiguity.md index 3ce92662..30e3f4b8 100644 --- a/docs/ambiguity.md +++ b/docs/ambiguity.md @@ -33,37 +33,62 @@ the state is triaged into one of these categories. ## Tooling -- `just ambiguities` — bounded, parallel GLR search for complete ambiguous +- `ambiguities` — bounded, parallel GLR search for complete ambiguous sentences (`tools/ambiguity_search.ml`). A completed bound is a theorem ("no ambiguous sentence of at most N tokens"), up to the astronomically unlikely collision of the 124-bit frontier digests used for - deduplication; an interrupted bound is evidence only. Two independent - per-worker budgets control the search: `--max-queue` caps the number of - queued frontiers — the search reach, and the live set that stack memory - tracks — while `--max-frontiers` sizes the evicting digest cache that - prunes redundant work (`--max-queue` defaults to `--max-frontiers`). - Together they run at roughly 2 KB per unit of resident memory; the search - itself is bounded by `--max-tokens` and `--timeout`, and a run whose queue - filled and had to drop part of the space reports itself as interrupted. + deduplication; an interrupted bound is evidence only. + `AMBIGUITY_MEMORY_MB` sets an approximate total resident-memory budget shared + by all workers. The tool derives two per-worker limits from it: a queue cap, + which controls search reach and the live stack set, and an evicting + digest-cache size, which controls deduplication. + `AMBIGUITY_MAX_FRONTIER_RATIO` is the number of digest-cache entries per + queued frontier: raising it trades queue reach for stronger deduplication, + while lowering it does the opposite. The estimate is based on + `queue * (600 + 24 * max_tokens) + cache * 240` bytes per worker. The cache + limit covers both of its generations; it is not multiplied behind the + scenes. Workers also monitor their actual OCaml heap: they compact at 80% of + their share, first release the older (purely optional) dedup generation, + stop admitting new frontiers at 90%, and resume below 85%. The remaining 10% + covers the coordinator, native allocations, and transient compaction/ + copy-on-write overhead. This keeps memory near the configured plateau while + prioritizing queue reach even when real frontiers are larger than the + estimate. The search itself is bounded by `--max-tokens` and `--timeout`, and + a run that had to drop part of the space reports itself as interrupted. Witnesses are grouped by the conflict states they traverse, which maps each finding directly onto an obligation above. -- `just prove` — conservative unambiguity prover (`--prove K`). It abstracts - GLR stacks to their top-K states and exhaustively explores pairs of - abstract parses of the same input, comparing reduction chains in lockstep. - Three verdicts: exit 0 "PROVEN UNAMBIGUOUS" is a genuine proof with no - sentence-length bound; exit 1 means a concrete ambiguous sentence was +- `ambiguities --prove K` — conservative unambiguity proof mode built into the + ambiguity search. It abstracts GLR stacks to their top-K states and + exhaustively explores pairs of abstract parses of the same input, comparing + reduction chains in lockstep. It does not depend on an external constraint + solver. Three verdicts: exit 0 "PROVEN UNAMBIGUOUS" is a genuine proof with + no sentence-length bound; exit 1 means a concrete ambiguous sentence was found; exit 3 means not proven — the abstraction reported a candidate the - bounded search could not concretize, so raise `--prove` or the search - bounds. Because unambiguity is undecidable in general, the "not proven" - verdict can never be eliminated entirely; the prover is validated against - known-ambiguous grammars, LR(1) grammars, precedence-resolved expression - grammars, and unambiguous non-LR grammars such as palindromes. -- `just syntax-experiments` — compares candidate grammar changes under + bounded search could not concretize, so raise `--prove` or the search bounds. + Because unambiguity is undecidable in general, the "not proven" verdict can + never be eliminated entirely; the prover is validated against known-ambiguous + grammars, LR(1) grammars, precedence-resolved expression grammars, and + unambiguous non-LR grammars such as palindromes. +- `syntax-experiments` — compares candidate grammar changes under equal search bounds before they are adopted (`tools/SYNTAX_EXPERIMENTS.md`). - `menhir --explain` — enumerates the conflict states that constitute the obligation ledger. +## Local machine configuration + +The ambiguity-tool executables load machine-specific values from the ignored +`machine-config.txt` file. Copy `machine-config.example` before running them. +There are no fallback values: a missing setting is an error. This keeps memory, +worker-count, and executable-path tuning out of normal command invocations and +out of version control. The file supplies `AMBIGUITY_MEMORY_MB`, +`AMBIGUITY_MAX_FRONTIER_RATIO`, `AMBIGUITY_JOBS`, and `AMBIGUITY_MENHIR` as +environment variables; they are deliberately not command-line options. + +Search intent remains on the command line. For example, +`ambiguities --max-tokens 100 --timeout 3600 --max-witnesses 50` searches +through 100 tokens for up to one hour, using the local machine budget. + ## Why this is sound Unambiguity of an arbitrary grammar admits no complete decision procedure, diff --git a/enter b/enter new file mode 100755 index 00000000..2838321c --- /dev/null +++ b/enter @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if ! command -v devbox >/dev/null 2>&1; then + echo "enter: devbox is required; install it from https://www.jetify.com/devbox" >&2 + exit 127 +fi + +cd "$ROOT" +exec devbox shell diff --git a/justfile b/justfile index 9a7a7954..57ba57f0 100644 --- a/justfile +++ b/justfile @@ -1,11 +1,6 @@ -grammarFile := "lib/cst/parser.mly" - default: just -l -run: - dune exec bin/compiler/main.exe - rebuild: dune clean dune build @@ -13,32 +8,5 @@ rebuild: watch: dune build --watch -stats: - menhir {{ grammarFile }} --no-code-generation --infer - -conflicts: - menhir {{ grammarFile }} --random-sentence-concrete package --random-seed 1 --random-sentence-length 16 - -# Find a short complete ambiguity within a bounded, parallel GLR search. -ambiguities max_tokens="50" timeout="1800" max_frontiers="60000" jobs="4" max_witnesses="50" menhir="menhir" max_queue="60000": - dune exec tools/ambiguity_search.exe -- {{ grammarFile }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --jobs {{ jobs }} --max-witnesses {{ max_witnesses }} --max-queue {{ max_queue }} - -# Conservative unambiguity proof attempt: exit 0 proven, 1 ambiguous, 3 not proven. -prove level="2" max_tokens="12" timeout="120" max_frontiers="2000000" jobs="4" menhir="menhir": - dune exec tools/ambiguity_search.exe -- {{ grammarFile }} --prove {{ level }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --jobs {{ jobs }} - -# Compare all controlled syntax variants and write Markdown/JSON reports. -syntax-experiments max_tokens="12" timeout="15" max_frontiers="150000" max_witnesses="10" jobs="4" menhir="menhir": - dune build tools/ambiguity_search.exe - python3 tools/syntax_experiments.py {{ grammarFile }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --max-witnesses {{ max_witnesses }} --jobs {{ jobs }} - -# Run one named variant, for example: just syntax-experiment semicolon-separated -syntax-experiment variant max_tokens="16" timeout="60" max_frontiers="500000" max_witnesses="20" menhir="menhir": - dune build tools/ambiguity_search.exe - python3 tools/syntax_experiments.py {{ grammarFile }} --variant {{ variant }} --menhir {{ menhir }} --max-tokens {{ max_tokens }} --timeout {{ timeout }} --max-frontiers {{ max_frontiers }} --max-witnesses {{ max_witnesses }} - -syntax-experiments-list: - python3 tools/syntax_experiments.py --list - syntax-experiments-test: python3 -m unittest tools.test_syntax_experiments -v diff --git a/machine-config.example b/machine-config.example new file mode 100644 index 00000000..f30b6ef4 --- /dev/null +++ b/machine-config.example @@ -0,0 +1,6 @@ +# Copy this file to machine-config.txt and tune it for the current machine. +# The memory budget is shared by all ambiguity-search workers. +AMBIGUITY_MEMORY_MB=512 +AMBIGUITY_MAX_FRONTIER_RATIO=1.0 +AMBIGUITY_JOBS=4 +AMBIGUITY_MENHIR=menhir diff --git a/new-ambiguities-report.txt b/new-ambiguities-report.txt new file mode 100644 index 00000000..bbcdff1b --- /dev/null +++ b/new-ambiguities-report.txt @@ -0,0 +1,205 @@ +Memory budget: 6144 MiB total across 4 worker(s); workers compact at 1229 MiB and stop admitting frontiers at 1382 MiB each (10% reserved); per-worker limits are 710564 queued frontiers and 710564 retained dedup frontiers (ratio 1). +Found 50 complete ambiguity families. + +1. Tokens (9): LIDENT UIDENT EQUAL TILDE TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = ~ ~ false ?? false + Conflict origins: state 496 on QSTNQSTN + +2. Tokens (10): LIDENT UIDENT EQUAL FALSE EQEQ TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false == ~ false ?? false + Conflict origins: state 214 on QSTNQSTN, state 496 on QSTNQSTN + +3. Tokens (10): LIDENT UIDENT EQUAL FALSE LESS TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false < ~ false ?? false + Conflict origins: state 206 on QSTNQSTN, state 496 on QSTNQSTN + +4. Tokens (10): LIDENT UIDENT EQUAL FALSE LESSEQ TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false <= ~ false ?? false + Conflict origins: state 198 on QSTNQSTN, state 496 on QSTNQSTN + +5. Tokens (10): LIDENT UIDENT EQUAL FALSE MINUS TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false - ~ false ?? false + Conflict origins: state 178 on QSTNQSTN, state 496 on QSTNQSTN + +6. Tokens (10): LIDENT UIDENT EQUAL FALSE MORE TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false > ~ false ?? false + Conflict origins: state 190 on QSTNQSTN, state 496 on QSTNQSTN + +7. Tokens (10): LIDENT UIDENT EQUAL FALSE MOREEQ TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false >= ~ false ?? false + Conflict origins: state 174 on QSTNQSTN, state 496 on QSTNQSTN + +8. Tokens (10): LIDENT UIDENT EQUAL FALSE PLUS TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false + ~ false ?? false + Conflict origins: state 166 on QSTNQSTN, state 496 on QSTNQSTN + +9. Tokens (10): LIDENT UIDENT EQUAL FALSE SLASH TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false / ~ false ?? false + Conflict origins: state 158 on QSTNQSTN, state 496 on QSTNQSTN + +10. Tokens (10): LIDENT UIDENT EQUAL FALSE STAR TILDE FALSE QSTNQSTN FALSE EOF + Source: length Int = false * ~ false ?? false + Conflict origins: state 148 on QSTNQSTN, state 496 on QSTNQSTN + +11. Tokens (10): LIDENT UIDENT EQUAL TILDE FALSE LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = ~ false ( ) ?? false + Conflict origins: state 135 on LPAREN, state 138 on QSTNQSTN, state 496 on QSTNQSTN + +12. Tokens (10): LIDENT UIDENT EQUAL TILDE TILDE FALSE QSTNMARK LCURLY RCURLY EOF + Source: length Int = ~ ~ false ? { } + Conflict origins: state 496 on QSTNMARK + +13. Tokens (10): LIDENT UIDENT EQUAL TILDE UIDENT LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = ~ Int ( ) ?? false + Conflict origins: state 93 on LPAREN, state 132 on QSTNQSTN, state 496 on QSTNQSTN + +14. Tokens (10): LIDENT UIDENT LPAREN TILDE TILDE FALSE QSTNQSTN FALSE RPAREN EOF + Source: length Int ( ~ ~ false ?? false ) + Conflict origins: state 325 on LPAREN, state 496 on QSTNQSTN + +15. Tokens (11): LIDENT UIDENT EQUAL FALSE EQEQ FALSE LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = false == false ( ) ?? false + Conflict origins: state 135 on LPAREN, state 138 on QSTNQSTN, state 214 on QSTNQSTN + +16. Tokens (11): LIDENT UIDENT EQUAL FALSE EQEQ FALSE MINUS FALSE QSTNQSTN FALSE EOF + Source: length Int = false == false - false ?? false + Conflict origins: state 178 on QSTNQSTN, state 214 on QSTNQSTN + +17. Tokens (11): LIDENT UIDENT EQUAL FALSE EQEQ FALSE PLUS FALSE QSTNQSTN FALSE EOF + Source: length Int = false == false + false ?? false + Conflict origins: state 166 on QSTNQSTN, state 214 on QSTNQSTN + +18. Tokens (11): LIDENT UIDENT EQUAL FALSE EQEQ FALSE SLASH FALSE QSTNQSTN FALSE EOF + Source: length Int = false == false / false ?? false + Conflict origins: state 158 on QSTNQSTN, state 214 on QSTNQSTN + +19. Tokens (11): LIDENT UIDENT EQUAL FALSE EQEQ FALSE STAR FALSE QSTNQSTN FALSE EOF + Source: length Int = false == false * false ?? false + Conflict origins: state 148 on QSTNQSTN, state 214 on QSTNQSTN + +20. Tokens (11): LIDENT UIDENT EQUAL FALSE EQEQ TILDE FALSE QSTNMARK LCURLY RCURLY EOF + Source: length Int = false == ~ false ? { } + Conflict origins: state 214 on QSTNMARK, state 496 on QSTNMARK + +21. Tokens (11): LIDENT UIDENT EQUAL FALSE EQEQ UIDENT LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = false == Int ( ) ?? false + Conflict origins: state 93 on LPAREN, state 132 on QSTNQSTN, state 214 on QSTNQSTN + +22. Tokens (11): LIDENT UIDENT EQUAL FALSE LESS FALSE LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = false < false ( ) ?? false + Conflict origins: state 135 on LPAREN, state 138 on QSTNQSTN, state 206 on QSTNQSTN + +23. Tokens (11): LIDENT UIDENT EQUAL FALSE LESS FALSE MINUS FALSE QSTNQSTN FALSE EOF + Source: length Int = false < false - false ?? false + Conflict origins: state 178 on QSTNQSTN, state 206 on QSTNQSTN + +24. Tokens (11): LIDENT UIDENT EQUAL FALSE LESS FALSE PLUS FALSE QSTNQSTN FALSE EOF + Source: length Int = false < false + false ?? false + Conflict origins: state 166 on QSTNQSTN, state 206 on QSTNQSTN + +25. Tokens (11): LIDENT UIDENT EQUAL FALSE LESS FALSE SLASH FALSE QSTNQSTN FALSE EOF + Source: length Int = false < false / false ?? false + Conflict origins: state 158 on QSTNQSTN, state 206 on QSTNQSTN + +26. Tokens (11): LIDENT UIDENT EQUAL FALSE LESS FALSE STAR FALSE QSTNQSTN FALSE EOF + Source: length Int = false < false * false ?? false + Conflict origins: state 148 on QSTNQSTN, state 206 on QSTNQSTN + +27. Tokens (11): LIDENT UIDENT EQUAL FALSE LESS TILDE FALSE QSTNMARK LCURLY RCURLY EOF + Source: length Int = false < ~ false ? { } + Conflict origins: state 206 on QSTNMARK, state 496 on QSTNMARK + +28. Tokens (11): LIDENT UIDENT EQUAL FALSE LESS UIDENT LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = false < Int ( ) ?? false + Conflict origins: state 93 on LPAREN, state 132 on QSTNQSTN, state 206 on QSTNQSTN + +29. Tokens (11): LIDENT UIDENT EQUAL FALSE LESSEQ FALSE LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = false <= false ( ) ?? false + Conflict origins: state 135 on LPAREN, state 138 on QSTNQSTN, state 198 on QSTNQSTN + +30. Tokens (11): LIDENT UIDENT EQUAL FALSE LESSEQ FALSE MINUS FALSE QSTNQSTN FALSE EOF + Source: length Int = false <= false - false ?? false + Conflict origins: state 178 on QSTNQSTN, state 198 on QSTNQSTN + +31. Tokens (11): LIDENT UIDENT EQUAL FALSE LESSEQ FALSE PLUS FALSE QSTNQSTN FALSE EOF + Source: length Int = false <= false + false ?? false + Conflict origins: state 166 on QSTNQSTN, state 198 on QSTNQSTN + +32. Tokens (11): LIDENT UIDENT EQUAL FALSE LESSEQ FALSE SLASH FALSE QSTNQSTN FALSE EOF + Source: length Int = false <= false / false ?? false + Conflict origins: state 158 on QSTNQSTN, state 198 on QSTNQSTN + +33. Tokens (11): LIDENT UIDENT EQUAL FALSE LESSEQ FALSE STAR FALSE QSTNQSTN FALSE EOF + Source: length Int = false <= false * false ?? false + Conflict origins: state 148 on QSTNQSTN, state 198 on QSTNQSTN + +34. Tokens (11): LIDENT UIDENT EQUAL FALSE LESSEQ TILDE FALSE QSTNMARK LCURLY RCURLY EOF + Source: length Int = false <= ~ false ? { } + Conflict origins: state 198 on QSTNMARK, state 496 on QSTNMARK + +35. Tokens (11): LIDENT UIDENT EQUAL FALSE LESSEQ UIDENT LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = false <= Int ( ) ?? false + Conflict origins: state 93 on LPAREN, state 132 on QSTNQSTN, state 198 on QSTNQSTN + +36. Tokens (11): LIDENT UIDENT EQUAL FALSE LPAREN RPAREN QSTNQSTN FALSE LPAREN RPAREN EOF + Source: length Int = false ( ) ?? false ( ) + Conflict origins: state 135 on LPAREN, state 138 on QSTNQSTN + +37. Tokens (11): LIDENT UIDENT EQUAL FALSE MINUS FALSE LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = false - false ( ) ?? false + Conflict origins: state 135 on LPAREN, state 138 on QSTNQSTN, state 178 on QSTNQSTN + +38. Tokens (11): LIDENT UIDENT EQUAL FALSE MINUS FALSE SLASH FALSE QSTNQSTN FALSE EOF + Source: length Int = false - false / false ?? false + Conflict origins: state 158 on QSTNQSTN, state 178 on QSTNQSTN + +39. Tokens (11): LIDENT UIDENT EQUAL FALSE MINUS FALSE STAR FALSE QSTNQSTN FALSE EOF + Source: length Int = false - false * false ?? false + Conflict origins: state 148 on QSTNQSTN, state 178 on QSTNQSTN + +40. Tokens (11): LIDENT UIDENT EQUAL FALSE MINUS TILDE FALSE QSTNMARK LCURLY RCURLY EOF + Source: length Int = false - ~ false ? { } + Conflict origins: state 178 on QSTNMARK, state 496 on QSTNMARK + +41. Tokens (11): LIDENT UIDENT EQUAL FALSE MINUS UIDENT LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = false - Int ( ) ?? false + Conflict origins: state 93 on LPAREN, state 132 on QSTNQSTN, state 178 on QSTNQSTN + +42. Tokens (11): LIDENT UIDENT EQUAL FALSE MORE FALSE LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = false > false ( ) ?? false + Conflict origins: state 135 on LPAREN, state 138 on QSTNQSTN, state 190 on QSTNQSTN + +43. Tokens (11): LIDENT UIDENT EQUAL FALSE MORE FALSE MINUS FALSE QSTNQSTN FALSE EOF + Source: length Int = false > false - false ?? false + Conflict origins: state 178 on QSTNQSTN, state 190 on QSTNQSTN + +44. Tokens (11): LIDENT UIDENT EQUAL FALSE MORE FALSE PLUS FALSE QSTNQSTN FALSE EOF + Source: length Int = false > false + false ?? false + Conflict origins: state 166 on QSTNQSTN, state 190 on QSTNQSTN + +45. Tokens (11): LIDENT UIDENT EQUAL FALSE MORE FALSE SLASH FALSE QSTNQSTN FALSE EOF + Source: length Int = false > false / false ?? false + Conflict origins: state 158 on QSTNQSTN, state 190 on QSTNQSTN + +46. Tokens (11): LIDENT UIDENT EQUAL FALSE MORE FALSE STAR FALSE QSTNQSTN FALSE EOF + Source: length Int = false > false * false ?? false + Conflict origins: state 148 on QSTNQSTN, state 190 on QSTNQSTN + +47. Tokens (11): LIDENT UIDENT EQUAL FALSE MORE TILDE FALSE QSTNMARK LCURLY RCURLY EOF + Source: length Int = false > ~ false ? { } + Conflict origins: state 190 on QSTNMARK, state 496 on QSTNMARK + +48. Tokens (11): LIDENT UIDENT EQUAL FALSE MORE UIDENT LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = false > Int ( ) ?? false + Conflict origins: state 93 on LPAREN, state 132 on QSTNQSTN, state 190 on QSTNQSTN + +49. Tokens (11): LIDENT UIDENT EQUAL FALSE MOREEQ FALSE LPAREN RPAREN QSTNQSTN FALSE EOF + Source: length Int = false >= false ( ) ?? false + Conflict origins: state 135 on LPAREN, state 138 on QSTNQSTN, state 174 on QSTNQSTN + +50. Tokens (11): LIDENT UIDENT EQUAL FALSE MOREEQ FALSE MINUS FALSE QSTNQSTN FALSE EOF + Source: length Int = false >= false - false ?? false + Conflict origins: state 174 on QSTNQSTN, state 178 on QSTNQSTN + +Explored 5970121 frontiers (8805696 unique); 572350 conflict seeds. +Search stopped because one or more workers reached a search limit. diff --git a/tools/ambiguity_search.ml b/tools/ambiguity_search.ml index f8597460..1bd801a3 100644 --- a/tools/ambiguity_search.ml +++ b/tools/ambiguity_search.ml @@ -929,12 +929,12 @@ module Seen_cache = struct mutable inserted : int; } - (* Digest entries are an order of magnitude smaller than the queued items - the memory budget is sized for, so the cache can afford to remember - four times the budget: two generations of twice the budget each. *) + (* [capacity] is the total number of entries retained across both + generations. Keeping that meaning literal is important: callers use it + to divide a fixed memory budget between the queue and deduplication. *) let create capacity = { - generation_capacity = max 1 (2 * capacity); + generation_capacity = max 1 (capacity / 2); young = Hashtbl.create 4_096; old = Hashtbl.create 4_096; inserted = 0; @@ -958,15 +958,26 @@ module Seen_cache = struct let insert cache key depth = cache.inserted <- cache.inserted + 1; refresh cache key depth + + (* Deduplication is an optimization, so the older generation is the safest + memory to reclaim under pressure: forgetting it can cause re-exploration + but cannot hide a witness. *) + let release_old cache = cache.old <- Hashtbl.create 4_096 end +let managed_heap_bytes () = + let stats = Gc.quick_stat () in + float_of_int stats.heap_words *. float_of_int (Sys.word_size / 8) + let unified_search engine initial ~max_tokens ~timeout ~max_frontiers - ~max_queue ~max_witnesses conflict_distance accept_distance = + ~max_queue ~max_witnesses ~soft_heap_bytes ~hard_heap_bytes + conflict_distance accept_distance = let deadline = Unix.gettimeofday () +. timeout in let buckets = Array.init (max_tokens + 1) (fun _ -> Queue.create ()) in let seen = Seen_cache.create max_frontiers in let queued = ref 0 in let dropped = ref false in + let admit_new = ref true in let enqueue item = incr queued; Queue.add item buckets.(item.depth) @@ -981,6 +992,7 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers if item.depth <= max_tokens then if derivations item.frontier >= 2 && accepted_count engine item.frontier >= 2 then enqueue item + else if not !admit_new then dropped := true else let key = Seen_cache.digest item.branched item.frontier in match Seen_cache.find seen key with @@ -1019,11 +1031,47 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers bucket) buckets in - let maybe_compact () = + let compact_search_state () = + Stack_pool.compact engine.stacks mark_live; + Hashtbl.reset engine.closure_cache; + compact_floor := max stack_budget (2 * Stack_pool.size engine.stacks) + in + let maybe_compact_stacks () = if Stack_pool.size engine.stacks > !compact_floor then begin - Stack_pool.compact engine.stacks mark_live; - Hashtbl.reset engine.closure_cache; - compact_floor := max stack_budget (2 * Stack_pool.size engine.stacks) + compact_search_state () + end + in + (* Static entry-size estimates determine the shape of the search, but the + heap guard is what keeps the process inside the requested machine budget. + Near the soft limit, compact once and keep using the reclaimed space. At + the hard limit, pause admission and drain queued work until compaction + brings the heap below the resume watermark. This hysteresis keeps memory + near a plateau instead of repeatedly overshooting the budget. *) + (* soft and hard are 80% and 90% of the worker share respectively. Resume at + 85% so pressure mode holds a narrow 85--90% plateau instead of producing + a large sawtooth while the queue drains and refills. *) + let resume_heap_bytes = 1.0625 *. soft_heap_bytes in + let next_heap_check = ref soft_heap_bytes in + let manage_memory () = + let before = managed_heap_bytes () in + if before >= !next_heap_check then begin + Seen_cache.release_old seen; + compact_search_state (); + Gc.compact (); + let after = managed_heap_bytes () in + if after >= hard_heap_bytes then begin + admit_new := false; + dropped := true; + next_heap_check := 0. + end + else begin + if (not !admit_new) && after <= resume_heap_bytes then + admit_new := true; + next_heap_check := + if !admit_new then + min hard_heap_bytes (max soft_heap_bytes (after *. 1.10)) + else 0. + end end in while @@ -1033,7 +1081,11 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers do if Queue.is_empty buckets.(!depth) then incr depth else begin - maybe_compact (); + maybe_compact_stacks (); + if !admit_new then begin + if !explored mod 4_096 = 0 then manage_memory () + end + else manage_memory (); let item = Queue.take buckets.(!depth) in decr queued; incr explored; @@ -1144,14 +1196,16 @@ let initial_partitions engine jobs max_tokens = end let parallel_unified_search engine ~jobs ~max_tokens ~timeout ~max_frontiers - ~max_queue ~max_witnesses conflict_distance accept_distance temporary = + ~max_queue ~max_witnesses ~soft_heap_bytes ~hard_heap_bytes + conflict_distance accept_distance temporary = let partitions, prefix_explored, prefix_unique, prefix_seeds = initial_partitions engine (max 1 jobs) max_tokens in if Array.length partitions = 1 then let outcome, seeds = unified_search engine partitions.(0) ~max_tokens ~timeout ~max_frontiers - ~max_queue ~max_witnesses conflict_distance accept_distance + ~max_queue ~max_witnesses ~soft_heap_bytes ~hard_heap_bytes + conflict_distance accept_distance in ( { outcome with @@ -1160,6 +1214,9 @@ let parallel_unified_search engine ~jobs ~max_tokens ~timeout ~max_frontiers }, prefix_seeds + seeds ) else begin + (* Do not make every child inherit avoidable garbage or an unnecessarily + sparse major heap: after fork those pages become copy-on-write overhead. *) + Gc.compact (); (* Anything still buffered would be replayed by every child's exit. *) flush stdout; flush stderr; @@ -1171,7 +1228,8 @@ let parallel_unified_search engine ~jobs ~max_tokens ~timeout ~max_frontiers | 0 -> let result = unified_search engine initial ~max_tokens ~timeout ~max_frontiers - ~max_queue ~max_witnesses conflict_distance accept_distance + ~max_queue ~max_witnesses ~soft_heap_bytes ~hard_heap_bytes + conflict_distance accept_distance in let channel = open_out_bin output in Marshal.to_channel channel result []; @@ -1225,33 +1283,82 @@ let parallel_unified_search engine ~jobs ~max_tokens ~timeout ~max_frontiers prefix_seeds + seeds ) end +let environment name = + match Sys.getenv_opt name with + | Some value when value <> "" -> value + | _ -> invalid_arg (name ^ " must be set") + +let environment_int name = + match Sys.getenv_opt name with + | None | Some "" -> invalid_arg (name ^ " must be set") + | Some value -> + (match int_of_string_opt value with + | Some parsed -> parsed + | None -> invalid_arg (name ^ " must be an integer")) + +let environment_float name = + match Sys.getenv_opt name with + | None | Some "" -> invalid_arg (name ^ " must be set") + | Some value -> + (try float_of_string value + with Failure _ -> invalid_arg (name ^ " must be a number")) + let grammar = ref "" -let menhir = ref "menhir" -let max_tokens = ref 20 -let max_frontiers = ref 500_000 -let max_queue = ref 0 -let timeout = ref 60. -let jobs = ref 1 -let max_witnesses = ref 20 +let max_tokens = ref None +let timeout = ref None +let max_witnesses = ref None let check_tokens = ref [] let prove_level = ref 0 +type memory_limits = { + max_queue : int; + max_frontiers : int; + soft_heap_bytes : float; + hard_heap_bytes : float; +} + +(* Structural estimates choose how to divide the search space between queued + work and deduplication. Actual managed-heap measurements enforce the + budget at runtime, so unexpectedly large frontiers reduce search reach + instead of causing an unbounded memory spike. Ten percent remains outside + the worker high-water marks for the coordinator, native allocations, and + short-lived copy-on-write/compaction overhead. *) +let derive_memory_limits ~memory_mb ~max_frontier_ratio ~jobs ~max_tokens = + let queue_entry_bytes = 600. +. (24. *. float_of_int max_tokens) in + let frontier_entry_bytes = 240. in + let declared_per_worker_bytes = + float_of_int memory_mb *. 1024. *. 1024. /. float_of_int jobs + in + let hard_heap_bytes = 0.90 *. declared_per_worker_bytes in + let soft_heap_bytes = 0.80 *. declared_per_worker_bytes in + let combined_entry_bytes = + queue_entry_bytes +. (max_frontier_ratio *. frontier_entry_bytes) + in + let max_queue_float = floor (hard_heap_bytes /. combined_entry_bytes) in + if max_queue_float < 1. || max_queue_float > float_of_int max_int then + invalid_arg + "AMBIGUITY_MEMORY_MB is too small or too large for AMBIGUITY_JOBS"; + let max_queue = int_of_float max_queue_float in + let max_frontiers_float = + floor (float_of_int max_queue *. max_frontier_ratio) + in + if max_frontiers_float > float_of_int max_int then + invalid_arg + "AMBIGUITY_MEMORY_MB or AMBIGUITY_MAX_FRONTIER_RATIO is too large"; + let max_frontiers = max 1 (int_of_float max_frontiers_float) in + { max_queue; max_frontiers; soft_heap_bytes; hard_heap_bytes } + let options = [ - ("--menhir", Arg.Set_string menhir, "PATH Menhir executable"); - ("--max-tokens", Arg.Set_int max_tokens, "N maximum tokens, including EOF"); - ( "--max-frontiers", - Arg.Set_int max_frontiers, - "N dedup-cache entries per worker; bounds dedup memory, not the search \ - (and the abstract pair count under --prove)" ); - ( "--max-queue", - Arg.Set_int max_queue, - "N queued frontiers per worker; the search reach (a full queue drops \ - discoveries and reports the run incomplete). Its live set drives stack \ - memory. Defaults to --max-frontiers" ); - ("--timeout", Arg.Set_float timeout, "SECONDS time limit per search phase"); - ("--jobs", Arg.Set_int jobs, "N worker processes"); - ("--max-witnesses", Arg.Set_int max_witnesses, "N ambiguity families to report"); + ( "--max-tokens", + Arg.Int (fun value -> max_tokens := Some value), + "N maximum tokens, including EOF (required for search/prove)" ); + ( "--timeout", + Arg.Float (fun value -> timeout := Some value), + "SECONDS time limit per search phase (required for search/prove)" ); + ( "--max-witnesses", + Arg.Int (fun value -> max_witnesses := Some value), + "N ambiguity families to report (required for search/prove)" ); ( "--check-tokens", Arg.String (fun value -> check_tokens := words value), "TOKENS check one space-separated token sequence" ); @@ -1259,7 +1366,7 @@ let options = Arg.Set_int prove_level, "K attempt an unambiguity proof with a top-K stack abstraction; \ exit 0 proven unambiguous, 1 ambiguous, 3 not proven \ - (--max-frontiers also bounds the abstract pair count)" ); + (the derived dedup-frontier limit also bounds the abstract pair count)" ); ] let main () = @@ -1269,13 +1376,45 @@ let main () = Arg.usage options "ambiguity_search [options] GRAMMAR"; exit 2 end; - if !max_tokens < 0 then invalid_arg "--max-tokens must be at least 0"; - if !max_frontiers < 1 then invalid_arg "--max-frontiers must be at least 1"; - if !max_queue < 0 then invalid_arg "--max-queue must be non-negative"; - if !max_queue = 0 then max_queue := !max_frontiers; - if !timeout < 0. then invalid_arg "--timeout must be non-negative"; - if !jobs < 1 then invalid_arg "--jobs must be at least 1"; - if !max_witnesses < 1 then invalid_arg "--max-witnesses must be at least 1"; + let menhir = environment "AMBIGUITY_MENHIR" in + let memory_mb = environment_int "AMBIGUITY_MEMORY_MB" in + let max_frontier_ratio = + environment_float "AMBIGUITY_MAX_FRONTIER_RATIO" + in + let jobs = environment_int "AMBIGUITY_JOBS" in + Option.iter + (fun value -> + if value < 0 then invalid_arg "--max-tokens must be at least 0") + !max_tokens; + if memory_mb < 1 then invalid_arg "AMBIGUITY_MEMORY_MB must be at least 1"; + if + Float.is_nan max_frontier_ratio + || Float.is_infinite max_frontier_ratio + || max_frontier_ratio <= 0. + then + invalid_arg + "AMBIGUITY_MAX_FRONTIER_RATIO must be finite and greater than 0"; + Option.iter + (fun value -> + if value < 0. then invalid_arg "--timeout must be non-negative") + !timeout; + if jobs < 1 then invalid_arg "AMBIGUITY_JOBS must be at least 1"; + Option.iter + (fun value -> + if value < 1 then invalid_arg "--max-witnesses must be at least 1") + !max_witnesses; + let search_limits = + if !check_tokens <> [] then None + else + let required name = function + | Some value -> value + | None -> invalid_arg (name ^ " is required for search/prove") + in + Some + ( required "--max-tokens" !max_tokens, + required "--timeout" !timeout, + required "--max-witnesses" !max_witnesses ) + in let grammar_path = Unix.realpath !grammar in let temporary = temporary_directory () in Fun.protect @@ -1283,7 +1422,7 @@ let main () = (fun () -> let terminals, aliases = parse_tokens grammar_path in let automaton_path = - prepare_automaton ~menhir:!menhir ~grammar:grammar_path + prepare_automaton ~menhir ~grammar:grammar_path ~directory:temporary in let automaton = parse_automaton automaton_path terminals aliases in @@ -1301,8 +1440,19 @@ let main () = Printf.printf "Accepting derivations: %d\n" count; exit (if count >= 2 then 1 else 0) end; + let max_tokens, timeout, max_witnesses = Option.get search_limits in + let memory_limits = + derive_memory_limits ~memory_mb ~max_frontier_ratio ~jobs ~max_tokens + in + Printf.printf + "Memory budget: %d MiB total across %d worker(s); workers compact at %.0f MiB and stop admitting frontiers at %.0f MiB each (10%% reserved); per-worker limits are %d queued frontiers and %d retained dedup frontiers (ratio %g).\n" + memory_mb jobs + (memory_limits.soft_heap_bytes /. 1024. /. 1024.) + (memory_limits.hard_heap_bytes /. 1024. /. 1024.) + memory_limits.max_queue memory_limits.max_frontiers + max_frontier_ratio; if !prove_level > 0 then begin - match prove engine !prove_level !max_frontiers with + match prove engine !prove_level memory_limits.max_frontiers with | Proven pairs -> Printf.printf "PROVEN UNAMBIGUOUS: no diverging pair of accepting parses \ @@ -1313,7 +1463,8 @@ let main () = | Pair_overflow pairs -> Printf.printf "NOT PROVEN: the abstract pair limit (%d) was reached at \ - abstraction level %d. Raise --max-frontiers or lower --prove.\n" + abstraction level %d. Raise AMBIGUITY_MEMORY_MB or \ + AMBIGUITY_MAX_FRONTIER_RATIO, or lower --prove.\n" pairs !prove_level; exit 3 | Abstract_candidate (tokens, pairs) -> @@ -1334,9 +1485,11 @@ let main () = in let accept_distance = reverse_distances automaton accept_targets in let outcome, conflict_seeds = - parallel_unified_search engine ~jobs:!jobs ~max_tokens:!max_tokens - ~timeout:!timeout ~max_frontiers:!max_frontiers - ~max_queue:!max_queue ~max_witnesses:!max_witnesses conflict_distance + parallel_unified_search engine ~jobs ~max_tokens ~timeout + ~max_frontiers:memory_limits.max_frontiers + ~max_queue:memory_limits.max_queue ~max_witnesses + ~soft_heap_bytes:memory_limits.soft_heap_bytes + ~hard_heap_bytes:memory_limits.hard_heap_bytes conflict_distance accept_distance temporary in match outcome.witnesses with @@ -1345,7 +1498,7 @@ let main () = | None -> Printf.printf "No complete ambiguity found through %d tokens after exploring %d frontiers (%d unique).\n" - !max_tokens outcome.explored outcome.unique + max_tokens outcome.explored outcome.unique | Some reason -> Printf.printf "Search stopped at depth %d because %s; no complete ambiguity was found in %d explored frontiers (%d unique).\n" diff --git a/tools/syntax_experiments.py b/tools/syntax_experiments.py index 7f898bbd..f23a9a8d 100644 --- a/tools/syntax_experiments.py +++ b/tools/syntax_experiments.py @@ -14,6 +14,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed from dataclasses import asdict, dataclass, replace import json +import math import os from pathlib import Path import re @@ -719,14 +720,16 @@ def apply_variant(source: str, variant: Variant) -> str: return header + result -def run_process(command: list[str]) -> tuple[int, str, str, float]: +def run_process( + command: list[str], env: dict[str, str] | None = None +) -> tuple[int, str, str, float]: started = time.monotonic() - completed = subprocess.run(command, text=True, capture_output=True) + completed = subprocess.run(command, text=True, capture_output=True, env=env) return completed.returncode, completed.stdout, completed.stderr, time.monotonic() - started def base_command(args: argparse.Namespace, grammar: Path) -> list[str]: - return [*shlex.split(args.search_command), str(grammar), "--menhir", args.menhir] + return [*shlex.split(args.search_command), str(grammar)] def check_case(args: argparse.Namespace, grammar: Path, case: KnownCase, variant: Variant) -> CaseResult: @@ -743,20 +746,28 @@ def check_case(args: argparse.Namespace, grammar: Path, case: KnownCase, variant def search_variant(args: argparse.Namespace, grammar: Path) -> SearchResult: + # Several variants may run concurrently. Give each search an equal share + # so AMBIGUITY_MEMORY_MB remains a total budget for the whole command. + search_memory_mb = args.memory_mb // args.concurrent_searches + environment = os.environ.copy() + environment.update( + { + "AMBIGUITY_MEMORY_MB": str(search_memory_mb), + "AMBIGUITY_MAX_FRONTIER_RATIO": str(args.max_frontier_ratio), + "AMBIGUITY_JOBS": str(args.search_jobs), + "AMBIGUITY_MENHIR": args.menhir, + } + ) command = [ *base_command(args, grammar), "--max-tokens", str(args.max_tokens), "--timeout", str(args.timeout), - "--max-frontiers", - str(args.max_frontiers), - "--jobs", - str(args.search_jobs), "--max-witnesses", str(args.max_witnesses), ] - code, stdout, stderr, seconds = run_process(command) + code, stdout, stderr, seconds = run_process(command, env=environment) if code not in {0, 1}: message = (stderr or stdout or f"search exited with status {code}").strip() return SearchResult(None, None, None, None, None, None, [], seconds, message) @@ -875,7 +886,8 @@ def render_markdown(args: argparse.Namespace, results: list[VariantResult]) -> s "", ( f"Bounds: {args.max_tokens} tokens, {args.timeout:g}s, " - f"{args.max_frontiers:,} frontiers, {args.max_witnesses} witnesses per variant." + f"{args.memory_mb:,} MiB total memory, frontier ratio " + f"{args.max_frontier_ratio:g}, {args.max_witnesses} witnesses per variant." ), "", "A Pareto mark means no tested candidate was at least as good on every measured axis. " @@ -961,13 +973,9 @@ def parser() -> argparse.ArgumentParser: help="command prefix used to invoke the ambiguity search; the default" " expects a prior `dune build tools/ambiguity_search.exe`", ) - result.add_argument("--menhir", default="menhir", help="Menhir executable") - result.add_argument("--max-tokens", type=int, default=12) - result.add_argument("--timeout", type=float, default=15.0) - result.add_argument("--max-frontiers", type=int, default=150_000) - result.add_argument("--max-witnesses", type=int, default=10) - result.add_argument("--jobs", type=int, default=min(4, os.cpu_count() or 1)) - result.add_argument("--search-jobs", type=int, default=1) + result.add_argument("--max-tokens", type=int) + result.add_argument("--timeout", type=float) + result.add_argument("--max-witnesses", type=int) result.add_argument("--skip-known", action="store_true") result.add_argument( "--output", @@ -978,6 +986,28 @@ def parser() -> argparse.ArgumentParser: return result +def load_machine_config(args: argparse.Namespace, cli: argparse.ArgumentParser) -> None: + names = ( + "AMBIGUITY_MEMORY_MB", + "AMBIGUITY_MAX_FRONTIER_RATIO", + "AMBIGUITY_JOBS", + "AMBIGUITY_MENHIR", + ) + missing = [name for name in names if not os.environ.get(name)] + if missing: + cli.error(f"missing machine configuration: {', '.join(missing)}") + args.menhir = os.environ["AMBIGUITY_MENHIR"] + try: + args.memory_mb = int(os.environ["AMBIGUITY_MEMORY_MB"]) + args.max_frontier_ratio = float(os.environ["AMBIGUITY_MAX_FRONTIER_RATIO"]) + args.jobs = int(os.environ["AMBIGUITY_JOBS"]) + except ValueError: + cli.error( + "invalid AMBIGUITY_MEMORY_MB, AMBIGUITY_MAX_FRONTIER_RATIO, " + "or AMBIGUITY_JOBS" + ) + + def validate_args(args: argparse.Namespace, cli: argparse.ArgumentParser) -> None: if not args.grammar.is_file(): cli.error(f"grammar does not exist: {args.grammar}") @@ -990,14 +1020,27 @@ def validate_args(args: argparse.Namespace, cli: argparse.ArgumentParser) -> Non f"search executable does not exist: {executable};" " run `dune build tools/ambiguity_search.exe` first" ) + missing = [ + name + for name, value in ( + ("--max-tokens", args.max_tokens), + ("--timeout", args.timeout), + ("--max-witnesses", args.max_witnesses), + ) + if value is None + ] + if missing: + cli.error(f"required for experiments: {', '.join(missing)}") if args.max_tokens < 0: cli.error("--max-tokens must be at least 0") if args.timeout < 0: cli.error("--timeout must be non-negative") - if args.max_frontiers < 1 or args.max_witnesses < 1: - cli.error("frontier and witness limits must be at least 1") - if args.jobs < 1 or args.search_jobs < 1: - cli.error("worker counts must be at least 1") + if args.memory_mb < 1 or args.max_witnesses < 1: + cli.error("AMBIGUITY_MEMORY_MB and the witness limit must be at least 1") + if not math.isfinite(args.max_frontier_ratio) or args.max_frontier_ratio <= 0: + cli.error("AMBIGUITY_MAX_FRONTIER_RATIO must be finite and greater than 0") + if args.jobs < 1: + cli.error("AMBIGUITY_JOBS must be at least 1") def main() -> int: @@ -1009,11 +1052,18 @@ def main() -> int: print(f"{variant.name:52} cost={variant.edit_cost} {transforms}") print(f" {variant.description}") return 0 + load_machine_config(args, cli) validate_args(args, cli) try: variants = select_variants(args.variant) except ValueError as error: cli.error(str(error)) + args.concurrent_searches = min(args.jobs, len(variants)) + args.search_jobs = max(1, args.jobs // args.concurrent_searches) + if args.memory_mb < args.concurrent_searches: + cli.error( + "AMBIGUITY_MEMORY_MB must provide at least 1 MiB per concurrent search" + ) source = args.grammar.read_text(encoding="utf-8") temporary: tempfile.TemporaryDirectory[str] | None = None @@ -1064,7 +1114,8 @@ def main() -> int: "bounds": { "max_tokens": args.max_tokens, "timeout": args.timeout, - "max_frontiers": args.max_frontiers, + "memory_mb": args.memory_mb, + "max_frontier_ratio": args.max_frontier_ratio, "max_witnesses": args.max_witnesses, }, "known_cases": [ From c9d0cfcace5583d1057b95ed9f8c0ae711e2a446 Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Thu, 23 Jul 2026 22:10:49 +0200 Subject: [PATCH 148/154] Add targeted ambiguity search controls (#44) * Add targeted ambiguity search controls * Document targeted ambiguity searches * Use a function prefix in ambiguity example * try find f()(x)() * Make depth search rotate sibling nodes * Document nodes-per-depth scheduling * Add ambiguity search profiles * Add ambiguity search profiles * Add ambiguity search profiles * Add ambiguity search profiles * Add ambiguity search profiles * Add ambiguity search profiles * Add ambiguity search profiles * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * Use singular tool names * fix file permissions * make reports/ * Show live ambiguity search progress * Show live ambiguity search progress * Fix live progress record typing * Fix live progress record typing * Fix progress record type inference * Fix progress depth type inference * new report --- README.md | 17 +- ambiguity-searches.toml | 18 + dev/bin/ambiguities | 11 - dev/bin/ambiguity | 25 + .../{grammar-conflicts => grammar-conflict} | 1 + dev/bin/{grammar-stats => grammar-stat} | 1 + .../{syntax-experiments => syntax-experiment} | 3 +- dev/lib/ambiguity-config.sh | 2 +- docs/ambiguity.md | 69 ++- justfile | 7 +- reports/2026-07-23_21-38-17.txt | 28 ++ .../ambiguities-report.txt | 0 reports/deep.txt | 46 ++ .../new-ambiguities-report.txt | 0 ...AX_EXPERIMENTS.md => SYNTAX_EXPERIMENT.md} | 20 +- tools/ambiguity.py | 471 ++++++++++++++++++ tools/ambiguity_search.ml | 410 +++++++++++++-- ...ax_experiments.py => syntax_experiment.py} | 4 +- tools/test_ambiguity.py | 155 ++++++ ...periments.py => test_syntax_experiment.py} | 2 +- 20 files changed, 1189 insertions(+), 101 deletions(-) create mode 100644 ambiguity-searches.toml delete mode 100755 dev/bin/ambiguities create mode 100755 dev/bin/ambiguity rename dev/bin/{grammar-conflicts => grammar-conflict} (84%) rename dev/bin/{grammar-stats => grammar-stat} (88%) rename dev/bin/{syntax-experiments => syntax-experiment} (75%) create mode 100644 reports/2026-07-23_21-38-17.txt rename ambiguities-report.txt => reports/ambiguities-report.txt (100%) create mode 100644 reports/deep.txt rename new-ambiguities-report.txt => reports/new-ambiguities-report.txt (100%) rename tools/{SYNTAX_EXPERIMENTS.md => SYNTAX_EXPERIMENT.md} (90%) create mode 100644 tools/ambiguity.py rename tools/{syntax_experiments.py => syntax_experiment.py} (99%) create mode 100644 tools/test_ambiguity.py rename tools/{test_syntax_experiments.py => test_syntax_experiment.py} (99%) diff --git a/README.md b/README.md index 86602bc2..10e468c4 100644 --- a/README.md +++ b/README.md @@ -33,13 +33,16 @@ Common tools are available directly inside the development shell: ```sh compiler -ambiguities --max-tokens 100 --timeout 3600 --max-witnesses 50 -ambiguities --prove 3 --max-tokens 16 --timeout 120 --max-witnesses 20 -syntax-experiments --max-tokens 12 --timeout 15 --max-witnesses 10 -syntax-experiments --variant semicolon-separated --max-tokens 12 --timeout 15 --max-witnesses 10 -grammar-stats -grammar-conflicts +ambiguity profiles +ambiguity search +ambiguity search deep-function-body --timeout 1h --output deep-search.txt +ambiguity check UIDENT LIDENT LPAREN RPAREN LCURLY RCURLY EOF +ambiguity prove 3 +syntax-experiment --max-tokens 12 --timeout 15 --max-witnesses 10 +syntax-experiment --variant semicolon-separated --max-tokens 12 --timeout 15 --max-witnesses 10 +grammar-stat +grammar-conflict ``` The `justfile` is reserved for parameterless project actions such as rebuilding, -watching, and running the syntax-experiment tests. +watching, and running tool tests. diff --git a/ambiguity-searches.toml b/ambiguity-searches.toml new file mode 100644 index 00000000..1487dac3 --- /dev/null +++ b/ambiguity-searches.toml @@ -0,0 +1,18 @@ +[profiles.quick] +description = "Fast breadth-first feedback while editing the grammar." +tokens = "0..16" +timeout = "2m" +witnesses = 20 + +[profiles.general] +description = "Broad shortest-first search for the regular ambiguity report." +tokens = "0..50" +timeout = "30m" +witnesses = 50 + +[profiles.deep-function-body] +extends = "general" +description = "Rotate deep search waves through statements in a function body." +tokens = "15..50" +prefix_tokens = ["UIDENT", "LIDENT", "LPAREN", "RPAREN", "LCURLY"] +nodes_per_depth = 10 diff --git a/dev/bin/ambiguities b/dev/bin/ambiguities deleted file mode 100755 index 413e9dc0..00000000 --- a/dev/bin/ambiguities +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" -# shellcheck source=../lib/ambiguity-config.sh -. "$ROOT/dev/lib/ambiguity-config.sh" - -dune build --root "$ROOT" tools/ambiguity_search.exe -exec "$ROOT/_build/default/tools/ambiguity_search.exe" \ - "$ROOT/lib/cst/parser.mly" \ - "$@" diff --git a/dev/bin/ambiguity b/dev/bin/ambiguity new file mode 100755 index 00000000..86f9c5d5 --- /dev/null +++ b/dev/bin/ambiguity @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" + +if [[ "${1:-}" == "__engine" ]]; then + shift + # shellcheck source=../lib/ambiguity-config.sh + . "$ROOT/dev/lib/ambiguity-config.sh" + dune build --root "$ROOT" tools/ambiguity_search.exe + exec "$ROOT/_build/default/tools/ambiguity_search.exe" \ + "$ROOT/lib/cst/parser.mly" \ + "$@" +fi + +# Keep existing scripts working while the profile interface becomes the +# preferred entry point. +case "${1:-}" in + --max-tokens | --min-tokens | --prefix-tokens | --nodes-per-depth | \ + --timeout | --max-witnesses | --check-tokens | --prove) + exec "$0" __engine "$@" + ;; +esac + +exec python3 "$ROOT/tools/ambiguity.py" "$@" diff --git a/dev/bin/grammar-conflicts b/dev/bin/grammar-conflict similarity index 84% rename from dev/bin/grammar-conflicts rename to dev/bin/grammar-conflict index 1c4c753f..f8248ee9 100755 --- a/dev/bin/grammar-conflicts +++ b/dev/bin/grammar-conflict @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -euo pipefail +# Find a concrete sentence that reaches a grammar conflict. ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" # shellcheck source=../lib/ambiguity-config.sh . "$ROOT/dev/lib/ambiguity-config.sh" diff --git a/dev/bin/grammar-stats b/dev/bin/grammar-stat similarity index 88% rename from dev/bin/grammar-stats rename to dev/bin/grammar-stat index 3323fe74..e96b3b83 100755 --- a/dev/bin/grammar-stats +++ b/dev/bin/grammar-stat @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -euo pipefail +# Report statistics for the grammar. ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" # shellcheck source=../lib/ambiguity-config.sh . "$ROOT/dev/lib/ambiguity-config.sh" diff --git a/dev/bin/syntax-experiments b/dev/bin/syntax-experiment similarity index 75% rename from dev/bin/syntax-experiments rename to dev/bin/syntax-experiment index 0cdd7242..4d82bc97 100755 --- a/dev/bin/syntax-experiments +++ b/dev/bin/syntax-experiment @@ -1,12 +1,13 @@ #!/usr/bin/env bash set -euo pipefail +# Run one syntax experiment or a selected set of variants. ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" # shellcheck source=../lib/ambiguity-config.sh . "$ROOT/dev/lib/ambiguity-config.sh" dune build --root "$ROOT" tools/ambiguity_search.exe -exec python3 "$ROOT/tools/syntax_experiments.py" \ +exec python3 "$ROOT/tools/syntax_experiment.py" \ "$ROOT/lib/cst/parser.mly" \ --search-command "$ROOT/_build/default/tools/ambiguity_search.exe" \ "$@" diff --git a/dev/lib/ambiguity-config.sh b/dev/lib/ambiguity-config.sh index 392710b2..c5d8787e 100644 --- a/dev/lib/ambiguity-config.sh +++ b/dev/lib/ambiguity-config.sh @@ -10,7 +10,7 @@ for name in \ AMBIGUITY_JOBS \ AMBIGUITY_MENHIR; do if [[ -z "${!name:-}" ]]; then - echo "ambiguities: $name must be set in machine-config.txt or the environment" >&2 + echo "ambiguity: $name must be set in machine-config.txt or the environment" >&2 exit 2 fi done diff --git a/docs/ambiguity.md b/docs/ambiguity.md index 30e3f4b8..4fc40b6e 100644 --- a/docs/ambiguity.md +++ b/docs/ambiguity.md @@ -33,8 +33,8 @@ the state is triaged into one of these categories. ## Tooling -- `ambiguities` — bounded, parallel GLR search for complete ambiguous - sentences (`tools/ambiguity_search.ml`). A completed bound is a theorem +- `ambiguity search [PROFILE]` — bounded, parallel GLR search for complete + ambiguous sentences (`tools/ambiguity_search.ml`). A completed bound is a theorem ("no ambiguous sentence of at most N tokens"), up to the astronomically unlikely collision of the 124-bit frontier digests used for deduplication; an interrupted bound is evidence only. @@ -53,25 +53,49 @@ the state is triaged into one of these categories. covers the coordinator, native allocations, and transient compaction/ copy-on-write overhead. This keeps memory near the configured plateau while prioritizing queue reach even when real frontiers are larger than the - estimate. The search itself is bounded by `--max-tokens` and `--timeout`, and - a run that had to drop part of the space reports itself as interrupted. + estimate. Named profiles in `ambiguity-searches.toml` collect search intent + in one reviewable place. `ambiguity profiles` lists them, and command-line + options can temporarily override a profile. The default `general` profile + is breadth-first; `deep-function-body` fixes the function-body prefix and + rotates depth waves so sibling statements continue to receive attention. + The search itself is bounded by the profile's token range and timeout, and a + run that had to drop part of the space reports itself as interrupted. + In an interactive terminal, one transient status line shows the active token + depth, ambiguity families found at that depth, explored and unique frontiers, + elapsed time, and a RAM bar against the configured memory budget. The + coordinator deduplicates ambiguity families across workers before displaying + the count. Redirected output and saved reports contain no progress line. + `--nodes-per-depth N` expands up to `N` queued frontiers at one depth before + descending to the next populated depth. When a deep wave ends, the search + returns to the shallowest unfinished depth, so earlier token choices rotate + instead of one deep subtree monopolizing the run. Smaller values are + narrower and deeper; larger values explore more siblings before descending. + Omitting the option preserves breadth-first scheduling. The scheduler does + not prune queued frontiers, so a run that completes its bound remains + exhaustive. + `--min-tokens N` prevents shorter ambiguities from consuming witness slots. + `--prefix-tokens "TOKENS..."` first advances the GLR parser through a fixed + token prefix and searches from that frontier, which is useful for targeting + contexts such as a function body. Minimum and maximum token counts include + the prefix and `EOF`. Witnesses are grouped by the conflict states they traverse, which maps each finding directly onto an obligation above. -- `ambiguities --prove K` — conservative unambiguity proof mode built into the - ambiguity search. It abstracts GLR stacks to their top-K states and +- `ambiguity prove K [PROFILE]` — conservative unambiguity proof mode built + into the ambiguity search. It abstracts GLR stacks to their top-K states and exhaustively explores pairs of abstract parses of the same input, comparing reduction chains in lockstep. It does not depend on an external constraint solver. Three verdicts: exit 0 "PROVEN UNAMBIGUOUS" is a genuine proof with no sentence-length bound; exit 1 means a concrete ambiguous sentence was found; exit 3 means not proven — the abstraction reported a candidate the - bounded search could not concretize, so raise `--prove` or the search bounds. + bounded search could not concretize, so raise the proof level or override the + concretization profile. Because unambiguity is undecidable in general, the "not proven" verdict can never be eliminated entirely; the prover is validated against known-ambiguous grammars, LR(1) grammars, precedence-resolved expression grammars, and unambiguous non-LR grammars such as palindromes. -- `syntax-experiments` — compares candidate grammar changes under +- `syntax-experiment` — compares candidate grammar changes under equal search bounds before they are adopted - (`tools/SYNTAX_EXPERIMENTS.md`). + (`tools/SYNTAX_EXPERIMENT.md`). - `menhir --explain` — enumerates the conflict states that constitute the obligation ledger. @@ -85,9 +109,30 @@ out of version control. The file supplies `AMBIGUITY_MEMORY_MB`, `AMBIGUITY_MAX_FRONTIER_RATIO`, `AMBIGUITY_JOBS`, and `AMBIGUITY_MENHIR` as environment variables; they are deliberately not command-line options. -Search intent remains on the command line. For example, -`ambiguities --max-tokens 100 --timeout 3600 --max-witnesses 50` searches -through 100 tokens for up to one hour, using the local machine budget. +Search intent lives in versioned profiles, with concise overrides for one-off +runs. For example, `ambiguity search general --tokens 0..100 --timeout 1h` +searches through 100 tokens for up to one hour, using the local machine budget. +Friendly durations such as `90s`, `30m`, and `1h` are accepted. Add +`--output report.txt` to display and save a report, or `--dry-run` to inspect +the resolved settings without building the engine. + +To concentrate a run inside a function body and favor depth over breadth: + +```sh +ambiguity search deep-function-body +``` + +To change just one aspect without creating a profile: + +```sh +ambiguity search deep-function-body --nodes-per-depth 4 --timeout 2h +``` + +Exact witnesses can be checked without quoting their token names: + +```sh +ambiguity check UIDENT LIDENT LPAREN RPAREN LCURLY LIDENT LPAREN RPAREN EOF +``` ## Why this is sound diff --git a/justfile b/justfile index 57ba57f0..adbb10f7 100644 --- a/justfile +++ b/justfile @@ -8,5 +8,8 @@ rebuild: watch: dune build --watch -syntax-experiments-test: - python3 -m unittest tools.test_syntax_experiments -v +syntax-experiment-test: + python3 -m unittest tools.test_syntax_experiment -v + +ambiguity-test: + python3 -m unittest tools.test_ambiguity -v diff --git a/reports/2026-07-23_21-38-17.txt b/reports/2026-07-23_21-38-17.txt new file mode 100644 index 00000000..24104a6b --- /dev/null +++ b/reports/2026-07-23_21-38-17.txt @@ -0,0 +1,28 @@ +Search profile: deep-function-body +Rotate deep search waves through statements in a function body. +Tokens 15..50 · timeout 30m · 50 witnesses · 10 nodes per depth +Prefix (5): UIDENT LIDENT LPAREN RPAREN LCURLY + +Memory budget: 6144 MiB total across 4 worker(s); workers compact at 1229 MiB and stop admitting frontiers at 1382 MiB each (10% reserved); per-worker limits are 710564 queued frontiers and 710564 retained dedup frontiers (ratio 1). +Search constraints: 15..50 total tokens; 5-token prefix; 10 nodes per depth. +Prefix tokens: UIDENT LIDENT LPAREN RPAREN LCURLY +Found 4 complete ambiguity families. + +1. Tokens (15): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT TRUE EQEQ AND TILDE FALSE QSTNQSTN FALSE RCURLY EOF + Source: Int length ( ) { abort true == & ~ false ?? false } + Conflict origins: state 214 on QSTNQSTN, state 496 on QSTNQSTN + +2. Tokens (15): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT TRUE LESSEQ TILDE FALSE QSTNQSTN AND STRING RCURLY EOF + Source: Int length ( ) { abort true <= ~ false ?? & "john" } + Conflict origins: state 198 on QSTNQSTN, state 496 on QSTNQSTN + +3. Tokens (17): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT TRUE ABORT AND FALSE LESS TILDE FALSE QSTNQSTN INT RCURLY EOF + Source: Int length ( ) { abort true abort & false < ~ false ?? 43 } + Conflict origins: state 206 on QSTNQSTN, state 496 on QSTNQSTN + +4. Tokens (17): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT UIDENT LBRACKET RBRACKET LPAREN RPAREN THICK_ARROW FALSE DOT LIDENT RCURLY EOF + Source: Int length ( ) { abort Int [ ] ( ) => false . length } + Conflict origins: state 503 on DOT + +Explored 19546256 frontiers (22249396 unique); 415852 conflict seeds. +Search stopped because one or more workers reached a search limit. diff --git a/ambiguities-report.txt b/reports/ambiguities-report.txt similarity index 100% rename from ambiguities-report.txt rename to reports/ambiguities-report.txt diff --git a/reports/deep.txt b/reports/deep.txt new file mode 100644 index 00000000..c1fca543 --- /dev/null +++ b/reports/deep.txt @@ -0,0 +1,46 @@ +Search profile: deep-function-body +Rotate deep search waves through statements in a function body. +Tokens 15..50 · timeout 30m · 50 witnesses · 10 nodes per depth +Prefix (5): UIDENT LIDENT LPAREN RPAREN LCURLY + +Memory budget: 6144 MiB total across 4 worker(s); workers compact at 1229 MiB and stop admitting frontiers at 1 +382 MiB each (10% reserved); per-worker limits are 710564 queued frontiers and 710564 retained dedup frontiers +(ratio 1). +Search constraints: 15..50 total tokens; 5-token prefix; 10 nodes per depth. +Prefix tokens: UIDENT LIDENT LPAREN RPAREN LCURLY +Found 7 complete ambiguity families. + +1. Tokens (15): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT TRUE EQEQ AND TILDE FALSE QSTNQSTN FALSE RCURLY EOF + Source: Int length ( ) { abort true == & ~ false ?? false } + Conflict origins: state 214 on QSTNQSTN, state 496 on QSTNQSTN + +2. Tokens (15): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT TRUE LESSEQ TILDE FALSE QSTNQSTN AND STRING RCURLY EOF + Source: Int length ( ) { abort true <= ~ false ?? & "john" } + Conflict origins: state 198 on QSTNQSTN, state 496 on QSTNQSTN + +3. Tokens (15): UIDENT LIDENT LPAREN RPAREN LCURLY RESOLVE TRUE MINUS TILDE FALSE QSTNQSTN AND TRUE RCURLY EOF + Source: Int length ( ) { resolve true - ~ false ?? & true } + Conflict origins: state 178 on QSTNQSTN, state 496 on QSTNQSTN + +4. Tokens (15): UIDENT LIDENT LPAREN RPAREN LCURLY RESOLVE UIDENT LPAREN RPAREN THICK_ARROW FLOAT SLASH STRING +RCURLY EOF + Source: Int length ( ) { resolve Int ( ) => 8.647 / "john" } + Conflict origins: state 93 on LPAREN, state 503 on SLASH + +5. Tokens (16): UIDENT LIDENT LPAREN RPAREN LCURLY RESOLVE TILDE TILDE TILDE AND TRUE QSTNQSTN AND INT RCURLY E +OF + Source: Int length ( ) { resolve ~ ~ ~ & true ?? & 43 } + Conflict origins: state 496 on QSTNQSTN + +6. Tokens (16): UIDENT LIDENT LPAREN RPAREN LCURLY RETURN TRUE LESS TILDE FALSE QSTNQSTN LIDENT MINUS FLOAT RCU +RLY EOF + Source: Int length ( ) { return true < ~ false ?? length - 8.647 } + Conflict origins: state 206 on QSTNQSTN, state 496 on QSTNQSTN + +7. Tokens (17): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT UIDENT LBRACKET RBRACKET LPAREN RPAREN THICK_ARROW FAL +SE DOT LIDENT RCURLY EOF + Source: Int length ( ) { abort Int [ ] ( ) => false . length } + Conflict origins: state 503 on DOT + +Explored 27585724 frontiers (30246349 unique); 455669 conflict seeds. +Search stopped because one or more workers reached a search limit. diff --git a/new-ambiguities-report.txt b/reports/new-ambiguities-report.txt similarity index 100% rename from new-ambiguities-report.txt rename to reports/new-ambiguities-report.txt diff --git a/tools/SYNTAX_EXPERIMENTS.md b/tools/SYNTAX_EXPERIMENT.md similarity index 90% rename from tools/SYNTAX_EXPERIMENTS.md rename to tools/SYNTAX_EXPERIMENT.md index b7755acd..12b5e240 100644 --- a/tools/SYNTAX_EXPERIMENTS.md +++ b/tools/SYNTAX_EXPERIMENT.md @@ -1,6 +1,6 @@ # Syntax experiments -`syntax_experiments.py` compares small, explicit changes to Zane's concrete +`syntax_experiment.py` compares small, explicit changes to Zane's concrete syntax. It generates a temporary Menhir grammar for every selected variant, replays the known complete-ambiguity witnesses, runs the bounded ambiguity search, and produces Markdown and JSON reports. @@ -11,24 +11,24 @@ reviewable, composable, and assigned an approximate edit cost. ## Quick start ```sh -just syntax-experiments-list -just syntax-experiments -just syntax-experiment semicolon-separated +syntax-experiment --list +syntax-experiment +syntax-experiment --variant semicolon-separated ``` Reports are written to: ```text -_build/syntax-experiments/report.md -_build/syntax-experiments/report.json +_build/syntax-experiment/report.md +_build/syntax-experiment/report.json ``` Generated grammars normally live only for the duration of a run. To inspect them directly: ```sh -python3 tools/syntax_experiments.py --emit-only \ - --emit-dir _build/syntax-experiments/grammars +python3 tools/syntax_experiment.py --emit-only \ + --emit-dir _build/syntax-experiment/grammars ``` ## Included ideas @@ -104,8 +104,8 @@ human judgment. known witnesses are spelled). The two tables must cover the same names. 3. Add one or more `Variant` entries, including useful combinations and an edit cost. -4. Add focused assertions to `test_syntax_experiments.py`. -5. Run `just syntax-experiments-test`, then a short single-variant search before +4. Add focused assertions to `test_syntax_experiment.py`. +5. Run `just syntax-experiment-test`, then a short single-variant search before comparing the full matrix. ## Limitations diff --git a/tools/ambiguity.py b/tools/ambiguity.py new file mode 100644 index 00000000..a2198177 --- /dev/null +++ b/tools/ambiguity.py @@ -0,0 +1,471 @@ +#!/usr/bin/env python3 +"""Friendly command-line interface for the ambiguity-search engine.""" + +from __future__ import annotations + +import argparse +from dataclasses import dataclass, replace +from pathlib import Path +import re +import shlex +import subprocess +import sys +import tomllib +from typing import Any, Sequence, TextIO + + +ROOT = Path(__file__).resolve().parent.parent +DEFAULT_PROFILES = ROOT / "ambiguity-searches.toml" +ENGINE_RUNNER = ROOT / "dev" / "bin" / "ambiguity" + +PROFILE_KEYS = { + "description", + "extends", + "tokens", + "timeout", + "witnesses", + "prefix_tokens", + "nodes_per_depth", +} +DURATION_PART = re.compile(r"(\d+(?:\.\d+)?)(ms|s|m|h)") +DURATION_FACTORS = {"ms": 0.001, "s": 1.0, "m": 60.0, "h": 3600.0} + + +class ConfigurationError(ValueError): + pass + + +@dataclass(frozen=True) +class SearchProfile: + name: str + description: str + min_tokens: int + max_tokens: int + timeout_seconds: float + witnesses: int + prefix_tokens: tuple[str, ...] = () + nodes_per_depth: int | None = None + + +def parse_token_range(value: str) -> tuple[int, int]: + match = re.fullmatch(r"\s*(\d+)\s*\.\.\s*(\d+)\s*", value) + if match is None: + raise ConfigurationError( + f"invalid token range {value!r}; expected MIN..MAX" + ) + minimum, maximum = map(int, match.groups()) + if minimum > maximum: + raise ConfigurationError("token range minimum must not exceed its maximum") + return minimum, maximum + + +def parse_duration(value: str | int | float) -> float: + if isinstance(value, bool): + raise ConfigurationError("duration must be a number or a value such as 30m") + if isinstance(value, (int, float)): + seconds = float(value) + else: + text = value.strip().lower() + if re.fullmatch(r"\d+(?:\.\d+)?", text): + seconds = float(text) + else: + seconds = 0.0 + position = 0 + for match in DURATION_PART.finditer(text): + if match.start() != position: + break + seconds += float(match.group(1)) * DURATION_FACTORS[match.group(2)] + position = match.end() + if position != len(text) or position == 0: + raise ConfigurationError( + f"invalid duration {value!r}; use values such as 90s, 30m, or 1h" + ) + if seconds < 0: + raise ConfigurationError("duration must be non-negative") + return seconds + + +def format_duration(seconds: float) -> str: + if seconds == 0: + return "0s" + if seconds % 3600 == 0: + return f"{seconds / 3600:g}h" + if seconds % 60 == 0: + return f"{seconds / 60:g}m" + return f"{seconds:g}s" + + +def _profile_tables(path: Path) -> dict[str, dict[str, Any]]: + try: + with path.open("rb") as source: + document = tomllib.load(source) + except OSError as error: + raise ConfigurationError(f"cannot read profiles from {path}: {error}") from error + except tomllib.TOMLDecodeError as error: + raise ConfigurationError(f"invalid TOML in {path}: {error}") from error + tables = document.get("profiles") + if not isinstance(tables, dict) or not tables: + raise ConfigurationError(f"{path} must contain at least one [profiles.NAME]") + result: dict[str, dict[str, Any]] = {} + for name, table in tables.items(): + if not isinstance(table, dict): + raise ConfigurationError(f"profile {name!r} must be a TOML table") + unknown = set(table) - PROFILE_KEYS + if unknown: + keys = ", ".join(sorted(unknown)) + raise ConfigurationError(f"profile {name!r} has unknown settings: {keys}") + result[name] = table + return result + + +def load_profiles(path: Path = DEFAULT_PROFILES) -> dict[str, SearchProfile]: + tables = _profile_tables(path) + resolved: dict[str, dict[str, Any]] = {} + resolving: list[str] = [] + + def resolve(name: str) -> dict[str, Any]: + if name in resolved: + return resolved[name] + if name not in tables: + raise ConfigurationError(f"unknown inherited profile {name!r}") + if name in resolving: + cycle = " -> ".join([*resolving, name]) + raise ConfigurationError(f"profile inheritance cycle: {cycle}") + resolving.append(name) + table = tables[name] + parent = table.get("extends") + if parent is not None and not isinstance(parent, str): + raise ConfigurationError(f"profile {name!r}: extends must be a string") + merged = dict(resolve(parent)) if parent else {} + merged.update({key: value for key, value in table.items() if key != "extends"}) + resolving.pop() + resolved[name] = merged + return merged + + profiles: dict[str, SearchProfile] = {} + for name in tables: + settings = resolve(name) + missing = {"tokens", "timeout", "witnesses"} - set(settings) + if missing: + keys = ", ".join(sorted(missing)) + raise ConfigurationError(f"profile {name!r} is missing: {keys}") + token_value = settings["tokens"] + if not isinstance(token_value, str): + raise ConfigurationError(f"profile {name!r}: tokens must be MIN..MAX") + minimum, maximum = parse_token_range(token_value) + witnesses = settings["witnesses"] + if isinstance(witnesses, bool) or not isinstance(witnesses, int) or witnesses < 1: + raise ConfigurationError( + f"profile {name!r}: witnesses must be an integer of at least 1" + ) + prefix = settings.get("prefix_tokens", []) + if not isinstance(prefix, list) or not all( + isinstance(token, str) and token for token in prefix + ): + raise ConfigurationError( + f"profile {name!r}: prefix_tokens must be an array of token names" + ) + nodes = settings.get("nodes_per_depth") + if nodes is not None and ( + isinstance(nodes, bool) or not isinstance(nodes, int) or nodes < 1 + ): + raise ConfigurationError( + f"profile {name!r}: nodes_per_depth must be an integer of at least 1" + ) + if len(prefix) > maximum: + raise ConfigurationError( + f"profile {name!r}: prefix is longer than the maximum token count" + ) + description = settings.get("description", "") + if not isinstance(description, str): + raise ConfigurationError(f"profile {name!r}: description must be a string") + profiles[name] = SearchProfile( + name=name, + description=description, + min_tokens=minimum, + max_tokens=maximum, + timeout_seconds=parse_duration(settings["timeout"]), + witnesses=witnesses, + prefix_tokens=tuple(prefix), + nodes_per_depth=nodes, + ) + return profiles + + +def apply_overrides( + profile: SearchProfile, arguments: argparse.Namespace +) -> SearchProfile: + result = profile + if arguments.token_range is not None: + minimum, maximum = parse_token_range(arguments.token_range) + result = replace(result, min_tokens=minimum, max_tokens=maximum) + if arguments.timeout is not None: + result = replace(result, timeout_seconds=parse_duration(arguments.timeout)) + if arguments.witnesses is not None: + if arguments.witnesses < 1: + raise ConfigurationError("--witnesses must be at least 1") + result = replace(result, witnesses=arguments.witnesses) + if arguments.prefix_tokens is not None: + result = replace( + result, prefix_tokens=tuple(arguments.prefix_tokens.split()) + ) + if arguments.nodes_per_depth is not None: + if arguments.nodes_per_depth < 1: + raise ConfigurationError("--nodes-per-depth must be at least 1") + result = replace(result, nodes_per_depth=arguments.nodes_per_depth) + if arguments.breadth_first: + if arguments.nodes_per_depth is not None: + raise ConfigurationError( + "--breadth-first and --nodes-per-depth cannot be combined" + ) + result = replace(result, nodes_per_depth=None) + if len(result.prefix_tokens) > result.max_tokens: + raise ConfigurationError("prefix is longer than the maximum token count") + return result + + +def engine_arguments(profile: SearchProfile, prove: int | None = None) -> list[str]: + arguments = [ + "--max-tokens", + str(profile.max_tokens), + "--min-tokens", + str(profile.min_tokens), + "--timeout", + f"{profile.timeout_seconds:g}", + "--max-witnesses", + str(profile.witnesses), + ] + if profile.prefix_tokens: + arguments.extend(["--prefix-tokens", " ".join(profile.prefix_tokens)]) + if profile.nodes_per_depth is not None: + arguments.extend(["--nodes-per-depth", str(profile.nodes_per_depth)]) + if prove is not None: + arguments.extend(["--prove", str(prove)]) + return arguments + + +def profile_summary(profile: SearchProfile, action: str) -> str: + scheduling = ( + "breadth-first" + if profile.nodes_per_depth is None + else f"{profile.nodes_per_depth} node" + f"{'' if profile.nodes_per_depth == 1 else 's'} per depth" + ) + lines = [ + f"{action} profile: {profile.name}", + ( + f"Tokens {profile.min_tokens}..{profile.max_tokens} · " + f"timeout {format_duration(profile.timeout_seconds)} · " + f"{profile.witnesses} witnesses · {scheduling}" + ), + ] + if profile.description: + lines.insert(1, profile.description) + if profile.prefix_tokens: + lines.append( + f"Prefix ({len(profile.prefix_tokens)}): " + + " ".join(profile.prefix_tokens) + ) + return "\n".join(lines) + + +def add_overrides(command: argparse.ArgumentParser) -> None: + command.add_argument( + "--tokens", + dest="token_range", + metavar="MIN..MAX", + help="override the profile's complete-witness token range", + ) + command.add_argument( + "--timeout", + metavar="DURATION", + help="override the timeout; accepts values such as 90s, 30m, and 1h", + ) + command.add_argument( + "--witnesses", + type=int, + metavar="N", + help="override the number of ambiguity families to report", + ) + command.add_argument( + "--prefix-tokens", + metavar="TOKENS", + help="override the fixed space-separated token prefix", + ) + scheduling = command.add_mutually_exclusive_group() + scheduling.add_argument( + "--nodes-per-depth", + type=int, + metavar="N", + help="override how many sibling frontiers a depth wave expands", + ) + scheduling.add_argument( + "--breadth-first", + action="store_true", + help="override the profile and use shortest-first scheduling", + ) + command.add_argument( + "--output", + type=Path, + metavar="FILE", + help="write the complete report to FILE while also displaying it", + ) + command.add_argument( + "--dry-run", + action="store_true", + help="show the resolved profile without running the engine", + ) + + +def parser() -> argparse.ArgumentParser: + result = argparse.ArgumentParser( + prog="ambiguity", + description="Search for, check, and prove grammar ambiguity.", + ) + result.add_argument( + "--profiles-file", + type=Path, + default=DEFAULT_PROFILES, + help=argparse.SUPPRESS, + ) + commands = result.add_subparsers(dest="command", required=True) + + search = commands.add_parser( + "search", help="run a bounded search using a named profile" + ) + search.add_argument( + "profile", + nargs="?", + default="general", + help="profile from ambiguity-searches.toml (default: general)", + ) + add_overrides(search) + + check = commands.add_parser( + "check", help="check one exact space-separated token sequence" + ) + check.add_argument( + "tokens", + nargs="+", + metavar="TOKEN", + help="terminal names, including EOF when required", + ) + + prove = commands.add_parser( + "prove", help="attempt an unbounded top-K proof, then concretize if needed" + ) + prove.add_argument("level", type=int, metavar="LEVEL") + prove.add_argument( + "profile", + nargs="?", + default="quick", + help="profile for bounded concretization (default: quick)", + ) + add_overrides(prove) + + commands.add_parser("profiles", help="list available search profiles") + return result + + +def _write_prelude(prelude: str, output: TextIO | None) -> None: + print(prelude) + print() + sys.stdout.flush() + if output is not None: + output.write(prelude + "\n\n") + output.flush() + + +def run_engine( + arguments: Sequence[str], prelude: str, output_path: Path | None +) -> int: + output: TextIO | None = None + try: + if output_path is not None: + output = output_path.open("w", encoding="utf-8") + _write_prelude(prelude, output) + process = subprocess.Popen( + [str(ENGINE_RUNNER), "__engine", *arguments], + stdout=subprocess.PIPE, + text=True, + ) + assert process.stdout is not None + for line in process.stdout: + sys.stdout.write(line) + sys.stdout.flush() + if output is not None: + output.write(line) + output.flush() + return process.wait() + except OSError as error: + raise ConfigurationError(f"cannot run ambiguity engine: {error}") from error + finally: + if output is not None: + output.close() + + +def list_profiles(profiles: dict[str, SearchProfile]) -> None: + width = max(map(len, profiles)) + print("Available ambiguity-search profiles:\n") + for name in sorted(profiles): + profile = profiles[name] + print(f" {name:<{width}} {profile.description}") + scheduling = ( + "breadth-first" + if profile.nodes_per_depth is None + else f"{profile.nodes_per_depth} nodes/depth" + ) + print( + f" {'':<{width}} {profile.min_tokens}..{profile.max_tokens} tokens, " + f"{format_duration(profile.timeout_seconds)}, " + f"{profile.witnesses} witnesses, {scheduling}" + ) + + +def main(argv: Sequence[str] | None = None) -> int: + cli = parser() + arguments = cli.parse_args(argv) + try: + if arguments.command == "check": + return run_engine( + ["--check-tokens", " ".join(arguments.tokens)], + "Exact ambiguity check", + None, + ) + + profiles = load_profiles(arguments.profiles_file) + if arguments.command == "profiles": + list_profiles(profiles) + return 0 + + if arguments.profile not in profiles: + available = ", ".join(sorted(profiles)) + raise ConfigurationError( + f"unknown profile {arguments.profile!r}; available: {available}" + ) + profile = apply_overrides(profiles[arguments.profile], arguments) + if arguments.command == "prove" and arguments.level < 1: + raise ConfigurationError("proof level must be at least 1") + proof_level = arguments.level if arguments.command == "prove" else None + action = ( + f"Proof level {proof_level}, concretization" + if proof_level is not None + else "Search" + ) + summary = profile_summary(profile, action) + if arguments.output is not None: + summary += f"\nReport: {arguments.output}" + engine_args = engine_arguments(profile, proof_level) + if arguments.dry_run: + print(summary) + print("\nEngine arguments:") + print(" " + shlex.join(engine_args)) + return 0 + return run_engine(engine_args, summary, arguments.output) + except ConfigurationError as error: + cli.error(str(error)) + return 2 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/ambiguity_search.ml b/tools/ambiguity_search.ml index 1bd801a3..3a5a4bd6 100644 --- a/tools/ambiguity_search.ml +++ b/tools/ambiguity_search.ml @@ -815,6 +815,14 @@ type outcome = { stopped : string option; } +type search_progress = { + depth : int; + ambiguities : ((int * string) list * int) list; + explored : int; + unique : int; + rss_bytes : float; +} + let () = Random.self_init () let rec temporary_directory () = @@ -913,12 +921,12 @@ module Seen_cache = struct (* Two independently seeded 62-bit lanes make colliding distinct frontiers astronomically unlikely even across billions of entries. A collision could only skip a frontier wrongly, never produce a false witness. *) - let digest branched frontier = + let digest branched progress frontier = let lane seed = IntMap.fold (fun stack_id count hash -> mix (mix hash stack_id) count) frontier - (mix seed (Bool.to_int branched)) + (mix (mix seed (Bool.to_int branched)) progress) in (lane 0x2545F4914F6CDD1D, lane 0x27220A95FE4D1D65) @@ -969,9 +977,102 @@ let managed_heap_bytes () = let stats = Gc.quick_stat () in float_of_int stats.heap_words *. float_of_int (Sys.word_size / 8) -let unified_search engine initial ~max_tokens ~timeout ~max_frontiers - ~max_queue ~max_witnesses ~soft_heap_bytes ~hard_heap_bytes - conflict_distance accept_distance = +let resident_memory_bytes () = + try + read_lines "/proc/self/status" + |> List.find_map (fun line -> + if String.starts_with ~prefix:"VmRSS:" line then + try Some (Scanf.sscanf line "VmRSS: %f kB" (fun kib -> kib *. 1024.)) + with _ -> None + else None) + |> Option.value ~default:(managed_heap_bytes ()) + with _ -> managed_heap_bytes () + +let progress_is_visible = Unix.isatty Unix.stderr + +let compact_number value = + let value = float_of_int value in + if value >= 1_000_000_000. then Printf.sprintf "%.1fB" (value /. 1_000_000_000.) + else if value >= 1_000_000. then Printf.sprintf "%.1fM" (value /. 1_000_000.) + else if value >= 1_000. then Printf.sprintf "%.1fk" (value /. 1_000.) + else Printf.sprintf "%.0f" value + +let memory_bar used budget = + let width = 12 in + let ratio = if budget <= 0. then 0. else min 1. (used /. budget) in + let filled = int_of_float (floor ((ratio *. float_of_int width) +. 0.5)) in + String.make filled '#' ^ String.make (width - filled) '-' + +let render_progress ~started ~max_tokens ~memory_budget + (entries : (bool * search_progress) list) = + if progress_is_visible && entries <> [] then begin + let has_active = List.exists fst entries in + let depth = + List.fold_left + (fun current + (is_active, (progress : search_progress)) -> + if has_active && not is_active then current + else max current progress.depth) + 0 entries + in + let profiles = Hashtbl.create 64 in + let explored = ref 0 in + let unique = ref 0 in + let rss_bytes = ref 0. in + List.iter + (fun (_, (progress : search_progress)) -> + explored := !explored + progress.explored; + unique := !unique + progress.unique; + rss_bytes := !rss_bytes +. progress.rss_bytes; + List.iter + (fun (profile, witness_depth) -> + match Hashtbl.find_opt profiles profile with + | Some previous when previous <= witness_depth -> () + | _ -> Hashtbl.replace profiles profile witness_depth) + progress.ambiguities) + entries; + let at_depth = + Hashtbl.fold + (fun _ witness_depth count -> + if witness_depth = depth then count + 1 else count) + profiles 0 + in + let elapsed = max 0. (Unix.gettimeofday () -. started) in + Printf.eprintf + "\r\027[2K● depth %d/%d | ambiguities@depth %d | %s explored | %s unique | RAM [%s] %.1f/%.1f GiB | %02d:%02d" + depth max_tokens at_depth (compact_number !explored) + (compact_number !unique) + (memory_bar !rss_bytes memory_budget) + (!rss_bytes /. 1024. /. 1024. /. 1024.) + (memory_budget /. 1024. /. 1024. /. 1024.) + (int_of_float elapsed / 60) (int_of_float elapsed mod 60); + flush stderr + end + +let clear_progress () = + if progress_is_visible then begin + Printf.eprintf "\r\027[2K"; + flush stderr + end + +let write_progress path (progress : search_progress) = + let temporary = path ^ ".new" in + let channel = open_out_bin temporary in + Marshal.to_channel channel progress []; + close_out channel; + Sys.rename temporary path + +let read_progress path : search_progress option = + try + let channel = open_in_bin path in + Fun.protect ~finally:(fun () -> close_in channel) (fun () -> + Some (Marshal.from_channel channel : search_progress)) + with Sys_error _ | End_of_file | Failure _ -> None + +let unified_search engine initial ~max_tokens ~min_tokens ~nodes_per_depth + ~timeout ~max_frontiers ~max_queue ~max_witnesses ~soft_heap_bytes + ~hard_heap_bytes ~show_progress ~on_progress conflict_distance + accept_distance = let deadline = Unix.gettimeofday () +. timeout in let buckets = Array.init (max_tokens + 1) (fun _ -> Queue.create ()) in let seen = Seen_cache.create max_frontiers in @@ -994,7 +1095,12 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers then enqueue item else if not !admit_new then dropped := true else - let key = Seen_cache.digest item.branched item.frontier in + (* Before [min_tokens], revisiting the same parser frontier at a + greater depth is useful rather than redundant: it can eventually + produce a witness long enough to report. Once the minimum is met, + the usual shortest-path deduplication applies. *) + let progress = min item.depth min_tokens in + let key = Seen_cache.digest item.branched progress item.frontier in match Seen_cache.find seen key with | Some depth when depth <= item.depth -> Seen_cache.refresh seen key depth @@ -1012,7 +1118,28 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers let conflict_seeds = ref 0 in let witnesses = Hashtbl.create max_witnesses in let stopped = ref None in - let depth = ref 0 in + let current_depth = ref 0 in + let expanded_at_depth = ref 0 in + let last_depth = ref 0 in + let last_progress = ref 0. in + let emit_progress force = + let now = Unix.gettimeofday () in + if show_progress && (force || now -. !last_progress >= 0.2) then begin + last_progress := now; + on_progress + { + depth = !last_depth; + ambiguities = + Hashtbl.fold + (fun profile tokens result -> + (profile, List.length tokens) :: result) + witnesses []; + explored = !explored; + unique = seen.Seen_cache.inserted; + rss_bytes = resident_memory_bytes (); + } + end + in (* The stack pool and closure cache also grow with the search; sweep them against the live queue on a geometric schedule so total memory stays proportional to the queue itself (the live set marked below), whose size @@ -1074,27 +1201,61 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers end end in + (* A quota forms a depth wave: expand a bounded number of siblings, descend + through their children, then return to the earliest unfinished siblings + when no deeper bucket remains. Nothing is discarded, so repeated waves + eventually cover the same frontiers as breadth-first search. *) + let first_nonempty start = + let depth = ref start in + while !depth <= max_tokens && Queue.is_empty buckets.(!depth) do + incr depth + done; + if !depth <= max_tokens then Some !depth else None + in + let next_bucket () = + match nodes_per_depth with + | None -> Option.get (first_nonempty 0) + | Some limit -> + let current_available = + !current_depth <= max_tokens + && not (Queue.is_empty buckets.(!current_depth)) + in + if (not current_available) || !expanded_at_depth >= limit then begin + let next = + match first_nonempty (!current_depth + 1) with + | Some depth -> depth + | None -> Option.get (first_nonempty 0) + in + current_depth := next; + expanded_at_depth := 0 + end; + incr expanded_at_depth; + !current_depth + in while Hashtbl.length witnesses < max_witnesses - && !depth <= max_tokens + && !queued > 0 && Unix.gettimeofday () < deadline do - if Queue.is_empty buckets.(!depth) then incr depth - else begin + let bucket = next_bucket () in + if bucket >= 0 && bucket <= max_tokens then begin maybe_compact_stacks (); if !admit_new then begin if !explored mod 4_096 = 0 then manage_memory () end else manage_memory (); - let item = Queue.take buckets.(!depth) in + let item = Queue.take buckets.(bucket) in decr queued; incr explored; + last_depth := item.depth; deepest := max !deepest item.depth; if accepted_count engine item.frontier >= 2 then begin - let tokens = List.rev item.tokens_rev in - let profile = conflict_profile engine tokens in - if not (Hashtbl.mem witnesses profile) then - Hashtbl.add witnesses profile tokens + if item.depth >= min_tokens then begin + let tokens = List.rev item.tokens_rev in + let profile = conflict_profile engine tokens in + if not (Hashtbl.mem witnesses profile) then + Hashtbl.add witnesses profile tokens + end end else if item.depth < max_tokens then StringSet.iter @@ -1118,8 +1279,10 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers } end) (possible_tokens engine item.frontier) - end + end; + emit_progress false done; + emit_progress true; if Unix.gettimeofday () >= deadline then stopped := Some "the timeout was reached" else if Hashtbl.length witnesses >= max_witnesses then @@ -1138,16 +1301,15 @@ let unified_search engine initial ~max_tokens ~timeout ~max_frontiers }, !conflict_seeds ) -let initial_partitions engine jobs max_tokens = - let root = IntMap.singleton engine.stacks.root.id 1 in - if jobs <= 1 || max_tokens = 0 then - ( [| [ { tokens_rev = []; depth = 0; frontier = root; branched = false } ] |], +let initial_partitions engine jobs max_tokens initial = + if jobs <= 1 || initial.depth = max_tokens then + ( [| [ initial ] |], 0, 0, 0 ) else begin - let split_depth = min 3 max_tokens in - let current = ref [ { tokens_rev = []; depth = 0; frontier = root; branched = false } ] in + let split_depth = min 3 (max_tokens - initial.depth) in + let current = ref [ initial ] in let explored = ref 0 in let unique = ref 1 in let conflict_seeds = ref 0 in @@ -1195,18 +1357,39 @@ let initial_partitions engine jobs max_tokens = (buckets, !explored, !unique, !conflict_seeds) end -let parallel_unified_search engine ~jobs ~max_tokens ~timeout ~max_frontiers - ~max_queue ~max_witnesses ~soft_heap_bytes ~hard_heap_bytes - conflict_distance accept_distance temporary = +let parallel_unified_search engine initial ~jobs ~max_tokens ~min_tokens + ~nodes_per_depth ~timeout ~max_frontiers ~max_queue ~max_witnesses + ~soft_heap_bytes ~hard_heap_bytes conflict_distance accept_distance + temporary = + let started = Unix.gettimeofday () in + let memory_budget = + hard_heap_bytes /. 0.90 *. float_of_int (max 1 jobs) + in let partitions, prefix_explored, prefix_unique, prefix_seeds = - initial_partitions engine (max 1 jobs) max_tokens + initial_partitions engine (max 1 jobs) max_tokens initial + in + let prefix_progress = + { + depth = initial.depth; + ambiguities = []; + explored = prefix_explored; + unique = prefix_unique; + rss_bytes = 0.; + } in if Array.length partitions = 1 then + let show progress = + render_progress ~started ~max_tokens ~memory_budget + [ (false, prefix_progress); (true, progress) ] + in let outcome, seeds = - unified_search engine partitions.(0) ~max_tokens ~timeout ~max_frontiers - ~max_queue ~max_witnesses ~soft_heap_bytes ~hard_heap_bytes - conflict_distance accept_distance + unified_search engine partitions.(0) ~max_tokens ~min_tokens + ~nodes_per_depth ~timeout ~max_frontiers ~max_queue ~max_witnesses + ~soft_heap_bytes ~hard_heap_bytes + ~show_progress:progress_is_visible ~on_progress:show conflict_distance + accept_distance in + clear_progress (); ( { outcome with explored = prefix_explored + outcome.explored; @@ -1224,39 +1407,107 @@ let parallel_unified_search engine ~jobs ~max_tokens ~timeout ~max_frontiers Array.iteri (fun index initial -> let output = Filename.concat temporary (Printf.sprintf "worker-%d" index) in + let progress_path = + Filename.concat temporary (Printf.sprintf "progress-%d" index) + in match Unix.fork () with | 0 -> + let report progress = + if progress_is_visible then write_progress progress_path progress + in let result = - unified_search engine initial ~max_tokens ~timeout ~max_frontiers - ~max_queue ~max_witnesses ~soft_heap_bytes ~hard_heap_bytes + unified_search engine initial ~max_tokens ~min_tokens + ~nodes_per_depth ~timeout ~max_frontiers ~max_queue + ~max_witnesses ~soft_heap_bytes ~hard_heap_bytes + ~show_progress:progress_is_visible ~on_progress:report conflict_distance accept_distance in let channel = open_out_bin output in Marshal.to_channel channel result []; close_out channel; exit 0 - | pid -> children := (pid, output) :: !children) + | pid -> children := (pid, output, progress_path) :: !children) partitions; - let outcomes = - List.map - (fun (pid, output) -> - let rec wait () = - try Unix.waitpid [] pid - with Unix.Unix_error (Unix.EINTR, _, _) -> wait () - in - match wait () with - | _, Unix.WEXITED 0 -> - let channel = open_in_bin output in - Fun.protect ~finally:(fun () -> close_in channel) (fun () -> - (Marshal.from_channel channel : outcome * int)) - | _, Unix.WEXITED code -> - failwith (Printf.sprintf "ambiguity-search worker %d exited with status %d" pid code) - | _, Unix.WSIGNALED signal -> - failwith (Printf.sprintf "ambiguity-search worker %d was killed by signal %d" pid signal) - | _, Unix.WSTOPPED signal -> - failwith (Printf.sprintf "ambiguity-search worker %d stopped on signal %d" pid signal)) - !children + let latest = Hashtbl.create (Array.length partitions) in + let worker_result pid output status = + match status with + | Unix.WEXITED 0 -> + let channel = open_in_bin output in + Fun.protect ~finally:(fun () -> close_in channel) (fun () -> + (Marshal.from_channel channel : outcome * int)) + | Unix.WEXITED code -> + failwith + (Printf.sprintf "ambiguity-search worker %d exited with status %d" + pid code) + | Unix.WSIGNALED signal -> + failwith + (Printf.sprintf "ambiguity-search worker %d was killed by signal %d" + pid signal) + | Unix.WSTOPPED signal -> + failwith + (Printf.sprintf "ambiguity-search worker %d stopped on signal %d" + pid signal) + in + let rec collect pending outcomes = + List.iter + (fun (pid, _, progress_path) -> + Option.iter + (fun progress -> Hashtbl.replace latest pid progress) + (read_progress progress_path)) + pending; + let active = Hashtbl.create (List.length pending) in + List.iter (fun (pid, _, _) -> Hashtbl.replace active pid ()) pending; + let entries = + (false, prefix_progress) + :: Hashtbl.fold + (fun pid progress result -> + (Hashtbl.mem active pid, progress) :: result) + latest [] + in + render_progress ~started ~max_tokens ~memory_budget entries; + match pending with + | [] -> List.rev outcomes + | _ -> + let remaining = ref [] in + let completed = ref [] in + List.iter + (fun ((pid, output, progress_path) as child) -> + let waited, status = + try Unix.waitpid [ Unix.WNOHANG ] pid + with Unix.Unix_error (Unix.EINTR, _, _) -> + (0, Unix.WEXITED 0) + in + if waited = 0 then remaining := child :: !remaining + else begin + let ((outcome, _) as result) = + worker_result pid output status + in + let final_progress = + Option.value (read_progress progress_path) + ~default: + { + depth = outcome.deepest; + ambiguities = + List.map + (fun (profile, tokens) -> + (profile, List.length tokens)) + outcome.witnesses; + explored = outcome.explored; + unique = outcome.unique; + rss_bytes = 0.; + } + in + Hashtbl.replace latest pid + { final_progress with rss_bytes = 0. }; + completed := result :: !completed + end) + pending; + if !completed = [] then + ignore (Unix.select [] [] [] 0.1); + collect (List.rev !remaining) (List.rev_append !completed outcomes) in + let outcomes = collect !children [] in + clear_progress (); let outcome, seeds = List.fold_left (fun (combined, seeds) (outcome, worker_seeds) -> ( { @@ -1305,6 +1556,9 @@ let environment_float name = let grammar = ref "" let max_tokens = ref None +let min_tokens = ref 0 +let prefix_tokens = ref [] +let nodes_per_depth = ref None let timeout = ref None let max_witnesses = ref None let check_tokens = ref [] @@ -1353,6 +1607,17 @@ let options = ( "--max-tokens", Arg.Int (fun value -> max_tokens := Some value), "N maximum tokens, including EOF (required for search/prove)" ); + ( "--min-tokens", + Arg.Set_int min_tokens, + "N minimum tokens for reported witnesses, including the prefix and EOF \ + (default 0)" ); + ( "--prefix-tokens", + Arg.String (fun value -> prefix_tokens := words value), + "TOKENS consume a space-separated token prefix before searching" ); + ( "--nodes-per-depth", + Arg.Int (fun value -> nodes_per_depth := Some value), + "N queued frontiers to expand at each depth before descending; omitted \ + for breadth-first search" ); ( "--timeout", Arg.Float (fun value -> timeout := Some value), "SECONDS time limit per search phase (required for search/prove)" ); @@ -1386,6 +1651,11 @@ let main () = (fun value -> if value < 0 then invalid_arg "--max-tokens must be at least 0") !max_tokens; + if !min_tokens < 0 then invalid_arg "--min-tokens must be at least 0"; + Option.iter + (fun value -> + if value < 1 then invalid_arg "--nodes-per-depth must be at least 1") + !nodes_per_depth; if memory_mb < 1 then invalid_arg "AMBIGUITY_MEMORY_MB must be at least 1"; if Float.is_nan max_frontier_ratio @@ -1441,6 +1711,27 @@ let main () = exit (if count >= 2 then 1 else 0) end; let max_tokens, timeout, max_witnesses = Option.get search_limits in + if !min_tokens > max_tokens then + invalid_arg "--min-tokens must not exceed --max-tokens"; + let prefix_depth = List.length !prefix_tokens in + if prefix_depth > max_tokens then + invalid_arg + "--prefix-tokens must not contain more tokens than --max-tokens"; + let initial_frontier = + List.fold_left (shift engine) + (IntMap.singleton engine.stacks.root.id 1) + !prefix_tokens + in + if IntMap.is_empty initial_frontier then + invalid_arg "--prefix-tokens is not a valid grammar prefix"; + let initial = + { + tokens_rev = List.rev !prefix_tokens; + depth = prefix_depth; + frontier = initial_frontier; + branched = derivations initial_frontier >= 2; + } + in let memory_limits = derive_memory_limits ~memory_mb ~max_frontier_ratio ~jobs ~max_tokens in @@ -1451,6 +1742,15 @@ let main () = (memory_limits.hard_heap_bytes /. 1024. /. 1024.) memory_limits.max_queue memory_limits.max_frontiers max_frontier_ratio; + Printf.printf + "Search constraints: %d..%d total tokens; %d-token prefix; %s.\n" + !min_tokens max_tokens prefix_depth + (match !nodes_per_depth with + | None -> "breadth-first scheduling" + | Some 1 -> "1 node per depth" + | Some limit -> Printf.sprintf "%d nodes per depth" limit); + if !prefix_tokens <> [] then + Printf.printf "Prefix tokens: %s\n" (String.concat " " !prefix_tokens); if !prove_level > 0 then begin match prove engine !prove_level memory_limits.max_frontiers with | Proven pairs -> @@ -1485,7 +1785,8 @@ let main () = in let accept_distance = reverse_distances automaton accept_targets in let outcome, conflict_seeds = - parallel_unified_search engine ~jobs ~max_tokens ~timeout + parallel_unified_search engine initial ~jobs ~max_tokens + ~min_tokens:!min_tokens ~nodes_per_depth:!nodes_per_depth ~timeout ~max_frontiers:memory_limits.max_frontiers ~max_queue:memory_limits.max_queue ~max_witnesses ~soft_heap_bytes:memory_limits.soft_heap_bytes @@ -1497,8 +1798,8 @@ let main () = (match outcome.stopped with | None -> Printf.printf - "No complete ambiguity found through %d tokens after exploring %d frontiers (%d unique).\n" - max_tokens outcome.explored outcome.unique + "No complete ambiguity satisfying the search constraints was found after exploring %d frontiers (%d unique).\n" + outcome.explored outcome.unique | Some reason -> Printf.printf "Search stopped at depth %d because %s; no complete ambiguity was found in %d explored frontiers (%d unique).\n" @@ -1542,5 +1843,6 @@ let () = with | Failure message | Invalid_argument message | Sys_error message | Unix.Unix_error (_, _, message) -> + clear_progress (); prerr_endline ("error: " ^ message); exit 2 diff --git a/tools/syntax_experiments.py b/tools/syntax_experiment.py similarity index 99% rename from tools/syntax_experiments.py rename to tools/syntax_experiment.py index f23a9a8d..b927cb75 100644 --- a/tools/syntax_experiments.py +++ b/tools/syntax_experiment.py @@ -713,7 +713,7 @@ def apply_variant(source: str, variant: Variant) -> str: for name in variant.transforms: result = TRANSFORMS[name](result) header = ( - "(* Generated by tools/syntax_experiments.py.\n" + "(* Generated by tools/syntax_experiment.py.\n" f" Variant: {variant.name}\n" f" Transformations: {', '.join(variant.transforms) or 'none'} *)\n" ) @@ -980,7 +980,7 @@ def parser() -> argparse.ArgumentParser: result.add_argument( "--output", type=Path, - default=Path("_build/syntax-experiments/report"), + default=Path("_build/syntax-experiment/report"), help="report path without extension", ) return result diff --git a/tools/test_ambiguity.py b/tools/test_ambiguity.py new file mode 100644 index 00000000..a1c4f096 --- /dev/null +++ b/tools/test_ambiguity.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +import argparse +from pathlib import Path +from tempfile import TemporaryDirectory +import unittest + +from tools import ambiguity + + +class ValueParsingTests(unittest.TestCase): + def test_token_range_accepts_whitespace(self) -> None: + self.assertEqual(ambiguity.parse_token_range(" 12 .. 50 "), (12, 50)) + + def test_token_range_rejects_a_descending_range(self) -> None: + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "minimum must not exceed" + ): + ambiguity.parse_token_range("50..12") + + def test_duration_accepts_friendly_and_composed_units(self) -> None: + self.assertEqual(ambiguity.parse_duration("1h30m"), 5400) + self.assertEqual(ambiguity.parse_duration("250ms"), 0.25) + self.assertEqual(ambiguity.parse_duration(90), 90) + + def test_duration_rejects_trailing_text(self) -> None: + with self.assertRaisesRegex(ambiguity.ConfigurationError, "invalid duration"): + ambiguity.parse_duration("30 minutes") + + +class ProfileTests(unittest.TestCase): + def write_profiles(self, contents: str) -> Path: + directory = TemporaryDirectory() + self.addCleanup(directory.cleanup) + path = Path(directory.name) / "searches.toml" + path.write_text(contents, encoding="utf-8") + return path + + def test_inheritance_and_overrides(self) -> None: + path = self.write_profiles( + """ +[profiles.base] +description = "Broad search." +tokens = "0..20" +timeout = "2m" +witnesses = 10 + +[profiles.deep] +extends = "base" +tokens = "12..50" +prefix_tokens = ["UIDENT", "LCURLY"] +nodes_per_depth = 4 +""" + ) + profile = ambiguity.load_profiles(path)["deep"] + self.assertEqual(profile.description, "Broad search.") + self.assertEqual((profile.min_tokens, profile.max_tokens), (12, 50)) + self.assertEqual(profile.timeout_seconds, 120) + self.assertEqual(profile.prefix_tokens, ("UIDENT", "LCURLY")) + self.assertEqual(profile.nodes_per_depth, 4) + + arguments = argparse.Namespace( + token_range="10..30", + timeout="1h", + witnesses=25, + prefix_tokens="UIDENT LIDENT", + nodes_per_depth=None, + breadth_first=True, + ) + overridden = ambiguity.apply_overrides(profile, arguments) + self.assertEqual((overridden.min_tokens, overridden.max_tokens), (10, 30)) + self.assertEqual(overridden.timeout_seconds, 3600) + self.assertEqual(overridden.witnesses, 25) + self.assertEqual(overridden.prefix_tokens, ("UIDENT", "LIDENT")) + self.assertIsNone(overridden.nodes_per_depth) + + def test_inheritance_cycle_is_reported(self) -> None: + path = self.write_profiles( + """ +[profiles.one] +extends = "two" + +[profiles.two] +extends = "one" +""" + ) + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "one -> two -> one" + ): + ambiguity.load_profiles(path) + + def test_unknown_setting_is_reported(self) -> None: + path = self.write_profiles( + """ +[profiles.quick] +tokens = "0..10" +timeout = "1m" +witnesses = 5 +surprise = true +""" + ) + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "unknown settings: surprise" + ): + ambiguity.load_profiles(path) + + +class CommandLineTests(unittest.TestCase): + def test_search_defaults_to_general(self) -> None: + arguments = ambiguity.parser().parse_args(["search"]) + self.assertEqual(arguments.profile, "general") + + def test_prove_defaults_to_quick(self) -> None: + arguments = ambiguity.parser().parse_args(["prove", "3"]) + self.assertEqual(arguments.profile, "quick") + + def test_check_accepts_quoted_or_individual_tokens(self) -> None: + cli = ambiguity.parser() + quoted = cli.parse_args(["check", "UIDENT LPAREN RPAREN EOF"]) + separate = cli.parse_args( + ["check", "UIDENT", "LPAREN", "RPAREN", "EOF"] + ) + self.assertEqual(" ".join(quoted.tokens), " ".join(separate.tokens)) + + def test_engine_arguments_are_stable_and_low_level(self) -> None: + profile = ambiguity.SearchProfile( + name="deep", + description="", + min_tokens=12, + max_tokens=50, + timeout_seconds=1800, + witnesses=50, + prefix_tokens=("UIDENT", "LCURLY"), + nodes_per_depth=10, + ) + self.assertEqual( + ambiguity.engine_arguments(profile), + [ + "--max-tokens", + "50", + "--min-tokens", + "12", + "--timeout", + "1800", + "--max-witnesses", + "50", + "--prefix-tokens", + "UIDENT LCURLY", + "--nodes-per-depth", + "10", + ], + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tools/test_syntax_experiments.py b/tools/test_syntax_experiment.py similarity index 99% rename from tools/test_syntax_experiments.py rename to tools/test_syntax_experiment.py index 165f7e71..246431ff 100644 --- a/tools/test_syntax_experiments.py +++ b/tools/test_syntax_experiment.py @@ -2,7 +2,7 @@ import unittest from pathlib import Path -from tools import syntax_experiments as experiments +from tools import syntax_experiment as experiments class SyntaxExperimentTests(unittest.TestCase): From 3874982c27fe2a3a315c21302e40390171f67e1d Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Fri, 24 Jul 2026 12:09:45 +0200 Subject: [PATCH 149/154] Optimize ambiguity search with terminal equivalence classes (#45) * ambiguity: search by terminal equivalence class, not per token The bounded search branched on every terminal at each frontier, so interchangeable tokens (STRING/FLOAT/TRUE/FALSE as a primary, +/- as an operator, ...) each spawned a full isomorphic subtree that only reconverged after the token reduced to a nonterminal. The dedup cache could not collapse them because their post-shift frontiers sit on distinct LR states. Compute terminal equivalence classes up front: a two-step partition refinement (a state bisimulation over recognition behaviour, then a grouping of terminals by their per-state action up to that partition) puts two terminals in one class exactly when swapping them is an automorphism of the recognition relation. The search, the parallel split, and the prover then explore one representative per class. Because class members generate isomorphic parse forests, an ambiguous sentence exists with one iff it exists with every member, so a completed bound remains a theorem up to renaming terminals within their class and no obligation is lost. On the current grammar this collapses 56 terminals to 45 classes and roughly halves the frontiers explored at a given depth; exhaustive runs agree with the previous behaviour up to the representative substitution. Add `ambiguity classes` (engine flag --dump-terminal-classes) to list the classes, and document the change. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01NkitqNXZZsXuEKfwK3ajMc * ambiguity: test the prove path through a non-representative terminal Add an engine-level regression test for the terminal equivalence-class machinery, per CodeRabbit review on #45. A tiny ambiguous grammar with two interchangeable atoms A and B (one class, A as representative) checks that: the class is detected, an all-B sentence is still recognized as ambiguous even though the search only ever shifts A, and prove concretizes the ambiguity via the representative. Skips when the engine binary or menhir is unavailable so the pure-Python suite still runs without the OCaml toolchain. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01NkitqNXZZsXuEKfwK3ajMc * ambiguity: harden the terminal-class engine tests Address CodeRabbit review on #45: give the engine subprocess a process-level timeout so a hung binary or menhir cannot block the suite, and assert the prove witness is spelled with the class representative A (never the non-representative B) so the test would catch concretization drifting off representatives. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01NkitqNXZZsXuEKfwK3ajMc --------- Co-authored-by: Claude --- docs/ambiguity.md | 20 ++++ tools/ambiguity.py | 11 +++ tools/ambiguity_search.ml | 191 +++++++++++++++++++++++++++++++++++++- tools/test_ambiguity.py | 101 ++++++++++++++++++++ 4 files changed, 318 insertions(+), 5 deletions(-) diff --git a/docs/ambiguity.md b/docs/ambiguity.md index 4fc40b6e..64b9c45d 100644 --- a/docs/ambiguity.md +++ b/docs/ambiguity.md @@ -80,6 +80,23 @@ the state is triaged into one of these categories. the prefix and `EOF`. Witnesses are grouped by the conflict states they traverse, which maps each finding directly onto an obligation above. + Before searching, the tool computes **terminal equivalence classes**: + terminals that behave identically throughout the LR automaton — the same + shifts (up to a state bisimulation), the same reductions as a lookahead, and + the same acceptance — are interchangeable, so swapping one for another is an + automorphism of the recognition relation. The search explores a single + representative per class instead of every interchangeable token, which cuts + the branching factor wherever a construct admits several equivalent terminals + (for the current grammar, the value atoms `FALSE`/`FLOAT`/`STRING`/`TRUE` + collapse to one class, as do same-precedence operator groups such as + `+`/`-` and `*`/`/`). Precedence and associativity are already resolved in + the automaton's concrete actions, so tokens with different precedence never + share a class; and a token that reaches a context the others do not — `INT`, + which is also a const-generic argument — stays in its own class. Because + class members generate isomorphic parse forests, a completed bound is a + theorem up to renaming terminals within their class: an ambiguous sentence + exists with one member iff it exists with every member, so no obligation is + lost. Witnesses render with the representative terminal. - `ambiguity prove K [PROFILE]` — conservative unambiguity proof mode built into the ambiguity search. It abstracts GLR stacks to their top-K states and exhaustively explores pairs of abstract parses of the same input, comparing @@ -93,6 +110,9 @@ the state is triaged into one of these categories. never be eliminated entirely; the prover is validated against known-ambiguous grammars, LR(1) grammars, precedence-resolved expression grammars, and unambiguous non-LR grammars such as palindromes. +- `ambiguity classes` — lists the terminal equivalence classes the search + collapses, so a grammar change that unexpectedly splits or merges a class is + visible. The same classes bound the prover's terminal alphabet. - `syntax-experiment` — compares candidate grammar changes under equal search bounds before they are adopted (`tools/SYNTAX_EXPERIMENT.md`). diff --git a/tools/ambiguity.py b/tools/ambiguity.py index a2198177..28654936 100644 --- a/tools/ambiguity.py +++ b/tools/ambiguity.py @@ -364,6 +364,10 @@ def parser() -> argparse.ArgumentParser: add_overrides(prove) commands.add_parser("profiles", help="list available search profiles") + commands.add_parser( + "classes", + help="list the terminal equivalence classes the search collapses", + ) return result @@ -433,6 +437,13 @@ def main(argv: Sequence[str] | None = None) -> int: None, ) + if arguments.command == "classes": + return run_engine( + ["--dump-terminal-classes"], + "Terminal equivalence classes", + None, + ) + profiles = load_profiles(arguments.profiles_file) if arguments.command == "profiles": list_profiles(profiles) diff --git a/tools/ambiguity_search.ml b/tools/ambiguity_search.ml index 3a5a4bd6..63a04934 100644 --- a/tools/ambiguity_search.ml +++ b/tools/ambiguity_search.ml @@ -21,6 +21,11 @@ type automaton = { states : state array; terminals : StringSet.t; aliases : (string, string) Hashtbl.t; + (* Terminals that behave identically everywhere in the automaton share a + class id. Two terminals are in one class when swapping them is an + automorphism of the recognition relation, so the search only needs to try + one representative per class instead of every interchangeable token. *) + terminal_class : (string, int) Hashtbl.t; } let empty_state () = @@ -195,6 +200,145 @@ let prepare_automaton ~menhir ~grammar ~directory = end; automaton +(* Terminal equivalence classes. + + Two terminals are interchangeable when replacing every occurrence of one by + the other is an automorphism of the recognition relation: they shift to + equivalent states, trigger the same reductions as a lookahead, and are + accepted in the same places. Interchangeable terminals generate isomorphic + parse forests, so an ambiguous sentence exists with one iff it exists with + the other; the search may therefore explore a single representative per + class. Because precedence and associativity are already baked into the + automaton's concrete shift/reduce actions, tokens with different precedence + land in different classes automatically. + + Equivalence is computed in two steps. First a partition refinement over the + states (a bisimulation on recognition behaviour: shift-target blocks, + reduction (lhs, width) sets, nonterminal goto-target blocks, and accepts) + collapses states that differ only in which production they carry - so + [primary -> INT], [primary -> FLOAT] and [primary -> STRING] states become + one block. Then terminals are grouped by their action across every state, + comparing shift targets up to that state partition. This is why FLOAT and + STRING merge even though they shift to distinct states, while INT stays + separate: it is also valid as a const generic argument, a context the other + two never reach. *) +let compute_terminal_classes states terminals = + let count = Array.length states in + let terminal_list = StringSet.elements terminals in + (* "#" is the end marker; it is never shifted but does drive reductions and + acceptance, so it participates in the lookahead-role signatures. *) + let lookaheads = "#" :: terminal_list in + let reduce_signature state token = + match Hashtbl.find_opt state.reductions token with + | None -> [] + | Some reductions -> + List.sort_uniq compare + (List.map (fun reduction -> (reduction.lhs, reduction.width)) reductions) + in + let shift_target state token = + if StringSet.mem token terminals then Hashtbl.find_opt state.transitions token + else None + in + let goto_targets state = + Hashtbl.fold + (fun symbol target result -> + if StringSet.mem symbol terminals then result + else (symbol, target) :: result) + state.transitions [] + |> List.sort compare + in + let block = Array.make (max 1 count) 0 in + let state_signature index = + let state = states.(index) in + let shifts = + List.map + (fun token -> + match shift_target state token with + | Some target -> Some block.(target) + | None -> None) + terminal_list + in + let reduces = List.map (reduce_signature state) lookaheads in + let accepts = + List.map (fun token -> StringSet.mem token state.accepts) lookaheads + in + let gotos = + List.map (fun (symbol, target) -> (symbol, block.(target))) (goto_targets state) + in + (shifts, reduces, accepts, gotos) + in + (* One refinement pass. Keying by the previous block keeps the partition + monotonically finer, so the block count never decreases and the loop + below terminates once it stabilizes. *) + let refine () = + let table = Hashtbl.create 1024 in + let fresh = ref 0 in + let updated = Array.make (max 1 count) 0 in + for index = 0 to count - 1 do + let key = (block.(index), state_signature index) in + match Hashtbl.find_opt table key with + | Some id -> updated.(index) <- id + | None -> + let id = !fresh in + incr fresh; + Hashtbl.add table key id; + updated.(index) <- id + done; + Array.blit updated 0 block 0 count; + !fresh + in + let previous = ref (-1) in + let blocks = ref (refine ()) in + while !blocks <> !previous do + previous := !blocks; + blocks := refine () + done; + let terminal_signature token = + List.init count (fun index -> + let state = states.(index) in + let shift = + match shift_target state token with + | Some target -> Some block.(target) + | None -> None + in + (shift, reduce_signature state token, StringSet.mem token state.accepts)) + in + let signatures = Hashtbl.create 64 in + let terminal_class = Hashtbl.create 64 in + let fresh = ref 0 in + List.iter + (fun token -> + let key = terminal_signature token in + let id = + match Hashtbl.find_opt signatures key with + | Some id -> id + | None -> + let id = !fresh in + incr fresh; + Hashtbl.add signatures key id; + id + in + Hashtbl.add terminal_class token id) + terminal_list; + terminal_class + +(* Keep one terminal per class - the alphabetically first, for reproducible + witnesses - so interchangeable tokens are explored once. A class is either + wholly present in a frontier's possible tokens or wholly absent (its members + act identically in every state), so picking representatives never drops a + reachable token. *) +let class_representatives automaton tokens = + let seen = Hashtbl.create 32 in + StringSet.fold + (fun token result -> + match Hashtbl.find_opt automaton.terminal_class token with + | Some id when Hashtbl.mem seen id -> result + | Some id -> + Hashtbl.add seen id (); + StringSet.add token result + | None -> StringSet.add token result) + tokens StringSet.empty + let state_re = Str.regexp "^State \\([0-9]+\\):$" let transition_re = Str.regexp "^-- On \\([^ ]+\\) shift to state \\([0-9]+\\)$" @@ -270,7 +414,8 @@ let parse_automaton path terminals aliases = (read_lines path); let maximum = Hashtbl.fold (fun number _ value -> max number value) table 0 in let states = Array.init (maximum + 1) (fun number -> get_state number) in - { states; terminals; aliases } + let terminal_class = compute_terminal_classes states terminals in + { states; terminals; aliases; terminal_class } module Stack_pool = struct type node = { @@ -782,7 +927,12 @@ let prove engine limit pair_limit = | None -> [] | Some (token, parent) -> token :: trail parent in - let terminals = StringSet.elements automaton.terminals in + (* One representative per terminal class: interchangeable lookaheads drive + the same abstract reduction chains, so exploring one covers the class and + shrinks the abstract pair space by the same factor as the search. *) + let terminals = + StringSet.elements (class_representatives automaton automaton.terminals) + in push None ([ 0 ], [ 0 ], false); while (not (Queue.is_empty queue)) && !candidate = None && not !overflow do let (left, right, diverged) as node = Queue.take queue in @@ -1278,7 +1428,8 @@ let unified_search engine initial ~max_tokens ~min_tokens ~nodes_per_depth branched; } end) - (possible_tokens engine item.frontier) + (class_representatives engine.automaton + (possible_tokens engine item.frontier)) end; emit_progress false done; @@ -1342,7 +1493,8 @@ let initial_partitions engine jobs max_tokens initial = next := item :: !next end end) - (possible_tokens engine item.frontier)) + (class_representatives engine.automaton + (possible_tokens engine item.frontier))) !current; unique := !unique + Hashtbl.length seen; current := !next @@ -1563,6 +1715,7 @@ let timeout = ref None let max_witnesses = ref None let check_tokens = ref [] let prove_level = ref 0 +let dump_classes = ref false type memory_limits = { max_queue : int; @@ -1632,6 +1785,9 @@ let options = "K attempt an unambiguity proof with a top-K stack abstraction; \ exit 0 proven unambiguous, 1 ambiguous, 3 not proven \ (the derived dedup-frontier limit also bounds the abstract pair count)" ); + ( "--dump-terminal-classes", + Arg.Set dump_classes, + " list the terminal equivalence classes the search collapses, then exit" ); ] let main () = @@ -1674,7 +1830,7 @@ let main () = if value < 1 then invalid_arg "--max-witnesses must be at least 1") !max_witnesses; let search_limits = - if !check_tokens <> [] then None + if !check_tokens <> [] || !dump_classes then None else let required name = function | Some value -> value @@ -1700,6 +1856,31 @@ let main () = let engine = { automaton; stacks; closure_cache = Hashtbl.create 16_384 } in + if !dump_classes then begin + let members = Hashtbl.create 64 in + Hashtbl.iter + (fun token id -> + Hashtbl.replace members id + (token :: Option.value (Hashtbl.find_opt members id) ~default:[])) + automaton.terminal_class; + let classes = + Hashtbl.fold (fun _ tokens result -> List.sort compare tokens :: result) + members [] + |> List.sort compare + in + let singletons = List.filter (fun tokens -> List.length tokens = 1) classes in + let merged = List.filter (fun tokens -> List.length tokens > 1) classes in + Printf.printf "%d terminals in %d classes (%d merged, %d singleton).\n" + (StringSet.cardinal automaton.terminals) + (List.length classes) (List.length merged) (List.length singletons); + List.iter + (fun tokens -> Printf.printf " { %s }\n" (String.concat " " tokens)) + merged; + if singletons <> [] then + Printf.printf " singletons: %s\n" + (String.concat " " (List.concat singletons)); + exit 0 + end; if !check_tokens <> [] then begin let frontier = List.fold_left (shift engine) diff --git a/tools/test_ambiguity.py b/tools/test_ambiguity.py index a1c4f096..97aedcac 100644 --- a/tools/test_ambiguity.py +++ b/tools/test_ambiguity.py @@ -1,11 +1,49 @@ #!/usr/bin/env python3 import argparse +import os +import shutil +import subprocess from pathlib import Path from tempfile import TemporaryDirectory import unittest from tools import ambiguity +ROOT = Path(__file__).resolve().parents[1] +ENGINE = ROOT / "_build" / "default" / "tools" / "ambiguity_search.exe" + +# A minimal grammar whose two atoms A and B are interchangeable (both reduce to +# [e] in the same contexts) so they collapse into one terminal class, while the +# unparenthesized [e PLUS e] rule is genuinely ambiguous. It exercises the +# equivalence-class machinery on a grammar small enough for the prover to finish +# instantly. +TINY_GRAMMAR = """\ +%token A "a" +%token B "b" +%token PLUS "+" +%token EOF "" +%start main +%% +main: e EOF { () } +e: + | A { () } + | B { () } + | e PLUS e { () } +""" + + +def engine_environment() -> dict[str, str] | None: + menhir = os.environ.get("AMBIGUITY_MENHIR") or shutil.which("menhir") + if not ENGINE.exists() or menhir is None: + return None + return { + **os.environ, + "AMBIGUITY_MENHIR": menhir, + "AMBIGUITY_MEMORY_MB": "64", + "AMBIGUITY_MAX_FRONTIER_RATIO": "1.0", + "AMBIGUITY_JOBS": "1", + } + class ValueParsingTests(unittest.TestCase): def test_token_range_accepts_whitespace(self) -> None: @@ -151,5 +189,68 @@ def test_engine_arguments_are_stable_and_low_level(self) -> None: ) +class TerminalClassEngineTests(unittest.TestCase): + """End-to-end checks that the search collapses interchangeable terminals + without losing an ambiguity reachable only through a non-representative + member. Skipped when the engine binary or menhir is unavailable, so the + otherwise pure-Python suite still runs without the OCaml toolchain.""" + + def setUp(self) -> None: + self.environment = engine_environment() + if self.environment is None: + self.skipTest( + "requires a built _build/default/tools/ambiguity_search.exe and menhir" + ) + directory = TemporaryDirectory() + self.addCleanup(directory.cleanup) + self.grammar = Path(directory.name) / "tiny.mly" + self.grammar.write_text(TINY_GRAMMAR, encoding="utf-8") + + def engine(self, *arguments: str) -> subprocess.CompletedProcess[str]: + # --timeout only bounds the engine's own search; a process-level timeout + # keeps a hung binary or menhir from blocking the whole suite. + return subprocess.run( + [str(ENGINE), *arguments, str(self.grammar)], + env=self.environment, + text=True, + capture_output=True, + timeout=120, + ) + + def test_interchangeable_atoms_share_one_class(self) -> None: + result = self.engine("--dump-terminal-classes") + self.assertIn("{ A B }", result.stdout) + + def test_ambiguity_holds_through_a_non_representative_member(self) -> None: + # B is not the class representative (A sorts first), so the search never + # shifts it directly; the all-B sentence must still be recognized as + # ambiguous, confirming the representative stands in for the whole class. + result = self.engine("--check-tokens", "B PLUS B PLUS B EOF") + self.assertIn("Accepting derivations: 2", result.stdout) + self.assertEqual(result.returncode, 1) + + def test_prove_finds_the_ambiguity_via_the_representative(self) -> None: + # prove drives the abstract BFS over class representatives, then + # concretizes; it must surface the e-PLUS-e ambiguity even though every + # witness is spelled with the representative atom. + result = self.engine( + "--prove", "2", + "--max-tokens", "8", + "--timeout", "30", + "--max-witnesses", "5", + ) + self.assertEqual(result.returncode, 1, result.stdout) + self.assertIn("complete ambiguity", result.stdout) + # The witness must be spelled with the class representative A, never the + # non-representative B, confirming concretization stays on representatives. + witnesses = [ + line for line in result.stdout.splitlines() if "Tokens (" in line + ] + self.assertTrue(witnesses, result.stdout) + tokens = witnesses[0].split(":", 1)[1].split() + self.assertIn("A", tokens) + self.assertNotIn("B", tokens) + + if __name__ == "__main__": unittest.main() From 5daad2e0bb5a27e1458b8da563c4e88d0212aa7d Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Fri, 24 Jul 2026 17:43:30 +0200 Subject: [PATCH 150/154] Add placeholder expansion for --output path patterns (#46) * Support placeholder patterns in ambiguity-search --output The --output path now accepts $profile, $date, $time, and $datetime placeholders (shell/string.Template syntax, $$ for a literal dollar), so a report can be saved to e.g. reports/$profile-$date.txt without a manual mkdir. The timestamp layout matches the existing reports/ filenames, and any missing directories in the expanded path are created. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Q3hXqkaob2JQDV4yfHTqom * Use brace placeholders for ambiguity-search --output patterns Switch the --output template from $name to {name} brace syntax ({profile}, {date}, {time}, {datetime}). Braces avoid the shell's $ expansion, so patterns work without quoting, and {{ / }} give literal braces. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Q3hXqkaob2JQDV4yfHTqom * Reject non-bare --output placeholders and fix docs wording Parse the --output pattern with string.Formatter instead of str.format_map so only the four bare names expand. This closes two holes format_map left open: {profile[0]} silently expanded to a wrong path, and {profile.foo} raised an uncaught AttributeError instead of a ConfigurationError. Both, plus stray format specs, now report a clear error. Also reword the docs to stop implying a literal {name} placeholder. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Q3hXqkaob2JQDV4yfHTqom --------- Co-authored-by: Claude --- docs/ambiguity.md | 7 +++++ tools/ambiguity.py | 64 ++++++++++++++++++++++++++++++++++++++--- tools/test_ambiguity.py | 61 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 4 deletions(-) diff --git a/docs/ambiguity.md b/docs/ambiguity.md index 64b9c45d..84b0e675 100644 --- a/docs/ambiguity.md +++ b/docs/ambiguity.md @@ -136,6 +136,13 @@ Friendly durations such as `90s`, `30m`, and `1h` are accepted. Add `--output report.txt` to display and save a report, or `--dry-run` to inspect the resolved settings without building the engine. +The `--output` path may contain placeholders that are filled in when the run +starts: `{profile}` is the resolved profile name, and `{date}`, `{time}`, and +`{datetime}` are timestamps laid out like the existing `reports/` filenames (`2026-07-23`, `21-38-17`, and `2026-07-23_21-38-17`). Any +directories in the expanded path are created automatically, so +`--output reports/{profile}-{date}.txt` drops a dated report into `reports/` +without a manual `mkdir`. Write `{{` and `}}` for literal braces. + To concentrate a run inside a function body and favor depth over breadth: ```sh diff --git a/tools/ambiguity.py b/tools/ambiguity.py index 28654936..69d2bf88 100644 --- a/tools/ambiguity.py +++ b/tools/ambiguity.py @@ -5,9 +5,11 @@ import argparse from dataclasses import dataclass, replace +import datetime from pathlib import Path import re import shlex +import string import subprocess import sys import tomllib @@ -95,6 +97,52 @@ def format_duration(seconds: float) -> str: return f"{seconds:g}s" +def expand_output_path(pattern: Path, profile_name: str) -> Path: + """Substitute report-naming placeholders in an --output pattern. + + Placeholders use brace syntax: ``{name}``, with ``{{`` and ``}}`` for + literal braces. The supported names are ``profile`` and three timestamp + forms whose date and time layout matches the existing ``reports/`` + filenames (e.g. ``2026-07-23_21-38-17``).""" + now = datetime.datetime.now() + fields = { + "profile": profile_name, + "date": now.strftime("%Y-%m-%d"), + "time": now.strftime("%H-%M-%S"), + "datetime": now.strftime("%Y-%m-%d_%H-%M-%S"), + } + available = ", ".join("{" + name + "}" for name in fields) + text = str(pattern) + # Expand only bare `{name}` placeholders. Parsing the pattern ourselves — + # rather than str.format_map — keeps indexed or attribute forms such as + # {profile[0]} or {profile.foo} out: format_map would silently expand the + # former to a wrong path and raise an uncaught AttributeError on the latter. + try: + parsed = list(string.Formatter().parse(text)) + except ValueError as error: + raise ConfigurationError( + f"invalid --output pattern {text!r}: {error}; " + "write {{ and }} for literal braces" + ) from error + result: list[str] = [] + for literal, field, spec, conversion in parsed: + result.append(literal) + if field is None: + continue + if field not in fields: + raise ConfigurationError( + f"unknown placeholder {{{field}}} in --output pattern " + f"{text!r}; available placeholders are {available}" + ) + if spec or conversion: + raise ConfigurationError( + f"--output placeholder {{{field}}} takes no format spec or " + f"conversion in pattern {text!r}" + ) + result.append(fields[field]) + return Path("".join(result)) + + def _profile_tables(path: Path) -> dict[str, dict[str, Any]]: try: with path.open("rb") as source: @@ -308,7 +356,9 @@ def add_overrides(command: argparse.ArgumentParser) -> None: "--output", type=Path, metavar="FILE", - help="write the complete report to FILE while also displaying it", + help="write the complete report to FILE while also displaying it; " + "{profile}, {date}, {time}, and {datetime} expand in the path " + "(e.g. reports/{profile}-{date}.txt), and missing directories are created", ) command.add_argument( "--dry-run", @@ -386,6 +436,7 @@ def run_engine( output: TextIO | None = None try: if output_path is not None: + output_path.parent.mkdir(parents=True, exist_ok=True) output = output_path.open("w", encoding="utf-8") _write_prelude(prelude, output) process = subprocess.Popen( @@ -463,16 +514,21 @@ def main(argv: Sequence[str] | None = None) -> int: if proof_level is not None else "Search" ) + output_path = ( + None + if arguments.output is None + else expand_output_path(arguments.output, profile.name) + ) summary = profile_summary(profile, action) - if arguments.output is not None: - summary += f"\nReport: {arguments.output}" + if output_path is not None: + summary += f"\nReport: {output_path}" engine_args = engine_arguments(profile, proof_level) if arguments.dry_run: print(summary) print("\nEngine arguments:") print(" " + shlex.join(engine_args)) return 0 - return run_engine(engine_args, summary, arguments.output) + return run_engine(engine_args, summary, output_path) except ConfigurationError as error: cli.error(str(error)) return 2 diff --git a/tools/test_ambiguity.py b/tools/test_ambiguity.py index 97aedcac..b935f1b6 100644 --- a/tools/test_ambiguity.py +++ b/tools/test_ambiguity.py @@ -142,6 +142,67 @@ def test_unknown_setting_is_reported(self) -> None: ambiguity.load_profiles(path) +class OutputPatternTests(unittest.TestCase): + def test_profile_and_date_placeholders_expand(self) -> None: + path = ambiguity.expand_output_path( + Path("reports/{profile}-{date}.txt"), "general" + ) + self.assertRegex(str(path), r"^reports/general-\d{4}-\d{2}-\d{2}\.txt$") + + def test_timestamp_placeholders_expand(self) -> None: + path = ambiguity.expand_output_path( + Path("{profile}_{datetime}--{time}"), "deep" + ) + self.assertRegex( + str(path), + r"^deep_\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}--\d{2}-\d{2}-\d{2}$", + ) + + def test_plain_path_is_unchanged(self) -> None: + self.assertEqual( + ambiguity.expand_output_path(Path("report.txt"), "general"), + Path("report.txt"), + ) + + def test_unknown_placeholder_is_reported(self) -> None: + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "unknown placeholder" + ): + ambiguity.expand_output_path(Path("reports/{oops}.txt"), "general") + + def test_unbalanced_brace_is_reported(self) -> None: + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "invalid --output pattern" + ): + ambiguity.expand_output_path(Path("reports/{profile.txt"), "general") + + def test_literal_braces_are_preserved(self) -> None: + self.assertEqual( + ambiguity.expand_output_path(Path("reports/{{profile}}.txt"), "general"), + Path("reports/{profile}.txt"), + ) + + def test_indexed_placeholder_is_rejected(self) -> None: + # str.format_map would silently expand this to the first character. + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "unknown placeholder" + ): + ambiguity.expand_output_path(Path("{profile[0]}.txt"), "general") + + def test_attribute_placeholder_is_rejected(self) -> None: + # str.format_map would raise an uncaught AttributeError here. + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "unknown placeholder" + ): + ambiguity.expand_output_path(Path("{profile.foo}.txt"), "general") + + def test_format_spec_is_rejected(self) -> None: + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "no format spec or conversion" + ): + ambiguity.expand_output_path(Path("{profile:>10}.txt"), "general") + + class CommandLineTests(unittest.TestCase): def test_search_defaults_to_general(self) -> None: arguments = ambiguity.parser().parse_args(["search"]) From 5f2824720c0a1cefd4026b4ea460dbd01746475b Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Fri, 24 Jul 2026 18:41:20 +0200 Subject: [PATCH 151/154] Unify ambiguity profile keys and CLI flags via one settings registry (#47) * Unify ambiguity profile keys and CLI flags via one settings registry Drive the profile keys, the --override flags, profile validation, override application, and engine-argument construction from a single SETTINGS registry. Each search parameter is declared once, and the TOML key and the --flag now share the identical kebab-case name, so the two surfaces cannot drift apart. - Rename the two multi-word profile keys to kebab-case: prefix_tokens -> prefix-tokens, nodes_per_depth -> nodes-per-depth (updates the committed ambiguity-searches.toml). - Add `output` as a profile key, so a report path can live in a profile (e.g. output = "reports/{profile}-{date}.txt"); --output still overrides it, and placeholder expansion plus directory creation apply either way. - --breadth-first and --dry-run stay CLI-only, documented as a mode and as nodes-per-depth-off rather than settings. Adding a future parameter is now a one-line registry entry. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Q3hXqkaob2JQDV4yfHTqom * Guard output coercion and tighten the prefix/EOF bound - _coerce_output now validates its input like every other coercer, so a malformed value such as output = 5 raises a ConfigurationError routed through main() instead of an uncaught TypeError from Path(5). - _validate_profile rejects a prefix whose length equals max_tokens: since max_tokens counts the prefix and the required EOF, a full-length prefix leaves no room for EOF and can never complete a witness (> becomes >=). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Q3hXqkaob2JQDV4yfHTqom --------- Co-authored-by: Claude --- ambiguity-searches.toml | 4 +- docs/ambiguity.md | 24 ++- tools/ambiguity.py | 342 +++++++++++++++++++++++++--------------- tools/test_ambiguity.py | 93 ++++++++++- 4 files changed, 326 insertions(+), 137 deletions(-) diff --git a/ambiguity-searches.toml b/ambiguity-searches.toml index 1487dac3..fb80fa09 100644 --- a/ambiguity-searches.toml +++ b/ambiguity-searches.toml @@ -14,5 +14,5 @@ witnesses = 50 extends = "general" description = "Rotate deep search waves through statements in a function body." tokens = "15..50" -prefix_tokens = ["UIDENT", "LIDENT", "LPAREN", "RPAREN", "LCURLY"] -nodes_per_depth = 10 +prefix-tokens = ["UIDENT", "LIDENT", "LPAREN", "RPAREN", "LCURLY"] +nodes-per-depth = 10 diff --git a/docs/ambiguity.md b/docs/ambiguity.md index 84b0e675..e2d0c559 100644 --- a/docs/ambiguity.md +++ b/docs/ambiguity.md @@ -136,12 +136,24 @@ Friendly durations such as `90s`, `30m`, and `1h` are accepted. Add `--output report.txt` to display and save a report, or `--dry-run` to inspect the resolved settings without building the engine. -The `--output` path may contain placeholders that are filled in when the run -starts: `{profile}` is the resolved profile name, and `{date}`, `{time}`, and -`{datetime}` are timestamps laid out like the existing `reports/` filenames (`2026-07-23`, `21-38-17`, and `2026-07-23_21-38-17`). Any -directories in the expanded path are created automatically, so -`--output reports/{profile}-{date}.txt` drops a dated report into `reports/` -without a manual `mkdir`. Write `{{` and `}}` for literal braces. +Every profile setting has an identically named override flag: the TOML key and +the `--flag` share the same kebab-case spelling (`tokens`, `timeout`, +`witnesses`, `prefix-tokens`, `nodes-per-depth`, `output`), and the command line +overrides the profile. A single registry in `tools/ambiguity.py` declares each +setting once and drives both the profile keys and the flags, so they cannot +drift apart. The two remaining flags are not settings: `--breadth-first` is just +`nodes-per-depth` turned off (a profile expresses it by leaving the key unset), +and `--dry-run` is a run mode. + +The `output` path — whether set as a profile key or passed with `--output` — +may contain placeholders that are filled in when the run starts: `{profile}` is +the resolved profile name, and `{date}`, `{time}`, and `{datetime}` are +timestamps laid out like the existing `reports/` filenames (`2026-07-23`, +`21-38-17`, and `2026-07-23_21-38-17`). Any directories in the expanded path are +created automatically, so `output = "reports/{profile}-{date}.txt"` in a profile +(or `--output reports/{profile}-{date}.txt` on the command line) drops a dated +report into `reports/` without a manual `mkdir`. Write `{{` and `}}` for literal +braces. To concentrate a run inside a function body and favor depth over breadth: diff --git a/tools/ambiguity.py b/tools/ambiguity.py index 69d2bf88..79abc4cb 100644 --- a/tools/ambiguity.py +++ b/tools/ambiguity.py @@ -13,22 +13,13 @@ import subprocess import sys import tomllib -from typing import Any, Sequence, TextIO +from typing import Any, Callable, Sequence, TextIO ROOT = Path(__file__).resolve().parent.parent DEFAULT_PROFILES = ROOT / "ambiguity-searches.toml" ENGINE_RUNNER = ROOT / "dev" / "bin" / "ambiguity" -PROFILE_KEYS = { - "description", - "extends", - "tokens", - "timeout", - "witnesses", - "prefix_tokens", - "nodes_per_depth", -} DURATION_PART = re.compile(r"(\d+(?:\.\d+)?)(ms|s|m|h)") DURATION_FACTORS = {"ms": 0.001, "s": 1.0, "m": 60.0, "h": 3600.0} @@ -47,6 +38,7 @@ class SearchProfile: witnesses: int prefix_tokens: tuple[str, ...] = () nodes_per_depth: int | None = None + output: Path | None = None def parse_token_range(value: str) -> tuple[int, int]: @@ -97,6 +89,185 @@ def format_duration(seconds: float) -> str: return f"{seconds:g}s" +# ----- Search-parameter registry ----- +# +# Every search parameter is declared once here and shared by both surfaces: +# the TOML profile key and the `--key` override flag use the identical +# kebab-case spelling. The registry drives profile validation, argparse flag +# registration, override application, and engine-argument construction, so a +# new parameter is added in exactly one place instead of five. + + +@dataclass(frozen=True) +class Setting: + key: str + # (raw value, profile name) -> SearchProfile field updates; raises + # ConfigurationError on an invalid value. Accepts both the TOML-typed value + # and the argparse-typed override so a single coercion serves both surfaces. + coerce: Callable[[Any, str], dict[str, Any]] + to_engine_args: Callable[["SearchProfile"], list[str]] + metavar: str + help: str + required: bool = False + arg_type: Callable[[str], Any] | None = None + + @property + def dest(self) -> str: + return self.key.replace("-", "_") + + +def _coerce_tokens(raw: Any, name: str) -> dict[str, Any]: + if not isinstance(raw, str): + raise ConfigurationError(f"profile {name!r}: tokens must be MIN..MAX") + minimum, maximum = parse_token_range(raw) + return {"min_tokens": minimum, "max_tokens": maximum} + + +def _coerce_timeout(raw: Any, name: str) -> dict[str, Any]: + return {"timeout_seconds": parse_duration(raw)} + + +def _coerce_witnesses(raw: Any, name: str) -> dict[str, Any]: + if isinstance(raw, bool) or not isinstance(raw, int) or raw < 1: + raise ConfigurationError( + f"profile {name!r}: witnesses must be an integer of at least 1" + ) + return {"witnesses": raw} + + +def _coerce_prefix_tokens(raw: Any, name: str) -> dict[str, Any]: + # A profile supplies an array; the CLI override supplies a space-separated + # string. Accept either so both surfaces share one code path. + tokens = raw.split() if isinstance(raw, str) else raw + if not isinstance(tokens, list) or not all( + isinstance(token, str) and token for token in tokens + ): + raise ConfigurationError( + f"profile {name!r}: prefix-tokens must be an array of token names" + ) + return {"prefix_tokens": tuple(tokens)} + + +def _coerce_nodes_per_depth(raw: Any, name: str) -> dict[str, Any]: + if isinstance(raw, bool) or not isinstance(raw, int) or raw < 1: + raise ConfigurationError( + f"profile {name!r}: nodes-per-depth must be an integer of at least 1" + ) + return {"nodes_per_depth": raw} + + +def _coerce_output(raw: Any, name: str) -> dict[str, Any]: + # A profile supplies a string; the --output override supplies a Path. Guard + # like every other coercer so a malformed value (e.g. output = 5) becomes a + # ConfigurationError routed through main() instead of an uncaught TypeError. + if not isinstance(raw, (str, Path)): + raise ConfigurationError(f"profile {name!r}: output must be a string path") + return {"output": Path(raw)} + + +def _tokens_engine_args(profile: SearchProfile) -> list[str]: + return [ + "--max-tokens", + str(profile.max_tokens), + "--min-tokens", + str(profile.min_tokens), + ] + + +def _timeout_engine_args(profile: SearchProfile) -> list[str]: + return ["--timeout", f"{profile.timeout_seconds:g}"] + + +def _witnesses_engine_args(profile: SearchProfile) -> list[str]: + return ["--max-witnesses", str(profile.witnesses)] + + +def _prefix_engine_args(profile: SearchProfile) -> list[str]: + if not profile.prefix_tokens: + return [] + return ["--prefix-tokens", " ".join(profile.prefix_tokens)] + + +def _nodes_engine_args(profile: SearchProfile) -> list[str]: + if profile.nodes_per_depth is None: + return [] + return ["--nodes-per-depth", str(profile.nodes_per_depth)] + + +def _no_engine_args(profile: SearchProfile) -> list[str]: + # The report path is handled by this wrapper, not passed to the engine. + return [] + + +SETTINGS: tuple[Setting, ...] = ( + Setting( + "tokens", + _coerce_tokens, + _tokens_engine_args, + "MIN..MAX", + "override the profile's complete-witness token range", + required=True, + ), + Setting( + "timeout", + _coerce_timeout, + _timeout_engine_args, + "DURATION", + "override the timeout; accepts values such as 90s, 30m, and 1h", + required=True, + ), + Setting( + "witnesses", + _coerce_witnesses, + _witnesses_engine_args, + "N", + "override the number of ambiguity families to report", + required=True, + arg_type=int, + ), + Setting( + "prefix-tokens", + _coerce_prefix_tokens, + _prefix_engine_args, + "TOKENS", + "override the fixed space-separated token prefix", + ), + Setting( + "nodes-per-depth", + _coerce_nodes_per_depth, + _nodes_engine_args, + "N", + "override how many sibling frontiers a depth wave expands", + arg_type=int, + ), + Setting( + "output", + _coerce_output, + _no_engine_args, + "FILE", + "write the complete report to FILE while also displaying it; " + "{profile}, {date}, {time}, and {datetime} expand in the path " + "(e.g. reports/{profile}-{date}.txt), and missing directories are created", + arg_type=Path, + ), +) + +# The TOML profile keys are exactly the setting names plus the two structural +# keys, so the flags and the profile keys can never drift apart. +PROFILE_KEYS = {"description", "extends"} | {setting.key for setting in SETTINGS} + + +def _validate_profile(profile: SearchProfile, name: str) -> None: + # max_tokens counts the prefix and the required EOF, so the prefix must + # leave room for at least the EOF token: a prefix of exactly max_tokens can + # never complete a witness. + if len(profile.prefix_tokens) >= profile.max_tokens: + raise ConfigurationError( + f"profile {name!r}: prefix fills the whole token budget, " + f"leaving no room for the EOF token" + ) + + def expand_output_path(pattern: Path, profile_name: str) -> Path: """Substitute report-naming placeholders in an --output pattern. @@ -193,100 +364,50 @@ def resolve(name: str) -> dict[str, Any]: profiles: dict[str, SearchProfile] = {} for name in tables: settings = resolve(name) - missing = {"tokens", "timeout", "witnesses"} - set(settings) + missing = {setting.key for setting in SETTINGS if setting.required} - set( + settings + ) if missing: keys = ", ".join(sorted(missing)) raise ConfigurationError(f"profile {name!r} is missing: {keys}") - token_value = settings["tokens"] - if not isinstance(token_value, str): - raise ConfigurationError(f"profile {name!r}: tokens must be MIN..MAX") - minimum, maximum = parse_token_range(token_value) - witnesses = settings["witnesses"] - if isinstance(witnesses, bool) or not isinstance(witnesses, int) or witnesses < 1: - raise ConfigurationError( - f"profile {name!r}: witnesses must be an integer of at least 1" - ) - prefix = settings.get("prefix_tokens", []) - if not isinstance(prefix, list) or not all( - isinstance(token, str) and token for token in prefix - ): - raise ConfigurationError( - f"profile {name!r}: prefix_tokens must be an array of token names" - ) - nodes = settings.get("nodes_per_depth") - if nodes is not None and ( - isinstance(nodes, bool) or not isinstance(nodes, int) or nodes < 1 - ): - raise ConfigurationError( - f"profile {name!r}: nodes_per_depth must be an integer of at least 1" - ) - if len(prefix) > maximum: - raise ConfigurationError( - f"profile {name!r}: prefix is longer than the maximum token count" - ) description = settings.get("description", "") if not isinstance(description, str): raise ConfigurationError(f"profile {name!r}: description must be a string") - profiles[name] = SearchProfile( - name=name, - description=description, - min_tokens=minimum, - max_tokens=maximum, - timeout_seconds=parse_duration(settings["timeout"]), - witnesses=witnesses, - prefix_tokens=tuple(prefix), - nodes_per_depth=nodes, - ) + fields: dict[str, Any] = {"name": name, "description": description} + for setting in SETTINGS: + if setting.key in settings: + fields.update(setting.coerce(settings[setting.key], name)) + profile = SearchProfile(**fields) + _validate_profile(profile, name) + profiles[name] = profile return profiles def apply_overrides( profile: SearchProfile, arguments: argparse.Namespace ) -> SearchProfile: - result = profile - if arguments.token_range is not None: - minimum, maximum = parse_token_range(arguments.token_range) - result = replace(result, min_tokens=minimum, max_tokens=maximum) - if arguments.timeout is not None: - result = replace(result, timeout_seconds=parse_duration(arguments.timeout)) - if arguments.witnesses is not None: - if arguments.witnesses < 1: - raise ConfigurationError("--witnesses must be at least 1") - result = replace(result, witnesses=arguments.witnesses) - if arguments.prefix_tokens is not None: - result = replace( - result, prefix_tokens=tuple(arguments.prefix_tokens.split()) - ) - if arguments.nodes_per_depth is not None: - if arguments.nodes_per_depth < 1: - raise ConfigurationError("--nodes-per-depth must be at least 1") - result = replace(result, nodes_per_depth=arguments.nodes_per_depth) - if arguments.breadth_first: - if arguments.nodes_per_depth is not None: + fields: dict[str, Any] = {} + for setting in SETTINGS: + value = getattr(arguments, setting.dest, None) + if value is not None: + fields.update(setting.coerce(value, profile.name)) + result = replace(profile, **fields) if fields else profile + # --breadth-first is not a value; it is nodes-per-depth turned off, and only + # exists to override a profile that set it. + if getattr(arguments, "breadth_first", False): + if getattr(arguments, "nodes_per_depth", None) is not None: raise ConfigurationError( "--breadth-first and --nodes-per-depth cannot be combined" ) result = replace(result, nodes_per_depth=None) - if len(result.prefix_tokens) > result.max_tokens: - raise ConfigurationError("prefix is longer than the maximum token count") + _validate_profile(result, result.name) return result def engine_arguments(profile: SearchProfile, prove: int | None = None) -> list[str]: - arguments = [ - "--max-tokens", - str(profile.max_tokens), - "--min-tokens", - str(profile.min_tokens), - "--timeout", - f"{profile.timeout_seconds:g}", - "--max-witnesses", - str(profile.witnesses), - ] - if profile.prefix_tokens: - arguments.extend(["--prefix-tokens", " ".join(profile.prefix_tokens)]) - if profile.nodes_per_depth is not None: - arguments.extend(["--nodes-per-depth", str(profile.nodes_per_depth)]) + arguments: list[str] = [] + for setting in SETTINGS: + arguments.extend(setting.to_engine_args(profile)) if prove is not None: arguments.extend(["--prove", str(prove)]) return arguments @@ -318,47 +439,18 @@ def profile_summary(profile: SearchProfile, action: str) -> str: def add_overrides(command: argparse.ArgumentParser) -> None: + # Every profile setting registers an identically named override flag; the + # single registry keeps the two surfaces in lockstep. + for setting in SETTINGS: + options: dict[str, Any] = {"metavar": setting.metavar, "help": setting.help} + if setting.arg_type is not None: + options["type"] = setting.arg_type + command.add_argument(f"--{setting.key}", **options) command.add_argument( - "--tokens", - dest="token_range", - metavar="MIN..MAX", - help="override the profile's complete-witness token range", - ) - command.add_argument( - "--timeout", - metavar="DURATION", - help="override the timeout; accepts values such as 90s, 30m, and 1h", - ) - command.add_argument( - "--witnesses", - type=int, - metavar="N", - help="override the number of ambiguity families to report", - ) - command.add_argument( - "--prefix-tokens", - metavar="TOKENS", - help="override the fixed space-separated token prefix", - ) - scheduling = command.add_mutually_exclusive_group() - scheduling.add_argument( - "--nodes-per-depth", - type=int, - metavar="N", - help="override how many sibling frontiers a depth wave expands", - ) - scheduling.add_argument( "--breadth-first", action="store_true", - help="override the profile and use shortest-first scheduling", - ) - command.add_argument( - "--output", - type=Path, - metavar="FILE", - help="write the complete report to FILE while also displaying it; " - "{profile}, {date}, {time}, and {datetime} expand in the path " - "(e.g. reports/{profile}-{date}.txt), and missing directories are created", + help="override the profile and use shortest-first scheduling " + "(the same as leaving nodes-per-depth unset)", ) command.add_argument( "--dry-run", @@ -475,6 +567,8 @@ def list_profiles(profiles: dict[str, SearchProfile]) -> None: f"{format_duration(profile.timeout_seconds)}, " f"{profile.witnesses} witnesses, {scheduling}" ) + if profile.output is not None: + print(f" {'':<{width}} report: {profile.output}") def main(argv: Sequence[str] | None = None) -> int: @@ -516,8 +610,8 @@ def main(argv: Sequence[str] | None = None) -> int: ) output_path = ( None - if arguments.output is None - else expand_output_path(arguments.output, profile.name) + if profile.output is None + else expand_output_path(profile.output, profile.name) ) summary = profile_summary(profile, action) if output_path is not None: diff --git a/tools/test_ambiguity.py b/tools/test_ambiguity.py index b935f1b6..20e48b3e 100644 --- a/tools/test_ambiguity.py +++ b/tools/test_ambiguity.py @@ -73,6 +73,14 @@ def write_profiles(self, contents: str) -> Path: path.write_text(contents, encoding="utf-8") return path + def override_namespace(self, **overrides: object) -> argparse.Namespace: + # Mirror argparse defaults: every override dest is None (store_true + # flags are False) unless the test sets it. + namespace = {setting.dest: None for setting in ambiguity.SETTINGS} + namespace["breadth_first"] = False + namespace.update(overrides) + return argparse.Namespace(**namespace) + def test_inheritance_and_overrides(self) -> None: path = self.write_profiles( """ @@ -85,8 +93,9 @@ def test_inheritance_and_overrides(self) -> None: [profiles.deep] extends = "base" tokens = "12..50" -prefix_tokens = ["UIDENT", "LCURLY"] -nodes_per_depth = 4 +prefix-tokens = ["UIDENT", "LCURLY"] +nodes-per-depth = 4 +output = "reports/{profile}-{date}.txt" """ ) profile = ambiguity.load_profiles(path)["deep"] @@ -95,13 +104,13 @@ def test_inheritance_and_overrides(self) -> None: self.assertEqual(profile.timeout_seconds, 120) self.assertEqual(profile.prefix_tokens, ("UIDENT", "LCURLY")) self.assertEqual(profile.nodes_per_depth, 4) + self.assertEqual(profile.output, Path("reports/{profile}-{date}.txt")) - arguments = argparse.Namespace( - token_range="10..30", + arguments = self.override_namespace( + tokens="10..30", timeout="1h", witnesses=25, prefix_tokens="UIDENT LIDENT", - nodes_per_depth=None, breadth_first=True, ) overridden = ambiguity.apply_overrides(profile, arguments) @@ -110,6 +119,80 @@ def test_inheritance_and_overrides(self) -> None: self.assertEqual(overridden.witnesses, 25) self.assertEqual(overridden.prefix_tokens, ("UIDENT", "LIDENT")) self.assertIsNone(overridden.nodes_per_depth) + # The profile's output survives when no --output override is given. + self.assertEqual(overridden.output, Path("reports/{profile}-{date}.txt")) + + def test_output_key_and_override(self) -> None: + path = self.write_profiles( + """ +[profiles.quick] +tokens = "0..10" +timeout = "1m" +witnesses = 5 +output = "reports/{profile}.txt" +""" + ) + profile = ambiguity.load_profiles(path)["quick"] + self.assertEqual(profile.output, Path("reports/{profile}.txt")) + overridden = ambiguity.apply_overrides( + profile, self.override_namespace(output=Path("elsewhere.txt")) + ) + self.assertEqual(overridden.output, Path("elsewhere.txt")) + + def test_output_must_be_a_string_path(self) -> None: + path = self.write_profiles( + """ +[profiles.quick] +tokens = "0..10" +timeout = "1m" +witnesses = 5 +output = 5 +""" + ) + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "output must be a string path" + ): + ambiguity.load_profiles(path) + + def test_prefix_must_leave_room_for_eof(self) -> None: + # A prefix that fills the entire max_tokens budget leaves no slot for the + # required EOF token, so it can never complete a witness. + path = self.write_profiles( + """ +[profiles.quick] +tokens = "0..3" +timeout = "1m" +witnesses = 5 +prefix-tokens = ["UIDENT", "LPAREN", "RPAREN"] +""" + ) + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "no room for the EOF token" + ): + ambiguity.load_profiles(path) + + def test_profile_keys_match_override_flags(self) -> None: + # The whole point of the registry: the TOML keys and the CLI flags are + # the same kebab-case names. + search = ambiguity.parser().parse_args(["search"]) + for setting in ambiguity.SETTINGS: + self.assertIn(setting.key, ambiguity.PROFILE_KEYS) + self.assertTrue(hasattr(search, setting.dest)) + + def test_snake_case_key_is_rejected(self) -> None: + path = self.write_profiles( + """ +[profiles.quick] +tokens = "0..10" +timeout = "1m" +witnesses = 5 +prefix_tokens = ["UIDENT"] +""" + ) + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "unknown settings: prefix_tokens" + ): + ambiguity.load_profiles(path) def test_inheritance_cycle_is_reported(self) -> None: path = self.write_profiles( From 17c8fb1616c9cc7bdf2ba3a052f7f724d3f30553 Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Fri, 24 Jul 2026 19:24:18 +0200 Subject: [PATCH 152/154] Fold all ambiguity flags into one registry; make breadth-first a config key (#48) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend the settings registry so it enumerates every flag, not just the value settings. Each entry carries a `kind` ("value" | "toggle" | "mode") and a `profile_key` marker, and the argparse flags, PROFILE_KEYS, profile loading, overrides, and engine arguments all derive from that one list. This removes the hardcoded cli-only flag lines that previously sat outside the registry, so there is a single source of truth for flags and keys. breadth-first is now a profile key. Scheduling is one slot with two spellings — a profile sets either `nodes-per-depth = N` or `breadth-first = true`, never both — so a child profile can now reset an inherited nodes-per-depth back to breadth-first (or the reverse); the child's choice replaces whichever the parent set. dry-run stays flag-only as a run mode (profile_key=False). Claude-Session: https://claude.ai/code/session_01Q3hXqkaob2JQDV4yfHTqom Co-authored-by: Claude --- docs/ambiguity.md | 21 +++-- tools/ambiguity.py | 174 +++++++++++++++++++++++++++------------- tools/test_ambiguity.py | 104 +++++++++++++++++++++++- 3 files changed, 232 insertions(+), 67 deletions(-) diff --git a/docs/ambiguity.md b/docs/ambiguity.md index e2d0c559..c81a436e 100644 --- a/docs/ambiguity.md +++ b/docs/ambiguity.md @@ -138,12 +138,21 @@ the resolved settings without building the engine. Every profile setting has an identically named override flag: the TOML key and the `--flag` share the same kebab-case spelling (`tokens`, `timeout`, -`witnesses`, `prefix-tokens`, `nodes-per-depth`, `output`), and the command line -overrides the profile. A single registry in `tools/ambiguity.py` declares each -setting once and drives both the profile keys and the flags, so they cannot -drift apart. The two remaining flags are not settings: `--breadth-first` is just -`nodes-per-depth` turned off (a profile expresses it by leaving the key unset), -and `--dry-run` is a run mode. +`witnesses`, `prefix-tokens`, `nodes-per-depth`, `breadth-first`, `output`), and +the command line overrides the profile. A single registry in +`tools/ambiguity.py` declares every flag once — value flags, the `breadth-first` +toggle, and the `dry-run` mode alike — and marks which ones profiles may set, so +the flags and the profile keys are one list and cannot drift apart. The only +flag that is not a profile key is `--dry-run`, which is a run mode (show the +resolved settings without running the engine), not saved search intent. + +Scheduling is one slot with two spellings: a profile sets either +`nodes-per-depth = N` (depth waves) or `breadth-first = true` (shortest-first), +never both. Because breadth-first is now a real key, a child profile can reset +an inherited `nodes-per-depth` back to breadth-first (or the reverse) — the +child's choice replaces whichever the parent set. On the command line, +`--breadth-first` overrides a profile's `nodes-per-depth`, and giving both +`--breadth-first` and `--nodes-per-depth` at once is an error. The `output` path — whether set as a profile key or passed with `--output` — may contain placeholders that are filled in when the run starts: `{profile}` is diff --git a/tools/ambiguity.py b/tools/ambiguity.py index 79abc4cb..1dbde53f 100644 --- a/tools/ambiguity.py +++ b/tools/ambiguity.py @@ -100,16 +100,28 @@ def format_duration(seconds: float) -> str: @dataclass(frozen=True) class Setting: + # One entry per command-line flag. `kind` records how it behaves and + # `profile_key` whether it is also a valid TOML key, so a single registry + # enumerates every flag and marks which ones profiles may set - there is no + # separate cli-only list. + # "value" - takes an argument; loadable from a profile and, unless it is + # purely a wrapper concern, forwarded to the engine. + # "toggle" - a boolean switch (--flag / `flag = true`) that rewrites a + # field rather than carrying its own value. + # "mode" - a boolean switch that changes what the CLI does, never a + # profile setting. key: str + kind: str + help: str + profile_key: bool = True + metavar: str | None = None + arg_type: Callable[[str], Any] | None = None + required: bool = False # (raw value, profile name) -> SearchProfile field updates; raises # ConfigurationError on an invalid value. Accepts both the TOML-typed value # and the argparse-typed override so a single coercion serves both surfaces. - coerce: Callable[[Any, str], dict[str, Any]] - to_engine_args: Callable[["SearchProfile"], list[str]] - metavar: str - help: str - required: bool = False - arg_type: Callable[[str], Any] | None = None + coerce: Callable[[Any, str], dict[str, Any]] | None = None + to_engine_args: Callable[["SearchProfile"], list[str]] | None = None @property def dest(self) -> str: @@ -165,6 +177,19 @@ def _coerce_output(raw: Any, name: str) -> dict[str, Any]: return {"output": Path(raw)} +def _coerce_breadth_first(raw: Any, name: str) -> dict[str, Any]: + # Scheduling is a single slot with two spellings: `nodes-per-depth = N` or + # `breadth-first = true`. This toggle rewrites the nodes_per_depth field to + # None; the two keys are mutually exclusive within a table (enforced in + # _profile_tables) and a child overrides whichever the parent chose. + if raw is not True: + raise ConfigurationError( + f"profile {name!r}: breadth-first must be true " + f"(omit it to use nodes-per-depth)" + ) + return {"nodes_per_depth": None} + + def _tokens_engine_args(profile: SearchProfile) -> list[str]: return [ "--max-tokens", @@ -202,59 +227,84 @@ def _no_engine_args(profile: SearchProfile) -> list[str]: SETTINGS: tuple[Setting, ...] = ( Setting( "tokens", - _coerce_tokens, - _tokens_engine_args, - "MIN..MAX", - "override the profile's complete-witness token range", + kind="value", + help="override the profile's complete-witness token range", + metavar="MIN..MAX", required=True, + coerce=_coerce_tokens, + to_engine_args=_tokens_engine_args, ), Setting( "timeout", - _coerce_timeout, - _timeout_engine_args, - "DURATION", - "override the timeout; accepts values such as 90s, 30m, and 1h", + kind="value", + help="override the timeout; accepts values such as 90s, 30m, and 1h", + metavar="DURATION", required=True, + coerce=_coerce_timeout, + to_engine_args=_timeout_engine_args, ), Setting( "witnesses", - _coerce_witnesses, - _witnesses_engine_args, - "N", - "override the number of ambiguity families to report", - required=True, + kind="value", + help="override the number of ambiguity families to report", + metavar="N", arg_type=int, + required=True, + coerce=_coerce_witnesses, + to_engine_args=_witnesses_engine_args, ), Setting( "prefix-tokens", - _coerce_prefix_tokens, - _prefix_engine_args, - "TOKENS", - "override the fixed space-separated token prefix", + kind="value", + help="override the fixed space-separated token prefix", + metavar="TOKENS", + coerce=_coerce_prefix_tokens, + to_engine_args=_prefix_engine_args, ), Setting( "nodes-per-depth", - _coerce_nodes_per_depth, - _nodes_engine_args, - "N", - "override how many sibling frontiers a depth wave expands", + kind="value", + help="override how many sibling frontiers a depth wave expands", + metavar="N", arg_type=int, + coerce=_coerce_nodes_per_depth, + to_engine_args=_nodes_engine_args, + ), + Setting( + "breadth-first", + kind="toggle", + help="use shortest-first scheduling (the breadth-first spelling of the " + "nodes-per-depth slot; a profile may set at most one of the two)", + coerce=_coerce_breadth_first, ), Setting( "output", - _coerce_output, - _no_engine_args, - "FILE", - "write the complete report to FILE while also displaying it; " + kind="value", + help="write the complete report to FILE while also displaying it; " "{profile}, {date}, {time}, and {datetime} expand in the path " "(e.g. reports/{profile}-{date}.txt), and missing directories are created", + metavar="FILE", arg_type=Path, + coerce=_coerce_output, + to_engine_args=_no_engine_args, + ), + Setting( + "dry-run", + kind="mode", + help="show the resolved profile without running the engine", + profile_key=False, ), ) -# The TOML profile keys are exactly the setting names plus the two structural -# keys, so the flags and the profile keys can never drift apart. -PROFILE_KEYS = {"description", "extends"} | {setting.key for setting in SETTINGS} +# Scheduling is one concept with two spellings; a profile table may set at most +# one of these keys, and a child profile's choice replaces the parent's. +SCHEDULING_KEYS = ("nodes-per-depth", "breadth-first") + +# The TOML profile keys are exactly the profile-key settings plus the two +# structural keys, so the flags and the profile keys can never drift apart. +PROFILE_KEYS = {"description", "extends"} | { + setting.key for setting in SETTINGS if setting.profile_key +} def _validate_profile(profile: SearchProfile, name: str) -> None: @@ -333,6 +383,10 @@ def _profile_tables(path: Path) -> dict[str, dict[str, Any]]: if unknown: keys = ", ".join(sorted(unknown)) raise ConfigurationError(f"profile {name!r} has unknown settings: {keys}") + if len([key for key in SCHEDULING_KEYS if key in table]) > 1: + raise ConfigurationError( + f"profile {name!r}: set at most one of {' and '.join(SCHEDULING_KEYS)}" + ) result[name] = table return result @@ -356,7 +410,13 @@ def resolve(name: str) -> dict[str, Any]: if parent is not None and not isinstance(parent, str): raise ConfigurationError(f"profile {name!r}: extends must be a string") merged = dict(resolve(parent)) if parent else {} - merged.update({key: value for key, value in table.items() if key != "extends"}) + child_items = {key: value for key, value in table.items() if key != "extends"} + # Scheduling is one slot: if the child chooses either spelling, drop + # whichever the parent set so the child's choice wins in both directions. + if any(key in child_items for key in SCHEDULING_KEYS): + for key in SCHEDULING_KEYS: + merged.pop(key, None) + merged.update(child_items) resolving.pop() resolved[name] = merged return merged @@ -375,7 +435,7 @@ def resolve(name: str) -> dict[str, Any]: raise ConfigurationError(f"profile {name!r}: description must be a string") fields: dict[str, Any] = {"name": name, "description": description} for setting in SETTINGS: - if setting.key in settings: + if setting.coerce is not None and setting.key in settings: fields.update(setting.coerce(settings[setting.key], name)) profile = SearchProfile(**fields) _validate_profile(profile, name) @@ -388,18 +448,20 @@ def apply_overrides( ) -> SearchProfile: fields: dict[str, Any] = {} for setting in SETTINGS: + if setting.kind != "value": + continue value = getattr(arguments, setting.dest, None) if value is not None: fields.update(setting.coerce(value, profile.name)) result = replace(profile, **fields) if fields else profile - # --breadth-first is not a value; it is nodes-per-depth turned off, and only - # exists to override a profile that set it. + # The scheduling slot again: --breadth-first rewrites nodes_per_depth to + # None, and the two cannot be given together on one command line. if getattr(arguments, "breadth_first", False): if getattr(arguments, "nodes_per_depth", None) is not None: raise ConfigurationError( "--breadth-first and --nodes-per-depth cannot be combined" ) - result = replace(result, nodes_per_depth=None) + result = replace(result, **_coerce_breadth_first(True, result.name)) _validate_profile(result, result.name) return result @@ -407,7 +469,8 @@ def apply_overrides( def engine_arguments(profile: SearchProfile, prove: int | None = None) -> list[str]: arguments: list[str] = [] for setting in SETTINGS: - arguments.extend(setting.to_engine_args(profile)) + if setting.to_engine_args is not None: + arguments.extend(setting.to_engine_args(profile)) if prove is not None: arguments.extend(["--prove", str(prove)]) return arguments @@ -439,24 +502,21 @@ def profile_summary(profile: SearchProfile, action: str) -> str: def add_overrides(command: argparse.ArgumentParser) -> None: - # Every profile setting registers an identically named override flag; the - # single registry keeps the two surfaces in lockstep. + # Every flag - value settings, toggles, and modes alike - is registered from + # the one registry, so there is no separate cli-only flag list to maintain. for setting in SETTINGS: - options: dict[str, Any] = {"metavar": setting.metavar, "help": setting.help} - if setting.arg_type is not None: - options["type"] = setting.arg_type - command.add_argument(f"--{setting.key}", **options) - command.add_argument( - "--breadth-first", - action="store_true", - help="override the profile and use shortest-first scheduling " - "(the same as leaving nodes-per-depth unset)", - ) - command.add_argument( - "--dry-run", - action="store_true", - help="show the resolved profile without running the engine", - ) + if setting.kind == "value": + options: dict[str, Any] = { + "metavar": setting.metavar, + "help": setting.help, + } + if setting.arg_type is not None: + options["type"] = setting.arg_type + command.add_argument(f"--{setting.key}", **options) + else: + command.add_argument( + f"--{setting.key}", action="store_true", help=setting.help + ) def parser() -> argparse.ArgumentParser: diff --git a/tools/test_ambiguity.py b/tools/test_ambiguity.py index 20e48b3e..768fbb8a 100644 --- a/tools/test_ambiguity.py +++ b/tools/test_ambiguity.py @@ -171,13 +171,109 @@ def test_prefix_must_leave_room_for_eof(self) -> None: ): ambiguity.load_profiles(path) - def test_profile_keys_match_override_flags(self) -> None: - # The whole point of the registry: the TOML keys and the CLI flags are - # the same kebab-case names. + def test_single_registry_drives_flags_and_keys(self) -> None: + # The whole point of the registry: one list enumerates every flag, and + # each entry marks whether it is also a TOML key. Every setting registers + # a flag; only profile_key settings are valid TOML keys. search = ambiguity.parser().parse_args(["search"]) for setting in ambiguity.SETTINGS: - self.assertIn(setting.key, ambiguity.PROFILE_KEYS) self.assertTrue(hasattr(search, setting.dest)) + self.assertEqual( + setting.profile_key, setting.key in ambiguity.PROFILE_KEYS + ) + # dry-run is a mode, so it is the one flag that is not a TOML key. + self.assertNotIn("dry-run", ambiguity.PROFILE_KEYS) + self.assertIn("breadth-first", ambiguity.PROFILE_KEYS) + + def test_breadth_first_profile_key(self) -> None: + path = self.write_profiles( + """ +[profiles.quick] +tokens = "0..10" +timeout = "1m" +witnesses = 5 +breadth-first = true +""" + ) + self.assertIsNone(ambiguity.load_profiles(path)["quick"].nodes_per_depth) + + def test_breadth_first_must_be_true(self) -> None: + path = self.write_profiles( + """ +[profiles.quick] +tokens = "0..10" +timeout = "1m" +witnesses = 5 +breadth-first = false +""" + ) + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "breadth-first must be true" + ): + ambiguity.load_profiles(path) + + def test_scheduling_keys_are_mutually_exclusive(self) -> None: + path = self.write_profiles( + """ +[profiles.quick] +tokens = "0..10" +timeout = "1m" +witnesses = 5 +nodes-per-depth = 4 +breadth-first = true +""" + ) + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "at most one of nodes-per-depth" + ): + ambiguity.load_profiles(path) + + def test_child_breadth_first_overrides_inherited_depth(self) -> None: + path = self.write_profiles( + """ +[profiles.base] +tokens = "0..10" +timeout = "1m" +witnesses = 5 +nodes-per-depth = 8 + +[profiles.child] +extends = "base" +breadth-first = true +""" + ) + self.assertIsNone(ambiguity.load_profiles(path)["child"].nodes_per_depth) + + def test_child_depth_overrides_inherited_breadth_first(self) -> None: + path = self.write_profiles( + """ +[profiles.base] +tokens = "0..10" +timeout = "1m" +witnesses = 5 +breadth-first = true + +[profiles.child] +extends = "base" +nodes-per-depth = 8 +""" + ) + self.assertEqual(ambiguity.load_profiles(path)["child"].nodes_per_depth, 8) + + def test_dry_run_is_not_a_profile_key(self) -> None: + path = self.write_profiles( + """ +[profiles.quick] +tokens = "0..10" +timeout = "1m" +witnesses = 5 +dry-run = true +""" + ) + with self.assertRaisesRegex( + ambiguity.ConfigurationError, "unknown settings: dry-run" + ): + ambiguity.load_profiles(path) def test_snake_case_key_is_rejected(self) -> None: path = self.write_profiles( From 110b595d6fe8d1517d127fa3984577179c5a3fda Mon Sep 17 00:00:00 2001 From: TheLazyCat00 Date: Fri, 24 Jul 2026 23:11:34 +0200 Subject: [PATCH 153/154] update --- ambiguity-searches.toml | 3 ++ .../2026-07-24_22-32-26.txt | 9 ++++ .../2026-07-24_22-36-24.txt | 41 +++++++++++++++++++ tools/ambiguity_search.ml | 2 +- 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 reports/deep-function-body/2026-07-24_22-32-26.txt create mode 100644 reports/deep-function-body/2026-07-24_22-36-24.txt diff --git a/ambiguity-searches.toml b/ambiguity-searches.toml index fb80fa09..33ec3105 100644 --- a/ambiguity-searches.toml +++ b/ambiguity-searches.toml @@ -3,12 +3,14 @@ description = "Fast breadth-first feedback while editing the grammar." tokens = "0..16" timeout = "2m" witnesses = 20 +output = "reports/{profile}/{datetime}.txt" [profiles.general] description = "Broad shortest-first search for the regular ambiguity report." tokens = "0..50" timeout = "30m" witnesses = 50 +output = "reports/{profile}/{datetime}.txt" [profiles.deep-function-body] extends = "general" @@ -16,3 +18,4 @@ description = "Rotate deep search waves through statements in a function body." tokens = "15..50" prefix-tokens = ["UIDENT", "LIDENT", "LPAREN", "RPAREN", "LCURLY"] nodes-per-depth = 10 +output = "reports/{profile}/{datetime}.txt" diff --git a/reports/deep-function-body/2026-07-24_22-32-26.txt b/reports/deep-function-body/2026-07-24_22-32-26.txt new file mode 100644 index 00000000..db518be8 --- /dev/null +++ b/reports/deep-function-body/2026-07-24_22-32-26.txt @@ -0,0 +1,9 @@ +Search profile: deep-function-body +Rotate deep search waves through statements in a function body. +Tokens 15..50 · timeout 30m · 50 witnesses · 10 nodes per depth +Prefix (5): UIDENT LIDENT LPAREN RPAREN LCURLY +Report: reports/deep-function-body/2026-07-24_22-32-26.txt + +Memory budget: 6144 MiB total across 4 worker(s); workers compact at 1229 MiB and stop admitting frontiers at 1382 MiB each (10% reserved); per-worker limits are 710564 queued frontiers and 710564 retained dedup frontiers (ratio 1). +Search constraints: 15..50 total tokens; 5-token prefix; 10 nodes per depth. +Prefix tokens: UIDENT LIDENT LPAREN RPAREN LCURLY diff --git a/reports/deep-function-body/2026-07-24_22-36-24.txt b/reports/deep-function-body/2026-07-24_22-36-24.txt new file mode 100644 index 00000000..3c037e8b --- /dev/null +++ b/reports/deep-function-body/2026-07-24_22-36-24.txt @@ -0,0 +1,41 @@ +Search profile: deep-function-body +Rotate deep search waves through statements in a function body. +Tokens 15..50 · timeout 30m · 50 witnesses · 10 nodes per depth +Prefix (5): UIDENT LIDENT LPAREN RPAREN LCURLY +Report: reports/deep-function-body/2026-07-24_22-36-24.txt + +Memory budget: 6144 MiB total across 4 worker(s); workers compact at 1229 MiB and stop admitting frontiers at 1382 MiB each (10% reserved); per-worker limits are 710564 queued frontiers and 710564 retained dedup frontiers (ratio 1). +Search constraints: 15..50 total tokens; 5-token prefix; 10 nodes per depth. +Prefix tokens: UIDENT LIDENT LPAREN RPAREN LCURLY +Found 7 complete ambiguity families. + +1. Tokens (15): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT TILDE INT EQEQ TILDE FALSE QSTNQSTN FALSE RCURLY EOF + Source: Int length ( ) { abort ~ 43 == ~ false ?? false } + Conflict origins: state 214 on QSTNQSTN, state 496 on QSTNQSTN + +2. Tokens (16): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT TILDE AND AND AND TILDE FALSE QSTNQSTN FALSE RCURLY EOF + Source: Int length ( ) { abort ~ & & & ~ false ?? false } + Conflict origins: state 496 on QSTNQSTN + +3. Tokens (16): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT TILDE UIDENT LPAREN AND FALSE RPAREN QSTNQSTN FALSE RCURLY EOF + Source: Int length ( ) { abort ~ Int ( & false ) ?? false } + Conflict origins: state 93 on LPAREN, state 132 on QSTNQSTN, state 496 on QSTNQSTN + +4. Tokens (17): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT TILDE AND AND FALSE MINUS TILDE FALSE QSTNQSTN FALSE RCURLY EOF + Source: Int length ( ) { abort ~ & & false - ~ false ?? false } + Conflict origins: state 178 on QSTNQSTN, state 496 on QSTNQSTN + +5. Tokens (17): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT UIDENT LBRACKET RBRACKET LPAREN RPAREN THICK_ARROW FALSE DOT LIDENT RCURLY EOF + Source: Int length ( ) { abort Int [ ] ( ) => false . length } + Conflict origins: state 503 on DOT + +6. Tokens (18): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT TILDE AND AND AND AND TILDE FALSE QSTNMARK LCURLY RCURLY RCURLY EOF + Source: Int length ( ) { abort ~ & & & & ~ false ? { } } + Conflict origins: state 496 on QSTNMARK + +7. Tokens (18): UIDENT LIDENT LPAREN RPAREN LCURLY ABORT UIDENT LBRACKET RBRACKET LPAREN RPAREN THICK_ARROW AND FALSE LPAREN RPAREN RCURLY EOF + Source: Int length ( ) { abort Int [ ] ( ) => & false ( ) } + Conflict origins: state 135 on LPAREN + +Explored 24639306 frontiers (27233404 unique); 176491 conflict seeds. +Search stopped because one or more workers reached a search limit. diff --git a/tools/ambiguity_search.ml b/tools/ambiguity_search.ml index 63a04934..ea696a1b 100644 --- a/tools/ambiguity_search.ml +++ b/tools/ambiguity_search.ml @@ -1189,7 +1189,7 @@ let render_progress ~started ~max_tokens ~memory_budget in let elapsed = max 0. (Unix.gettimeofday () -. started) in Printf.eprintf - "\r\027[2K● depth %d/%d | ambiguities@depth %d | %s explored | %s unique | RAM [%s] %.1f/%.1f GiB | %02d:%02d" + "\r\027[2K● %d/%d | amb %d | explored %s | unique %s | RAM [%s] %.1f/%.1fG | %02d:%02d" depth max_tokens at_depth (compact_number !explored) (compact_number !unique) (memory_bar !rss_bytes memory_budget) From eff3fd9db12f642e3a3c7481452a848cbd2f16e0 Mon Sep 17 00:00:00 2001 From: Manuel Stieger <149385373+TheLazyCat00@users.noreply.github.com> Date: Fri, 24 Jul 2026 23:24:08 +0200 Subject: [PATCH 154/154] Organize stray reports into reports/{profile}/{datetime}.txt layout (#49) Relocate the top-level report files under their search profile directory, naming each by run datetime to match the output pattern in ambiguity-searches.toml: - deep.txt and 2026-07-23_21-38-17.txt -> deep-function-body/ - ambiguities-report.txt and new-ambiguities-report.txt -> general/ Datetimes for the previously undated files are taken from the git commit that introduced each report. Claude-Session: https://claude.ai/code/session_01Chyo2Cp1tYK8dXtPNgemTZ Co-authored-by: Claude --- reports/{ => deep-function-body}/2026-07-23_21-38-17.txt | 0 reports/{deep.txt => deep-function-body/2026-07-23_22-10-49.txt} | 0 .../{ambiguities-report.txt => general/2026-07-21_22-36-30.txt} | 0 .../2026-07-23_00-58-36.txt} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename reports/{ => deep-function-body}/2026-07-23_21-38-17.txt (100%) rename reports/{deep.txt => deep-function-body/2026-07-23_22-10-49.txt} (100%) rename reports/{ambiguities-report.txt => general/2026-07-21_22-36-30.txt} (100%) rename reports/{new-ambiguities-report.txt => general/2026-07-23_00-58-36.txt} (100%) diff --git a/reports/2026-07-23_21-38-17.txt b/reports/deep-function-body/2026-07-23_21-38-17.txt similarity index 100% rename from reports/2026-07-23_21-38-17.txt rename to reports/deep-function-body/2026-07-23_21-38-17.txt diff --git a/reports/deep.txt b/reports/deep-function-body/2026-07-23_22-10-49.txt similarity index 100% rename from reports/deep.txt rename to reports/deep-function-body/2026-07-23_22-10-49.txt diff --git a/reports/ambiguities-report.txt b/reports/general/2026-07-21_22-36-30.txt similarity index 100% rename from reports/ambiguities-report.txt rename to reports/general/2026-07-21_22-36-30.txt diff --git a/reports/new-ambiguities-report.txt b/reports/general/2026-07-23_00-58-36.txt similarity index 100% rename from reports/new-ambiguities-report.txt rename to reports/general/2026-07-23_00-58-36.txt