diff --git a/docs/markdown/progress-notes/changelog.md b/docs/markdown/progress-notes/changelog.md index 9b7bfa52e8..399e6cf023 100644 --- a/docs/markdown/progress-notes/changelog.md +++ b/docs/markdown/progress-notes/changelog.md @@ -186,4 +186,5 @@ - Inline arrays of structures are now allowed with `stack-no-clear`. - Creating arrays on the stack now must be done with `stack-no-clear` as they are not memset to 0 or constructed in any way. - The register allocator has been dramatically improved and generates ~5x fewer spill instructions and is able to eliminate more moves. -- Added a `(print-debug-compiler-stats)` form to print out statistics related to register allocation and move elimination \ No newline at end of file +- Added a `(print-debug-compiler-stats)` form to print out statistics related to register allocation and move elimination +- Added `get-enum-vals` which returns a list of pairs. Each pair is the name (symbol) and value (int) for each value in the enum \ No newline at end of file diff --git a/goalc/compiler/Compiler.cpp b/goalc/compiler/Compiler.cpp index 6c14dcfa0e..723252226f 100644 --- a/goalc/compiler/Compiler.cpp +++ b/goalc/compiler/Compiler.cpp @@ -34,6 +34,9 @@ Compiler::Compiler(std::unique_ptr repl) if (m_repl) { m_repl->load_history(); } + + // add GOOS forms that get info from the compiler + setup_goos_forms(); } ReplStatus Compiler::execute_repl(bool auto_listen) { @@ -445,4 +448,36 @@ void Compiler::typecheck_reg_type_allow_false(const goos::Object& form, bool Compiler::knows_object_file(const std::string& name) { return m_debugger.knows_object(name); +} + +void Compiler::setup_goos_forms() { + m_goos.register_form("get-enum-vals", [&](const goos::Object& form, goos::Arguments& args, + const std::shared_ptr& env) { + m_goos.eval_args(&args, env); + va_check(form, args, {goos::ObjectType::SYMBOL}, {}); + std::vector enum_vals; + + const auto& enum_name = args.unnamed.at(0).as_symbol()->name; + auto enum_type = m_ts.try_enum_lookup(enum_name); + if (!enum_type) { + throw_compiler_error(form, "Unknown enum {} in get-enum-vals", enum_name); + } + + std::vector> sorted_values; + for (auto& val : enum_type->entries()) { + sorted_values.emplace_back(val.first, val.second); + } + + std::sort(sorted_values.begin(), sorted_values.end(), + [](const std::pair& a, const std::pair& b) { + return a.second < b.second; + }); + + for (auto& thing : sorted_values) { + enum_vals.push_back(PairObject::make_new(m_goos.intern(thing.first), + goos::Object::make_integer(thing.second))); + } + + return goos::build_list(enum_vals); + }); } \ No newline at end of file diff --git a/goalc/compiler/Compiler.h b/goalc/compiler/Compiler.h index f1321e28e2..e72a94d680 100644 --- a/goalc/compiler/Compiler.h +++ b/goalc/compiler/Compiler.h @@ -87,6 +87,7 @@ class Compiler { int funcs_requiring_v1_allocator = 0; } m_debug_stats; + void setup_goos_forms(); std::set lookup_symbol_infos_starting_with(const std::string& prefix) const; std::vector* lookup_exact_name_info(const std::string& name) const; bool get_true_or_false(const goos::Object& form, const goos::Object& boolean); diff --git a/test/goalc/source_templates/with_game/test-get-enum-vals.gc b/test/goalc/source_templates/with_game/test-get-enum-vals.gc new file mode 100644 index 0000000000..50835c18c0 --- /dev/null +++ b/test/goalc/source_templates/with_game/test-get-enum-vals.gc @@ -0,0 +1,14 @@ +(defenum test-val-enum + (thing1 1) + (thing3 3) + (thing5 5) + ) + +(defmacro test-enum-vals () + (let ((enum-list (get-enum-vals 'test-val-enum))) + `(quote ,enum-list) + ) + ) + +(printl (test-enum-vals)) +0 \ No newline at end of file diff --git a/test/goalc/test_with_game.cpp b/test/goalc/test_with_game.cpp index 1d56ed88ec..60d5a0770d 100644 --- a/test/goalc/test_with_game.cpp +++ b/test/goalc/test_with_game.cpp @@ -824,6 +824,12 @@ TEST_F(WithGameTests, StackInlineArray) { "#x30\n0\n"}); } +TEST_F(WithGameTests, GetEnumVals) { + runner.run_static_test(env, testCategory, "test-get-enum-vals.gc", + {"((thing1 . #) (thing3 . #) " + "(thing5 . #))\n0\n"}); +} + TEST(TypeConsistency, TypeConsistency) { Compiler compiler; compiler.enable_throw_on_redefines();