From 7a5562106e541d4ffe1fe9a036e0bb5fcebc7ec4 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Tue, 24 Aug 2021 22:15:26 -0400 Subject: [PATCH] Compiler performance improvements and error clean-up (#782) * compiler cleanup and error improvement * fix test --- common/goos/Interpreter.cpp | 22 +-- common/goos/Interpreter.h | 1 + common/goos/Object.cpp | 57 ++++++- common/goos/Object.h | 152 ++++++++++-------- common/goos/Reader.cpp | 14 +- common/goos/TextDB.cpp | 35 ++-- common/goos/TextDB.h | 8 +- goalc/compiler/Compiler.cpp | 29 +++- goalc/compiler/Compiler.h | 13 +- goalc/compiler/Env.cpp | 18 ++- goalc/compiler/Env.h | 121 ++++++++++---- goalc/compiler/Util.cpp | 4 +- goalc/compiler/Val.cpp | 2 +- goalc/compiler/compilation/Asm.cpp | 2 +- goalc/compiler/compilation/Atoms.cpp | 26 +-- goalc/compiler/compilation/Block.cpp | 8 +- .../compiler/compilation/CompilerControl.cpp | 4 +- goalc/compiler/compilation/ControlFlow.cpp | 8 +- goalc/compiler/compilation/Define.cpp | 12 +- goalc/compiler/compilation/Function.cpp | 34 ++-- goalc/compiler/compilation/Macro.cpp | 67 ++++++-- goalc/compiler/compilation/Math.cpp | 15 +- goalc/compiler/compilation/State.cpp | 3 +- goalc/compiler/compilation/Static.cpp | 22 +-- goalc/compiler/compilation/Type.cpp | 39 +++-- goalc/make/MakeSystem.cpp | 2 +- goalc/regalloc/IRegSet.h | 2 +- test/test_goos.cpp | 2 +- test/test_reader.cpp | 4 +- 29 files changed, 462 insertions(+), 264 deletions(-) diff --git a/common/goos/Interpreter.cpp b/common/goos/Interpreter.cpp index 9a68cbc874..90b61eb7ba 100644 --- a/common/goos/Interpreter.cpp +++ b/common/goos/Interpreter.cpp @@ -122,14 +122,14 @@ void Interpreter::disable_printfs() { */ void Interpreter::load_goos_library() { auto cmd = "(load-file \"goal_src/goos-lib.gs\")"; - eval_with_rewind(reader.read_from_string(cmd), global_environment.as_env()); + eval_with_rewind(reader.read_from_string(cmd), global_environment.as_env_ptr()); } /*! * In env, set the variable named "name" to the value var. */ void Interpreter::define_var_in_env(Object& env, Object& var, const std::string& name) { - env.as_env()->vars[intern(name).as_symbol()] = var; + env.as_env()->vars[intern_ptr(name)] = var; } /*! @@ -139,6 +139,10 @@ Object Interpreter::intern(const std::string& name) { return SymbolObject::make_new(reader.symbolTable, name); } +HeapObject* Interpreter::intern_ptr(const std::string& name) { + return reader.symbolTable.intern_ptr(name); +} + /*! * Display the REPL, which will run until the user executes exit. */ @@ -152,7 +156,7 @@ void Interpreter::execute_repl(ReplWrapper& repl) { continue; } // evaluate - Object evald = eval_with_rewind(*obj, global_environment.as_env()); + Object evald = eval_with_rewind(*obj, global_environment.as_env_ptr()); // print printf("%s\n", evald.print().c_str()); } catch (std::exception& e) { @@ -489,7 +493,7 @@ bool try_symbol_lookup(const Object& sym, } // loop up envs until we find it. - std::shared_ptr search_env = env; + EnvironmentObject* search_env = env.get(); for (;;) { auto kv = search_env->vars.find(sym.as_symbol()); if (kv != search_env->vars.end()) { @@ -497,7 +501,7 @@ bool try_symbol_lookup(const Object& sym, return true; } - auto pe = search_env->parent_env; + auto pe = search_env->parent_env.get(); if (pe) { search_env = pe; } else { @@ -565,7 +569,7 @@ Object Interpreter::eval_pair(const Object& obj, const std::shared_ptrargs); auto mac_env_obj = EnvironmentObject::make_new(); - auto mac_env = mac_env_obj.as_env(); + auto mac_env = mac_env_obj.as_env_ptr(); mac_env->parent_env = env; // not 100% clear that this is right set_args_in_env(obj, args, macro->args, mac_env); // expand the macro! @@ -583,7 +587,7 @@ Object Interpreter::eval_pair(const Object& obj, const std::shared_ptrargs); eval_args(&args, env); auto lam_env_obj = EnvironmentObject::make_new(); - auto lam_env = lam_env_obj.as_env(); + auto lam_env = lam_env_obj.as_env_ptr(); lam_env->parent_env = lam->parent_env; set_args_in_env(obj, args, lam->args, lam_env); return eval_list_return_last(lam->body, lam->body, lam_env); @@ -641,7 +645,7 @@ Object Interpreter::eval_define(const Object& form, if (args.has_named("env")) { auto result = eval_with_rewind(args.get_named("env"), env); expect_env(form, result); - define_env = result.as_env(); + define_env = result.as_env_ptr(); } Object value = eval_with_rewind(args.unnamed[1], env); @@ -1018,7 +1022,7 @@ Object Interpreter::eval_load_file(const Object& form, } try { - return eval_with_rewind(o, global_environment.as_env()); + return eval_with_rewind(o, global_environment.as_env_ptr()); } catch (std::runtime_error& e) { throw_eval_error(form, std::string("eval error inside of load-file:\n") + e.what()); } diff --git a/common/goos/Interpreter.h b/common/goos/Interpreter.h index ea5dfe298b..2b127c23ba 100644 --- a/common/goos/Interpreter.h +++ b/common/goos/Interpreter.h @@ -23,6 +23,7 @@ class Interpreter { void set_global_variable_to_symbol(const std::string& name, const std::string& value); Object eval(Object obj, const std::shared_ptr& env); Object intern(const std::string& name); + HeapObject* intern_ptr(const std::string& name); void disable_printfs(); Object eval_symbol(const Object& sym, const std::shared_ptr& env); bool eval_symbol(const Object& sym, diff --git a/common/goos/Object.cpp b/common/goos/Object.cpp index 9f004a668d..79acf9a5ed 100644 --- a/common/goos/Object.cpp +++ b/common/goos/Object.cpp @@ -46,7 +46,7 @@ namespace goos { -std::shared_ptr gEmptyList = nullptr; +std::shared_ptr gEmptyList = std::make_shared(); std::shared_ptr& get_empty_list() { return gEmptyList; } @@ -154,16 +154,57 @@ Object build_list(const std::vector& objects) { return EmptyListObject::make_new(); } - Object empty = EmptyListObject::make_new(); - Object head = PairObject::make_new(objects[0], empty); - Object last = head; + // this is by far the most expensive part of parsing, so this is done a bit carefully. + // we maintain a std::shared_ptr that represents the list, built from back to front. + std::shared_ptr head = + std::make_shared(objects.back(), EmptyListObject::make_new()); - for (std::size_t i = 1; i < objects.size(); i++) { - last.as_pair()->cdr = PairObject::make_new(objects[i], empty); - last = last.as_pair()->cdr; + s64 idx = ((s64)objects.size()) - 2; + while (idx >= 0) { + Object next; + next.type = ObjectType::PAIR; + next.heap_obj = std::move(head); + + head = std::make_shared(); + head->car = objects[idx]; + head->cdr = std::move(next); + + idx--; } - return head; + Object result; + result.type = ObjectType::PAIR; + result.heap_obj = head; + return result; +} + +Object build_list(std::vector&& objects) { + if (objects.empty()) { + return EmptyListObject::make_new(); + } + + // this is by far the most expensive part of parsing, so this is done a bit carefully. + // we maintain a std::shared_ptr that represents the list, built from back to front. + std::shared_ptr head = + std::make_shared(objects.back(), EmptyListObject::make_new()); + + s64 idx = ((s64)objects.size()) - 2; + while (idx >= 0) { + Object next; + next.type = ObjectType::PAIR; + next.heap_obj = std::move(head); + + head = std::make_shared(); + head->car = std::move(objects[idx]); + head->cdr = std::move(next); + + idx--; + } + + Object result; + result.type = ObjectType::PAIR; + result.heap_obj = head; + return result; } /*! diff --git a/common/goos/Object.h b/common/goos/Object.h index 518bdbbcb2..53df8d81cc 100644 --- a/common/goos/Object.h +++ b/common/goos/Object.h @@ -167,6 +167,8 @@ class ArrayObject; class Object { public: std::shared_ptr heap_obj = nullptr; + friend Object build_list(const std::vector& objects); + friend Object build_list(std::vector&& objects); union { IntegerObject integer_obj; @@ -226,60 +228,14 @@ class Object { return o; } - std::shared_ptr as_pair() const { - if (type != ObjectType::PAIR) { - throw std::runtime_error("as_pair called on a " + object_type_to_string(type) + " " + - print()); - } - return std::dynamic_pointer_cast(heap_obj); - } - - std::shared_ptr as_env() const { - if (type != ObjectType::ENVIRONMENT) { - throw std::runtime_error("as_env called on a " + object_type_to_string(type) + " " + print()); - } - return std::dynamic_pointer_cast(heap_obj); - } - - std::shared_ptr as_symbol() const { - if (type != ObjectType::SYMBOL) { - throw std::runtime_error("as_symbol called on a " + object_type_to_string(type) + " " + - print()); - } - return std::dynamic_pointer_cast(heap_obj); - } - - std::shared_ptr as_string() const { - if (type != ObjectType::STRING) { - throw std::runtime_error("as_string called on a " + object_type_to_string(type) + " " + - print()); - } - return std::dynamic_pointer_cast(heap_obj); - } - - std::shared_ptr as_lambda() const { - if (type != ObjectType::LAMBDA) { - throw std::runtime_error("as_lambda called on a " + object_type_to_string(type) + " " + - print()); - } - return std::dynamic_pointer_cast(heap_obj); - } - - std::shared_ptr as_macro() const { - if (type != ObjectType::MACRO) { - throw std::runtime_error("as_macro called on a " + object_type_to_string(type) + " " + - print()); - } - return std::dynamic_pointer_cast(heap_obj); - } - - std::shared_ptr as_array() const { - if (type != ObjectType::ARRAY) { - throw std::runtime_error("as_array called on a " + object_type_to_string(type) + " " + - print()); - } - return std::dynamic_pointer_cast(heap_obj); - } + PairObject* as_pair() const; + EnvironmentObject* as_env() const; + std::shared_ptr as_env_ptr() const; + SymbolObject* as_symbol() const; + StringObject* as_string() const; + LambdaObject* as_lambda() const; + MacroObject* as_macro() const; + ArrayObject* as_array() const; IntType& as_int() { if (type != ObjectType::INTEGER) { @@ -346,9 +302,6 @@ class EmptyListObject : public HeapObject { static Object make_new() { Object obj; obj.type = ObjectType::EMPTY_LIST; - if (!get_empty_list()) { - get_empty_list() = std::make_shared(); - } obj.heap_obj = get_empty_list(); return obj; } @@ -388,8 +341,8 @@ class SymbolObject : public HeapObject { */ class SymbolTable { public: - std::shared_ptr intern(const std::string& name) { - auto kv = table.find(name); + std::shared_ptr intern(const std::string& name) { + const auto& kv = table.find(name); if (kv == table.end()) { auto iter = table.insert({name, std::make_shared(name)}); return (*iter.first).second; @@ -398,10 +351,20 @@ class SymbolTable { } } + HeapObject* intern_ptr(const std::string& name) { + const auto& kv = table.find(name); + if (kv == table.end()) { + auto iter = table.insert({name, std::make_shared(name)}); + return (*iter.first).second.get(); + } else { + return kv->second.get(); + } + } + ~SymbolTable() = default; private: - std::unordered_map> table; + std::unordered_map> table; }; class StringObject : public HeapObject { @@ -426,9 +389,10 @@ class PairObject : public HeapObject { public: Object car, cdr; - PairObject(Object car_, Object cdr_) : car(car_), cdr(cdr_) {} + PairObject(const Object& car_, const Object& cdr_) : car(car_), cdr(cdr_) {} + PairObject() = default; - static Object make_new(Object a, Object b) { + static Object make_new(const Object& a, const Object& b) { Object obj; obj.type = ObjectType::PAIR; obj.heap_obj = std::make_shared(a, b); @@ -481,7 +445,10 @@ class EnvironmentObject : public HeapObject { public: std::string name; std::shared_ptr parent_env; - std::unordered_map, Object> vars; + + // the symbols will be stored in the symbol table and never removed, so we don't need shared + // pointers here. + std::unordered_map vars; EnvironmentObject() = default; @@ -641,5 +608,64 @@ class ArrayObject : public HeapObject { }; Object build_list(const std::vector& objects); +Object build_list(std::vector&& objects); +inline PairObject* Object::as_pair() const { + if (type != ObjectType::PAIR) { + throw std::runtime_error("as_pair called on a " + object_type_to_string(type) + " " + print()); + } + return static_cast(heap_obj.get()); +} + +inline EnvironmentObject* Object::as_env() const { + if (type != ObjectType::ENVIRONMENT) { + throw std::runtime_error("as_env called on a " + object_type_to_string(type) + " " + print()); + } + return static_cast(heap_obj.get()); +} + +inline std::shared_ptr Object::as_env_ptr() const { + if (type != ObjectType::ENVIRONMENT) { + throw std::runtime_error("as_env called on a " + object_type_to_string(type) + " " + print()); + } + return std::dynamic_pointer_cast(heap_obj); +} + +inline SymbolObject* Object::as_symbol() const { + if (type != ObjectType::SYMBOL) { + throw std::runtime_error("as_symbol called on a " + object_type_to_string(type) + " " + + print()); + } + return static_cast(heap_obj.get()); +} + +inline StringObject* Object::as_string() const { + if (type != ObjectType::STRING) { + throw std::runtime_error("as_string called on a " + object_type_to_string(type) + " " + + print()); + } + return static_cast(heap_obj.get()); +} + +inline LambdaObject* Object::as_lambda() const { + if (type != ObjectType::LAMBDA) { + throw std::runtime_error("as_lambda called on a " + object_type_to_string(type) + " " + + print()); + } + return static_cast(heap_obj.get()); +} + +inline MacroObject* Object::as_macro() const { + if (type != ObjectType::MACRO) { + throw std::runtime_error("as_macro called on a " + object_type_to_string(type) + " " + print()); + } + return static_cast(heap_obj.get()); +} + +inline ArrayObject* Object::as_array() const { + if (type != ObjectType::ARRAY) { + throw std::runtime_error("as_array called on a " + object_type_to_string(type) + " " + print()); + } + return static_cast(heap_obj.get()); +} } // namespace goos diff --git a/common/goos/Reader.cpp b/common/goos/Reader.cpp index 7783854126..ad875fccad 100644 --- a/common/goos/Reader.cpp +++ b/common/goos/Reader.cpp @@ -189,7 +189,17 @@ Object Reader::read_from_string(const std::string& str, bool add_top_level) { * Read a file */ Object Reader::read_from_file(const std::vector& file_path) { - auto textFrag = std::make_shared(file_util::get_file_path(file_path)); + std::string joined_name; + + for (const auto& thing : file_path) { + if (!joined_name.empty()) { + joined_name += '/'; + } + + joined_name += thing; + } + + auto textFrag = std::make_shared(file_util::get_file_path(file_path), joined_name); db.insert(textFrag); auto result = internal_read(textFrag); @@ -524,7 +534,7 @@ Object Reader::read_list(TextStream& ts, bool expect_close_paren) { db.link(rv, ts.text, start_offset); return rv; } else { - auto rv = build_list(objects); + auto rv = build_list(std::move(objects)); db.link(rv, ts.text, start_offset); return rv; } diff --git a/common/goos/TextDB.cpp b/common/goos/TextDB.cpp index 3a274741df..3d2c1a752a 100644 --- a/common/goos/TextDB.cpp +++ b/common/goos/TextDB.cpp @@ -12,6 +12,7 @@ */ #include "common/util/FileUtil.h" +#include "third-party/fmt/core.h" #include "TextDB.h" @@ -64,6 +65,10 @@ int SourceText::get_line_idx(int offset) { std::to_string(offset)); } +int SourceText::get_offset_of_line(int line_idx) { + return offset_by_line.at(line_idx); +} + /*! * Gets the [start, end) character offset of the line containing the given offset. */ @@ -79,8 +84,9 @@ std::pair SourceText::get_containing_line(int offset) { /*! * Read text from a file. */ -FileText::FileText(std::string filename_) : filename(std::move(filename_)) { - text = file_util::read_text_file(filename); +FileText::FileText(const std::string& filename, const std::string& description_name) + : m_filename(filename), m_desc_name(description_name) { + text = file_util::read_text_file(m_filename); build_offsets(); } @@ -134,10 +140,14 @@ std::string TextDb::get_info_for(const Object& o, bool* terminate_compiler_error * Given a source text and an offset, print a description of where it is. */ std::string TextDb::get_info_for(const std::shared_ptr& frag, int offset) const { - std::string result = "text from " + frag->get_description() + - ", line: " + std::to_string(frag->get_line_idx(offset) + 1) + "\n"; + int line_idx = frag->get_line_idx(offset); + std::string result = frag->get_description() + ", line: " + std::to_string(line_idx + 1) + "\n"; result += frag->get_line_containing_offset(offset) + "\n"; - return result; + int offset_in_line = std::max(offset - frag->get_offset_of_line(line_idx), 1) - 1; + + std::string pointer(offset_in_line, ' '); + pointer += "^\n"; + return result + pointer; } /*! @@ -156,14 +166,13 @@ void TextDb::inherit_info(const Object& parent, const Object& child) { while (!children.empty()) { auto top = children.back(); children.pop_back(); - if (map.find(top->heap_obj) == map.end()) { - map[top->heap_obj] = parent_kv->second; - } - if (top->as_pair()->car.is_pair()) { - children.push_back(&top->as_pair()->car); - } - if (top->as_pair()->cdr.is_pair()) { - children.push_back(&top->as_pair()->cdr); + if (map.insert({top->heap_obj, parent_kv->second}).second) { + if (top->as_pair()->car.is_pair()) { + children.push_back(&top->as_pair()->car); + } + if (top->as_pair()->cdr.is_pair()) { + children.push_back(&top->as_pair()->cdr); + } } } } diff --git a/common/goos/TextDB.h b/common/goos/TextDB.h index abb7535206..f9bd51e4a8 100644 --- a/common/goos/TextDB.h +++ b/common/goos/TextDB.h @@ -34,6 +34,7 @@ class SourceText { virtual std::string get_description() = 0; std::string get_line_containing_offset(int offset); int get_line_idx(int offset); + int get_offset_of_line(int line_idx); // should the compiler keep looking up the stack when printing errors on this, or not? // this should return true if the text source is specific enough so that they can find what they // want @@ -73,13 +74,14 @@ class ProgramString : public SourceText { */ class FileText : public SourceText { public: - FileText(std::string filename_); + FileText(const std::string& filename, const std::string& description_name); - std::string get_description() { return filename; } + std::string get_description() { return m_desc_name; } ~FileText() = default; private: - std::string filename; + std::string m_filename; + std::string m_desc_name; }; struct TextRef { diff --git a/goalc/compiler/Compiler.cpp b/goalc/compiler/Compiler.cpp index 723252226f..800dbc856a 100644 --- a/goalc/compiler/Compiler.cpp +++ b/goalc/compiler/Compiler.cpp @@ -170,10 +170,15 @@ Val* Compiler::compile_error_guard(const goos::Object& code, Env* env) { obj_print += "..."; } bool term; - fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Location:\n"); - fmt::print(m_goos.reader.db.get_info_for(code, &term)); + auto loc_info = m_goos.reader.db.get_info_for(code, &term); + if (term) { + fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Location:\n"); + fmt::print(loc_info); + } + fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Code:\n"); fmt::print("{}\n", obj_print); + if (term) { ce.print_err_stack = false; } @@ -190,14 +195,24 @@ Val* Compiler::compile_error_guard(const goos::Object& code, Env* env) { obj_print = obj_print.substr(0, 80); obj_print += "..."; } - fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Location:\n"); - fmt::print(m_goos.reader.db.get_info_for(code)); + bool term; + auto loc_info = m_goos.reader.db.get_info_for(code, &term); + if (term) { + fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Location:\n"); + fmt::print(loc_info); + } + fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Code:\n"); fmt::print("{}\n", obj_print); + + CompilerException ce("Compiler Exception"); + if (term) { + ce.print_err_stack = false; + } std::string line(80, '-'); line.push_back('\n'); fmt::print(line); - throw e; + throw ce; } } @@ -239,7 +254,7 @@ void Compiler::color_object_file(FileEnv* env) { // regalloc_result_2.num_spilled_vars); } num_spills_in_file += regalloc_result_2.num_spills; - f->set_allocations(regalloc_result_2); + f->set_allocations(std::move(regalloc_result_2)); } else { fmt::print( "Warning: function {} failed register allocation with the v2 allocator. Falling back to " @@ -249,7 +264,7 @@ void Compiler::color_object_file(FileEnv* env) { auto regalloc_result = allocate_registers(input); m_debug_stats.num_spills_v1 += regalloc_result.num_spills; num_spills_in_file += regalloc_result.num_spills; - f->set_allocations(regalloc_result); + f->set_allocations(std::move(regalloc_result)); } } diff --git a/goalc/compiler/Compiler.h b/goalc/compiler/Compiler.h index 65eed9bc58..4f67a57869 100644 --- a/goalc/compiler/Compiler.h +++ b/goalc/compiler/Compiler.h @@ -71,8 +71,8 @@ class Compiler { Debugger m_debugger; goos::Interpreter m_goos; std::unordered_map m_symbol_types; - std::unordered_map, goos::Object> m_global_constants; - std::unordered_map, LambdaVal*> m_inlineable_functions; + std::unordered_map m_global_constants; + std::unordered_map m_inlineable_functions; CompilerSettings m_settings; bool m_throw_on_define_extern_redefinition = false; SymbolInfoMap m_symbol_info; @@ -109,6 +109,7 @@ class Compiler { Val* compile_goos_macro(const goos::Object& o, const goos::Object& macro_obj, const goos::Object& rest, + const goos::Object& name_symbol, Env* env); Val* compile_pair(const goos::Object& code, Env* env); Val* compile_integer(const goos::Object& code, Env* env); @@ -357,9 +358,9 @@ class Compiler { void throw_compiler_error(const goos::Object& code, const std::string& str, Args&&... args) { fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, "-- Compilation Error! --\n"); if (!str.empty() && str.back() == '\n') { - fmt::print(str, std::forward(args)...); + fmt::print(fmt::emphasis::bold, str, std::forward(args)...); } else { - fmt::print(str + '\n', std::forward(args)...); + fmt::print(fmt::emphasis::bold, str + '\n', std::forward(args)...); } fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Form:\n"); @@ -371,9 +372,9 @@ class Compiler { void throw_compiler_error_no_code(const std::string& str, Args&&... args) { fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, "-- Compilation Error! --\n"); if (!str.empty() && str.back() == '\n') { - fmt::print(str, std::forward(args)...); + fmt::print(fmt::emphasis::bold, str, std::forward(args)...); } else { - fmt::print(str + '\n', std::forward(args)...); + fmt::print(fmt::emphasis::bold, str + '\n', std::forward(args)...); } fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Form:\n"); diff --git a/goalc/compiler/Env.cpp b/goalc/compiler/Env.cpp index 17f5016de8..3fdbd86a47 100644 --- a/goalc/compiler/Env.cpp +++ b/goalc/compiler/Env.cpp @@ -18,8 +18,8 @@ void Env::emit(std::unique_ptr ir) { /*! * Allocate an IRegister with the given type. */ -RegVal* Env::make_ireg(TypeSpec ts, RegClass reg_class) { - return m_parent->make_ireg(std::move(ts), reg_class); +RegVal* Env::make_ireg(const TypeSpec& ts, RegClass reg_class) { + return m_parent->make_ireg(ts, reg_class); } /*! @@ -63,7 +63,7 @@ std::unordered_map& Env::get_label_map() { // Because this is the top of the environment chain, all these end the parent calls and provide // errors, or return that the items were not found. -GlobalEnv::GlobalEnv() : Env(nullptr) {} +GlobalEnv::GlobalEnv() : Env(EnvKind::OTHER_ENV, nullptr) {} std::string GlobalEnv::print() { return "global-env"; @@ -81,7 +81,7 @@ void GlobalEnv::emit(std::unique_ptr ir) { /*! * Allocate an IRegister with the given type. */ -RegVal* GlobalEnv::make_ireg(TypeSpec ts, RegClass reg_class) { +RegVal* GlobalEnv::make_ireg(const TypeSpec& ts, RegClass reg_class) { (void)ts; (void)reg_class; throw std::runtime_error("cannot alloc reg in GlobalEnv"); @@ -136,7 +136,8 @@ void NoEmitEnv::emit(std::unique_ptr ir) { // BlockEnv /////////////////// -BlockEnv::BlockEnv(Env* parent, std::string _name) : Env(parent), name(std::move(_name)) {} +BlockEnv::BlockEnv(Env* parent, std::string _name) + : Env(EnvKind::OTHER_ENV, parent), name(std::move(_name)) {} std::string BlockEnv::print() { return "block-" + name; @@ -154,7 +155,8 @@ BlockEnv* BlockEnv::find_block(const std::string& block) { // FileEnv /////////////////// -FileEnv::FileEnv(Env* parent, std::string name) : Env(parent), m_name(std::move(name)) {} +FileEnv::FileEnv(Env* parent, std::string name) + : Env(EnvKind::FILE_ENV, parent), m_name(std::move(name)) {} std::string FileEnv::print() { return "file-" + m_name; @@ -202,7 +204,7 @@ bool FileEnv::is_empty() { /////////////////// FunctionEnv::FunctionEnv(Env* parent, std::string name) - : DeclareEnv(parent), m_name(std::move(name)) {} + : DeclareEnv(EnvKind::FUNCTION_ENV, parent), m_name(std::move(name)) {} std::string FunctionEnv::print() { return "function-" + m_name; @@ -235,7 +237,7 @@ void FunctionEnv::resolve_gotos() { } } -RegVal* FunctionEnv::make_ireg(TypeSpec ts, RegClass reg_class) { +RegVal* FunctionEnv::make_ireg(const TypeSpec& ts, RegClass reg_class) { IRegister ireg; ireg.reg_class = reg_class; ireg.id = m_iregs.size(); diff --git a/goalc/compiler/Env.h b/goalc/compiler/Env.h index 4a9d4edab5..c7b585bd8e 100644 --- a/goalc/compiler/Env.h +++ b/goalc/compiler/Env.h @@ -6,9 +6,6 @@ * manages the memory for stuff generated during compiling. */ -#ifndef JAK_ENV_H -#define JAK_ENV_H - #include #include #include @@ -21,17 +18,22 @@ class FileEnv; class BlockEnv; +class FunctionEnv; +class SymbolMacroEnv; +class MacroExpandEnv; class IR; +enum class EnvKind { FILE_ENV, FUNCTION_ENV, SYMBOL_MACRO_ENV, MACRO_EXPAND_ENV, OTHER_ENV }; + /*! * Parent class for Env's */ class Env { public: - explicit Env(Env* parent) : m_parent(parent) {} + explicit Env(EnvKind kind, Env* parent); virtual std::string print() = 0; virtual void emit(std::unique_ptr ir); - virtual RegVal* make_ireg(TypeSpec ts, RegClass reg_class); + virtual RegVal* make_ireg(const TypeSpec& ts, RegClass reg_class); virtual void constrain_reg(IRegConstraint constraint); // todo, remove! virtual RegVal* lexical_lookup(goos::Object sym); virtual BlockEnv* find_block(const std::string& name); @@ -47,8 +49,22 @@ class Env { emit(std::make_unique(std::forward(args)...)); } + FileEnv* file_env() { return m_lowest_envs.file_env; } + FunctionEnv* function_env() { return m_lowest_envs.function_env; } + SymbolMacroEnv* symbol_macro_env() { return m_lowest_envs.symbol_macro_env; } + MacroExpandEnv* macro_expand_env() { return m_lowest_envs.macro_expand_env; } + protected: + EnvKind m_kind; Env* m_parent = nullptr; + + // cache of the lowest env of the given type, possibly including ourselves + struct { + FileEnv* file_env = nullptr; + FunctionEnv* function_env = nullptr; + SymbolMacroEnv* symbol_macro_env = nullptr; + MacroExpandEnv* macro_expand_env = nullptr; + } m_lowest_envs; }; /*! @@ -59,7 +75,7 @@ class GlobalEnv : public Env { GlobalEnv(); std::string print() override; void emit(std::unique_ptr ir) override; - RegVal* make_ireg(TypeSpec ts, RegClass reg_class) override; + RegVal* make_ireg(const TypeSpec& ts, RegClass reg_class) override; void constrain_reg(IRegConstraint constraint) override; RegVal* lexical_lookup(goos::Object sym) override; BlockEnv* find_block(const std::string& name) override; @@ -77,7 +93,7 @@ class GlobalEnv : public Env { */ class NoEmitEnv : public Env { public: - explicit NoEmitEnv(Env* parent) : Env(parent) {} + explicit NoEmitEnv(Env* parent) : Env(EnvKind::OTHER_ENV, parent) {} std::string print() override; void emit(std::unique_ptr ir) override; ~NoEmitEnv() = default; @@ -133,7 +149,7 @@ class FileEnv : public Env { */ class DeclareEnv : public Env { public: - explicit DeclareEnv(Env* parent) : Env(parent) {} + explicit DeclareEnv(EnvKind kind, Env* parent) : Env(kind, parent) {} virtual std::string print() = 0; ~DeclareEnv() = default; @@ -168,12 +184,12 @@ class FunctionEnv : public DeclareEnv { void set_segment(int seg) { segment = seg; } void emit(std::unique_ptr ir) override; void finish(); - RegVal* make_ireg(TypeSpec ts, RegClass reg_class) override; + RegVal* make_ireg(const TypeSpec& ts, RegClass reg_class) override; const std::vector>& code() const { return m_code; } int max_vars() const { return m_iregs.size(); } const std::vector& constraints() { return m_constraints; } void constrain(const IRegConstraint& c) { m_constraints.push_back(c); } - void set_allocations(const AllocationResult& result) { m_regalloc_result = result; } + void set_allocations(AllocationResult&& result) { m_regalloc_result = std::move(result); } RegVal* lexical_lookup(goos::Object sym) override; const AllocationResult& alloc_result() { return m_regalloc_result; } bool needs_aligned_stack() const { return m_aligned_stack_required; } @@ -250,7 +266,7 @@ class BlockEnv : public Env { class LexicalEnv : public DeclareEnv { public: - explicit LexicalEnv(Env* parent) : DeclareEnv(parent) {} + explicit LexicalEnv(Env* parent) : DeclareEnv(EnvKind::OTHER_ENV, parent) {} RegVal* lexical_lookup(goos::Object sym) override; std::string print() override; std::unordered_map vars; @@ -258,7 +274,7 @@ class LexicalEnv : public DeclareEnv { class LabelEnv : public Env { public: - explicit LabelEnv(Env* parent) : Env(parent) {} + explicit LabelEnv(Env* parent) : Env(EnvKind::OTHER_ENV, parent) {} std::string print() override { return "labelenv"; } std::unordered_map& get_label_map() override; BlockEnv* find_block(const std::string& name) override; @@ -267,22 +283,51 @@ class LabelEnv : public Env { std::unordered_map m_labels; }; -class WithInlineEnv : public Env { - public: - WithInlineEnv(Env* parent, bool _inline_preference) - : Env(parent), inline_preference(_inline_preference) {} - bool inline_preference = false; -}; - class SymbolMacroEnv : public Env { public: - explicit SymbolMacroEnv(Env* parent) : Env(parent) {} - std::unordered_map, goos::Object> macros; + explicit SymbolMacroEnv(Env* parent) : Env(EnvKind::SYMBOL_MACRO_ENV, parent) {} + // key is goos symbols. + std::unordered_map macros; std::string print() override { return "symbol-macro-env"; } }; +class MacroExpandEnv : public Env { + public: + MacroExpandEnv(Env* parent, + const goos::HeapObject* macro_name, + const goos::Object& macro_body, + const goos::Object& macro_use) + : Env(EnvKind::MACRO_EXPAND_ENV, parent), + m_macro_name(macro_name), + m_macro_body(macro_body), + m_macro_use_location(macro_use) { + MacroExpandEnv* parent_macro = nullptr; + if (parent) { + parent_macro = parent->macro_expand_env(); + } + if (parent_macro) { + m_root_form = parent_macro->m_root_form; + } else { + m_root_form = m_macro_use_location; + } + } + + std::string print() override { return "macro-env"; } + + const goos::HeapObject* name() const { return m_macro_name; } + const goos::Object& macro_body() const { return m_macro_body; } + const goos::Object& macro_use_location() const { return m_macro_use_location; } + const goos::Object& root_form() const { return m_root_form; } + + private: + const goos::HeapObject* m_macro_name = nullptr; + goos::Object m_macro_body; + goos::Object m_macro_use_location; + goos::Object m_root_form; +}; + template -T* get_parent_env_of_type(Env* in) { +T* get_parent_env_of_type_slow(Env* in) { for (;;) { auto attempt = dynamic_cast(in); if (attempt) @@ -293,11 +338,29 @@ T* get_parent_env_of_type(Env* in) { in = in->parent(); } } -// function -// block -// lexical -// label -// symbolmacro -// get parent env of type. -#endif // JAK_ENV_H +inline Env::Env(EnvKind kind, Env* parent) : m_kind(kind), m_parent(parent) { + if (m_kind == EnvKind::FILE_ENV) { + m_lowest_envs.file_env = static_cast(this); + } else { + m_lowest_envs.file_env = m_parent ? m_parent->m_lowest_envs.file_env : nullptr; + } + + if (m_kind == EnvKind::FUNCTION_ENV) { + m_lowest_envs.function_env = static_cast(this); + } else { + m_lowest_envs.function_env = m_parent ? m_parent->m_lowest_envs.function_env : nullptr; + } + + if (m_kind == EnvKind::SYMBOL_MACRO_ENV) { + m_lowest_envs.symbol_macro_env = static_cast(this); + } else { + m_lowest_envs.symbol_macro_env = m_parent ? m_parent->m_lowest_envs.symbol_macro_env : nullptr; + } + + if (m_kind == EnvKind::MACRO_EXPAND_ENV) { + m_lowest_envs.macro_expand_env = static_cast(this); + } else { + m_lowest_envs.macro_expand_env = m_parent ? m_parent->m_lowest_envs.macro_expand_env : nullptr; + } +} diff --git a/goalc/compiler/Util.cpp b/goalc/compiler/Util.cpp index e12b3810a2..77be5dd816 100644 --- a/goalc/compiler/Util.cpp +++ b/goalc/compiler/Util.cpp @@ -130,12 +130,12 @@ TypeSpec Compiler::parse_typespec(const goos::Object& src) { bool Compiler::is_local_symbol(const goos::Object& obj, Env* env) { // check in the symbol macro env. - auto mlet_env = get_parent_env_of_type(env); + auto mlet_env = env->symbol_macro_env(); while (mlet_env) { if (mlet_env->macros.find(obj.as_symbol()) != mlet_env->macros.end()) { return true; } - mlet_env = get_parent_env_of_type(mlet_env->parent()); + mlet_env = mlet_env->parent()->symbol_macro_env(); } // check lexical diff --git a/goalc/compiler/Val.cpp b/goalc/compiler/Val.cpp index deb2f47620..71aa0423cd 100644 --- a/goalc/compiler/Val.cpp +++ b/goalc/compiler/Val.cpp @@ -250,7 +250,7 @@ std::string BitFieldVal::print() const { RegVal* BitFieldVal::to_reg(Env* env) { int start_bit = -1; - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); RegVal* result = fe->make_ireg(coerce_to_reg_type(m_ts), RegClass::GPR_64); // this first step gets the right 64-bits into a GPR that is also used as the result. diff --git a/goalc/compiler/compilation/Asm.cpp b/goalc/compiler/compilation/Asm.cpp index 4ca2d27481..05b6dc3e54 100644 --- a/goalc/compiler/compilation/Asm.cpp +++ b/goalc/compiler/compilation/Asm.cpp @@ -33,7 +33,7 @@ Val* Compiler::compile_rlet(const goos::Object& form, const goos::Object& rest, auto defs = args.unnamed.front(); - auto fenv = get_parent_env_of_type(env); + auto fenv = env->function_env(); auto lenv = fenv->alloc_env(env); std::vector constraints; diff --git a/goalc/compiler/compilation/Atoms.cpp b/goalc/compiler/compilation/Atoms.cpp index 75e7b05a7d..5006faa2e4 100644 --- a/goalc/compiler/compilation/Atoms.cpp +++ b/goalc/compiler/compilation/Atoms.cpp @@ -302,7 +302,7 @@ Val* Compiler::compile_pair(const goos::Object& code, Env* env) { // next try as a macro goos::Object macro_obj; if (try_getting_macro_from_goos(head, ¯o_obj)) { - return compile_goos_macro(code, macro_obj, rest, env); + return compile_goos_macro(code, macro_obj, rest, head, env); } // next try as an enum @@ -339,12 +339,12 @@ Val* Compiler::compile_char(const goos::Object& code, Env* env) { * The type is always int. */ Val* Compiler::compile_integer(s64 value, Env* env) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); return fe->alloc_val(m_ts.make_typespec("int"), &value, 8); } Val* Compiler::compile_integer(const U128& value, Env* env) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); return fe->alloc_val(m_ts.make_typespec("int"), &value, 16); } @@ -352,7 +352,7 @@ Val* Compiler::compile_integer(const U128& value, Env* env) { * Get a SymbolVal representing a GOAL symbol object. */ SymbolVal* Compiler::compile_get_sym_obj(const std::string& name, Env* env) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); return fe->alloc_val(name, m_ts.make_typespec("symbol")); } @@ -372,7 +372,7 @@ Val* Compiler::compile_get_symbol_value(const goos::Object& form, auto ts = existing_symbol->second; auto sext = m_ts.lookup_type(ts)->get_load_signed(); - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto sym = fe->alloc_val(name, m_ts.make_typespec("symbol")); auto re = fe->alloc_val(sym, ts, sext); return re; @@ -391,13 +391,13 @@ Val* Compiler::compile_symbol(const goos::Object& form, Env* env) { } // see if the symbol is defined in any enclosing symbol macro envs (mlet's). - auto mlet_env = get_parent_env_of_type(env); + auto mlet_env = env->symbol_macro_env(); while (mlet_env) { auto mlkv = mlet_env->macros.find(form.as_symbol()); if (mlkv != mlet_env->macros.end()) { return compile_error_guard(mlkv->second, env); } - mlet_env = get_parent_env_of_type(mlet_env->parent()); + mlet_env = mlet_env->parent()->symbol_macro_env(); } // see if it's a local variable @@ -430,7 +430,7 @@ Val* Compiler::compile_symbol(const goos::Object& form, Env* env) { * Compile a string constant. The constant is placed in the same segment as the parent function. */ Val* Compiler::compile_string(const goos::Object& form, Env* env) { - auto segment = get_parent_env_of_type(env)->segment; + auto segment = env->function_env()->segment; if (segment == TOP_LEVEL_SEGMENT) { segment = MAIN_SEGMENT; } @@ -442,9 +442,9 @@ Val* Compiler::compile_string(const goos::Object& form, Env* env) { */ Val* Compiler::compile_string(const std::string& str, Env* env, int seg) { auto obj = std::make_unique(str, seg); - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto result = fe->alloc_val(obj.get(), m_ts.make_typespec("string")); - auto fie = get_parent_env_of_type(env); + auto fie = env->file_env(); fie->add_static(std::move(obj)); return result; } @@ -455,7 +455,7 @@ Val* Compiler::compile_string(const std::string& str, Env* env, int seg) { * of the code, at least in Jak 1. */ Val* Compiler::compile_float(const goos::Object& code, Env* env) { - auto segment = get_parent_env_of_type(env)->segment; + auto segment = env->function_env()->segment; if (segment == TOP_LEVEL_SEGMENT) { segment = MAIN_SEGMENT; } @@ -470,9 +470,9 @@ Val* Compiler::compile_float(const goos::Object& code, Env* env) { */ Val* Compiler::compile_float(float value, Env* env, int seg) { auto obj = std::make_unique(value, seg); - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto result = fe->alloc_val(m_ts.make_typespec("float"), obj.get()); - auto fie = get_parent_env_of_type(env); + auto fie = env->file_env(); fie->add_static(std::move(obj)); return result; } diff --git a/goalc/compiler/compilation/Block.cpp b/goalc/compiler/compilation/Block.cpp index f4ab79154f..260ef39e16 100644 --- a/goalc/compiler/compilation/Block.cpp +++ b/goalc/compiler/compilation/Block.cpp @@ -47,7 +47,7 @@ Val* Compiler::compile_block(const goos::Object& form, const goos::Object& _rest throw_compiler_error(form, "Block form has an empty or invalid body"); } - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); // create environment auto block_env = fe->alloc_env(env, symbol_string(name)); @@ -116,7 +116,7 @@ Val* Compiler::compile_return_from(const goos::Object& form, const goos::Object& // evaluate expression to return auto result = compile_error_guard(value_expression, env); - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); // find block to return from auto block = dynamic_cast(env->find_block(block_name)); @@ -163,7 +163,7 @@ Val* Compiler::compile_label(const goos::Object& form, const goos::Object& rest, // make a label pointing to the end of the current function env. safe because we'll always add // a terminating "null" instruction at the end. - auto func_env = get_parent_env_of_type(env); + auto func_env = env->function_env(); labels[label_name] = Label(func_env, func_env->code().size()); return get_none(); } @@ -182,7 +182,7 @@ Val* Compiler::compile_goto(const goos::Object& form, const goos::Object& rest, // add this goto to the list of gotos to resolve after the function is done. // it's safe to have this reference, as the FunctionEnv also owns the goto. - get_parent_env_of_type(env)->unresolved_gotos.push_back({ir_goto.get(), label_name}); + env->function_env()->unresolved_gotos.push_back({ir_goto.get(), label_name}); env->emit(std::move(ir_goto)); return get_none(); } diff --git a/goalc/compiler/compilation/CompilerControl.cpp b/goalc/compiler/compilation/CompilerControl.cpp index 9a96edac32..41deefb0a2 100644 --- a/goalc/compiler/compilation/CompilerControl.cpp +++ b/goalc/compiler/compilation/CompilerControl.cpp @@ -49,7 +49,7 @@ Val* Compiler::compile_seval(const goos::Object& form, const goos::Object& rest, (void)env; try { for_each_in_list(rest, [&](const goos::Object& o) { - m_goos.eval_with_rewind(o, m_goos.global_environment.as_env()); + m_goos.eval_with_rewind(o, m_goos.global_environment.as_env_ptr()); }); } catch (std::runtime_error& e) { throw_compiler_error(form, "Error while evaluating GOOS: {}", e.what()); @@ -398,7 +398,7 @@ std::string Compiler::make_symbol_info_description(const SymbolInfo& info) { case SymbolInfo::Kind::CONSTANT: return fmt::format( "[Constant] Name: {} Value: {} Defined: {}", info.name(), - m_global_constants.at(m_goos.reader.symbolTable.intern(info.name())).print(), + m_global_constants.at(m_goos.reader.symbolTable.intern_ptr(info.name())).print(), m_goos.reader.db.get_info_for(info.src_form())); case SymbolInfo::Kind::FUNCTION: return fmt::format("[Function] Name: {} Defined: {}", info.name(), diff --git a/goalc/compiler/compilation/ControlFlow.cpp b/goalc/compiler/compilation/ControlFlow.cpp index d7625d34ce..a79cc11eff 100644 --- a/goalc/compiler/compilation/ControlFlow.cpp +++ b/goalc/compiler/compilation/ControlFlow.cpp @@ -125,7 +125,7 @@ Val* Compiler::compile_condition_as_bool(const goos::Object& form, (void)rest; auto c = compile_condition(form, env, true); auto result = compile_get_sym_obj("#f", env)->to_gpr(env); // todo - can be optimized. - Label label(get_parent_env_of_type(env), -5); + Label label(env->function_env(), -5); auto branch_ir = std::make_unique(c, label); auto branch_ir_ref = branch_ir.get(); env->emit(std::move(branch_ir)); @@ -155,7 +155,7 @@ Val* Compiler::compile_when_goto(const goos::Object& form, const goos::Object& _ // compile as condition (will set flags register with a cmp instruction) auto condition = compile_condition(condition_code, env, false); auto branch = std::make_unique(condition, Label()); - get_parent_env_of_type(env)->unresolved_cond_gotos.push_back({branch.get(), label}); + env->function_env()->unresolved_cond_gotos.push_back({branch.get(), label}); env->emit(std::move(branch)); return get_none(); } @@ -169,7 +169,7 @@ Val* Compiler::compile_when_goto(const goos::Object& form, const goos::Object& _ Val* Compiler::compile_cond(const goos::Object& form, const goos::Object& rest, Env* env) { auto result = env->make_gpr(m_ts.make_typespec("object")); - auto fenv = get_parent_env_of_type(env); + auto fenv = env->function_env(); auto end_label = fenv->alloc_unnamed_label(); end_label->func = fenv; end_label->idx = -3; // placeholder @@ -276,7 +276,7 @@ Val* Compiler::compile_and_or(const goos::Object& form, const goos::Object& rest } auto result = env->make_gpr(m_ts.make_typespec("object")); // temp type for now. - auto fenv = get_parent_env_of_type(env); + auto fenv = env->function_env(); auto end_label = fenv->alloc_unnamed_label(); end_label->func = fenv; end_label->idx = -4; // placeholder diff --git a/goalc/compiler/compilation/Define.cpp b/goalc/compiler/compilation/Define.cpp index b7aee7f071..10b7405f2f 100644 --- a/goalc/compiler/compilation/Define.cpp +++ b/goalc/compiler/compilation/Define.cpp @@ -24,7 +24,7 @@ Val* Compiler::compile_define(const goos::Object& form, const goos::Object& rest sym.print(), global_constant->second.print()); } - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto sym_val = fe->alloc_val(symbol_string(sym), m_ts.make_typespec("symbol")); auto compiled_val = compile_error_guard(val, env); auto as_lambda = dynamic_cast(compiled_val); @@ -137,7 +137,7 @@ void Compiler::set_bitfield(const goos::Object& form, BitFieldVal* dst, RegVal* return; } - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); // first, get the value we want to modify: auto original_original = dst->parent()->to_gpr(env); @@ -151,7 +151,7 @@ void Compiler::set_bitfield(const goos::Object& form, BitFieldVal* dst, RegVal* } void Compiler::set_bitfield_128(const goos::Object& form, BitFieldVal* dst, RegVal* src, Env* env) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); bool get_top = dst->offset() >= 64; @@ -220,7 +220,7 @@ Val* Compiler::do_set(const goos::Object& form, Val* dest, RegVal* src_in_reg, V // we want to allow setting a 128-bit field from a 64-bit variable. if (as_mem_deref->info.size == 16) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto src_128 = fe->make_ireg(src_in_reg->type(), RegClass::INT_128); env->emit_ir(src_128, src_in_reg); src_in_reg = src_128; @@ -229,7 +229,7 @@ Val* Compiler::do_set(const goos::Object& form, Val* dest, RegVal* src_in_reg, V // we want to allow setting a smaller thing from a 128-bit variable if (as_mem_deref->info.size != 16 && (src_in_reg->ireg().reg_class == RegClass::VECTOR_FLOAT || src_in_reg->ireg().reg_class == RegClass::INT_128)) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto src_gpr = fe->make_ireg(src_in_reg->type(), RegClass::GPR_64); env->emit_ir(src_gpr, src_in_reg); src_in_reg = src_gpr; @@ -237,7 +237,7 @@ Val* Compiler::do_set(const goos::Object& form, Val* dest, RegVal* src_in_reg, V // we want to allow setting a 64-bit place to a float if (as_mem_deref->info.size == 8 && src_in_reg->ireg().reg_class == RegClass::FLOAT) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto src_gpr = fe->make_ireg(src_in_reg->type(), RegClass::GPR_64); env->emit_ir(src_gpr, src_in_reg); src_in_reg = src_gpr; diff --git a/goalc/compiler/compilation/Function.cpp b/goalc/compiler/compilation/Function.cpp index e473d007db..b21eff1dec 100644 --- a/goalc/compiler/compilation/Function.cpp +++ b/goalc/compiler/compilation/Function.cpp @@ -8,17 +8,6 @@ #include "third-party/fmt/core.h" namespace { -/*! - * Get the preference to inline of the given environment. - */ -bool get_inline_preference(Env* env) { - auto ile = get_parent_env_of_type(env); - if (ile) { - return ile->inline_preference; - } else { - return false; - } -} /*! * Hacky function to seek past arguments to get a goos::Object containing the body of a lambda. @@ -61,12 +50,12 @@ Val* Compiler::compile_inline(const goos::Object& form, const goos::Object& rest throw_compiler_error(form, "Cannot inline {} because inlining of this function was disallowed."); } - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); return fe->alloc_val(kv->second->type(), kv->second); } Val* Compiler::compile_local_vars(const goos::Object& form, const goos::Object& rest, Env* env) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); for_each_in_list(rest, [&](const goos::Object& o) { if (o.is_symbol()) { @@ -112,8 +101,8 @@ Val* Compiler::compile_local_vars(const goos::Object& form, const goos::Object& * confusing special cases... */ Val* Compiler::compile_lambda(const goos::Object& form, const goos::Object& rest, Env* env) { - auto fe = get_parent_env_of_type(env); - auto obj_env = get_parent_env_of_type(env); + auto fe = env->function_env(); + auto obj_env = env->file_env(); auto args = get_va(form, rest); if (args.unnamed.empty() || !args.unnamed.front().is_list() || !args.only_contains_named({"name", "inline-only", "segment", "behavior"})) { @@ -329,7 +318,7 @@ Val* Compiler::compile_lambda(const goos::Object& form, const goos::Object& rest */ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* env) { goos::Object f = form; - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto args = get_va(form, form); auto uneval_head = args.unnamed.at(0); @@ -347,9 +336,8 @@ Val* Compiler::compile_function_or_method_call(const goos::Object& form, Env* en if (kv->second->func == nullptr || // only-inline, we must inline it as there is no code generated for it kv->second->func->settings - .inline_by_default || // inline when possible, so we should inline - (kv->second->func->settings.allow_inline && - get_inline_preference(env))) { // inline is allowed, and we prefer it locally + .inline_by_default) { // inline when possible, so we should inline + auto_inline = true; head = kv->second; } @@ -588,7 +576,7 @@ Val* Compiler::compile_real_function_call(const goos::Object& form, const std::vector& args, Env* env, const std::string& method_type_name) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); fe->require_aligned_stack(); TypeSpec return_ts; if (function->type().arg_count() == 0) { @@ -660,7 +648,7 @@ Val* Compiler::compile_real_function_call(const goos::Object& form, * Currently there aren't many useful settings, but more may be added in the future. */ Val* Compiler::compile_declare(const goos::Object& form, const goos::Object& rest, Env* env) { - auto& settings = get_parent_env_of_type(env)->settings; + auto& settings = get_parent_env_of_type_slow(env)->settings; if (settings.is_set) { throw_compiler_error(form, "Function cannot have multiple declares"); @@ -696,7 +684,7 @@ Val* Compiler::compile_declare(const goos::Object& form, const goos::Object& res settings.inline_by_default = false; settings.save_code = true; } else if (first.as_symbol()->name == "asm-func") { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); fe->is_asm_func = true; if (!rrest->is_pair()) { throw_compiler_error( @@ -716,7 +704,7 @@ Val* Compiler::compile_declare(const goos::Object& form, const goos::Object& res if (!rrest->is_empty_list()) { throw_compiler_error(first, "Invalid allow-saved-regs declare"); } - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); fe->asm_func_saved_regs = true; } else { diff --git a/goalc/compiler/compilation/Macro.cpp b/goalc/compiler/compilation/Macro.cpp index bf68d38101..d25624cce4 100644 --- a/goalc/compiler/compilation/Macro.cpp +++ b/goalc/compiler/compilation/Macro.cpp @@ -1,5 +1,6 @@ #include "goalc/compiler/Compiler.h" #include "third-party/fmt/core.h" +#include "common/goos/PrettyPrinter.h" using namespace goos; @@ -9,7 +10,7 @@ using namespace goos; bool Compiler::try_getting_macro_from_goos(const goos::Object& macro_name, goos::Object* dest) { Object macro_obj; bool got_macro = false; - if (m_goos.eval_symbol(macro_name, m_goos.goal_env.as_env(), ¯o_obj) && + if (m_goos.eval_symbol(macro_name, m_goos.goal_env.as_env_ptr(), ¯o_obj) && macro_obj.is_macro()) { got_macro = true; } @@ -26,20 +27,60 @@ bool Compiler::try_getting_macro_from_goos(const goos::Object& macro_name, goos: Val* Compiler::compile_goos_macro(const goos::Object& o, const goos::Object& macro_obj, const goos::Object& rest, + const goos::Object& name, Env* env) { auto macro = macro_obj.as_macro(); Arguments args = m_goos.get_args(o, rest, macro->args); auto mac_env_obj = EnvironmentObject::make_new(); - auto mac_env = mac_env_obj.as_env(); - mac_env->parent_env = m_goos.global_environment.as_env(); + auto mac_env = mac_env_obj.as_env_ptr(); + mac_env->parent_env = m_goos.global_environment.as_env_ptr(); m_goos.set_args_in_env(o, args, macro->args, mac_env); - m_goos.goal_to_goos.enclosing_method_type = - get_parent_env_of_type(env)->method_of_type_name; + m_goos.goal_to_goos.enclosing_method_type = env->function_env()->method_of_type_name; auto goos_result = m_goos.eval_list_return_last(macro->body, macro->body, mac_env); // make the macro expanded form point to the source where the macro was used for error messages. - m_goos.reader.db.inherit_info(o, goos_result); + // m_goos.reader.db.inherit_info(o, goos_result); m_goos.goal_to_goos.reset(); - return compile_error_guard(goos_result, env); + + auto compile_env_for_macro = + env->function_env()->alloc_env(env, name.as_symbol(), macro->body, o); + try { + return compile(goos_result, compile_env_for_macro); + } catch (CompilerException& ce) { + if (ce.print_err_stack) { + bool good_info = false; + auto info = m_goos.reader.db.get_info_for(o, &good_info); + fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Code:\n"); + fmt::print("{}\n", pretty_print::to_string(goos_result, 120)); + fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "From macro: "); + fmt::print(fg(fmt::color::orange), "{}\n", name.print()); + if (good_info) { + fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Used in:\n"); + fmt::print("{}\n", info); + ce.print_err_stack = false; + } + std::string line(80, '-'); + line.push_back('\n'); + fmt::print(line); + } + + throw; + } catch (std::runtime_error& e) { + bool good_info = false; + auto info = m_goos.reader.db.get_info_for(o, &good_info); + fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Code:\n"); + fmt::print("{}\n", pretty_print::to_string(goos_result, 120)); + fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "From macro: "); + fmt::print(fg(fmt::color::orange), "{}\n", name.print()); + if (good_info) { + fmt::print(fg(fmt::color::yellow) | fmt::emphasis::bold, "Used in:\n"); + fmt::print("{}\n", info); + } + std::string line(80, '-'); + line.push_back('\n'); + fmt::print(line); + + throw; + } } /*! @@ -60,8 +101,8 @@ Val* Compiler::compile_gscond(const goos::Object& form, const goos::Object& rest } // check condition: - Object condition_result = - m_goos.eval_with_rewind(current_case.as_pair()->car, m_goos.global_environment.as_env()); + Object condition_result = m_goos.eval_with_rewind(current_case.as_pair()->car, + m_goos.global_environment.as_env_ptr()); if (m_goos.truthy(condition_result)) { if (current_case.as_pair()->cdr.is_empty_list()) { return get_none(); @@ -176,7 +217,7 @@ Val* Compiler::compile_mlet(const goos::Object& form, const goos::Object& rest, auto defs = pair_car(rest); auto body = pair_cdr(rest); - auto fenv = get_parent_env_of_type(env); + auto fenv = env->function_env(); auto menv = fenv->alloc_env(env); for_each_in_list(defs, [&](const goos::Object& o) { @@ -214,13 +255,13 @@ bool Compiler::expand_macro_once(const goos::Object& src, goos::Object* out, Env auto macro = macro_obj.as_macro(); Arguments args = m_goos.get_args(src, rest, macro->args); auto mac_env_obj = EnvironmentObject::make_new(); - auto mac_env = mac_env_obj.as_env(); - mac_env->parent_env = m_goos.global_environment.as_env(); + auto mac_env = mac_env_obj.as_env_ptr(); + mac_env->parent_env = m_goos.global_environment.as_env_ptr(); m_goos.set_args_in_env(src, args, macro->args, mac_env); auto goos_result = m_goos.eval_list_return_last(macro->body, macro->body, mac_env); // make the macro expanded form point to the source where the macro was used for error messages. - m_goos.reader.db.inherit_info(src, goos_result); + // m_goos.reader.db.inherit_info(src, goos_result); *out = goos_result; return true; diff --git a/goalc/compiler/compilation/Math.cpp b/goalc/compiler/compilation/Math.cpp index 2f85e2ae3a..2e898752c9 100644 --- a/goalc/compiler/compilation/Math.cpp +++ b/goalc/compiler/compilation/Math.cpp @@ -43,7 +43,7 @@ Val* Compiler::number_to_integer(const goos::Object& form, Val* in, Env* env) { if (is_binteger(ts)) { throw_compiler_error(form, "Cannot convert {} (a binteger) to an integer yet.", in->print()); } else if (is_float(ts)) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto result = fe->make_gpr(m_ts.make_typespec("int")); env->emit(std::make_unique(result, in->to_fpr(env))); return result; @@ -62,7 +62,7 @@ Val* Compiler::number_to_binteger(const goos::Object& form, Val* in, Env* env) { } else if (is_float(ts)) { throw_compiler_error(form, "Cannot convert {} (a float) to an integer yet.", in->print()); } else if (is_integer(ts)) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); RegVal* input = in->to_reg(env); auto sa = fe->make_gpr(m_ts.make_typespec("int")); env->emit(std::make_unique(sa, 3)); @@ -82,7 +82,7 @@ Val* Compiler::number_to_float(const goos::Object& form, Val* in, Env* env) { } else if (is_float(ts)) { return in; } else if (is_integer(ts)) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto result = fe->make_fpr(m_ts.make_typespec("float")); env->emit(std::make_unique(result, in->to_gpr(env))); return result; @@ -339,8 +339,7 @@ Val* Compiler::compile_sub(const goos::Object& form, const goos::Object& rest, E case MATH_FLOAT: if (args.unnamed.size() == 1) { - auto result = - compile_float(0, env, get_parent_env_of_type(env)->segment)->to_fpr(env); + auto result = compile_float(0, env, env->function_env()->segment)->to_fpr(env); env->emit(std::make_unique( FloatMathKind::SUB_SS, result, to_math_type(form, compile_error_guard(args.unnamed.at(0), env), math_type, env) @@ -382,7 +381,7 @@ Val* Compiler::compile_div(const goos::Object& form, const goos::Object& rest, E auto math_type = get_math_mode(first_type); switch (math_type) { case MATH_INT: { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto first_thing = first_val->to_gpr(env); auto result = env->make_gpr(first_type); env->emit(std::make_unique(result, first_thing)); @@ -458,7 +457,7 @@ Val* Compiler::compile_variable_shift(const goos::Object& form, env->emit(std::make_unique(result, in)); env->emit(std::make_unique(sa_in, sa)); - auto fenv = get_parent_env_of_type(env); + auto fenv = env->function_env(); IRegConstraint sa_con; sa_con.ireg = sa_in->ireg(); @@ -550,7 +549,7 @@ Val* Compiler::compile_mod(const goos::Object& form, const goos::Object& rest, E va_check(form, args, {{}, {}}, {}); auto first = compile_error_guard(args.unnamed.at(0), env)->to_gpr(env); auto second = compile_error_guard(args.unnamed.at(1), env)->to_gpr(env); - auto fenv = get_parent_env_of_type(env); + auto fenv = env->function_env(); if (get_math_mode(first->type()) != MathMode::MATH_INT || get_math_mode(second->type()) != MathMode::MATH_INT) { diff --git a/goalc/compiler/compilation/State.cpp b/goalc/compiler/compilation/State.cpp index aed951b3a1..b274ba764a 100644 --- a/goalc/compiler/compilation/State.cpp +++ b/goalc/compiler/compilation/State.cpp @@ -73,8 +73,7 @@ Val* Compiler::compile_define_state_hook(const goos::Object& form, state_name, existing_var->second.print(), state_type.print()); } m_symbol_types[state_name] = state_type; - auto sym_val = - get_parent_env_of_type(env)->alloc_val(state_name, state_type); + auto sym_val = env->function_env()->alloc_val(state_name, state_type); env->emit(std::make_unique(sym_val, state_object)); return get_none(); diff --git a/goalc/compiler/compilation/Static.cpp b/goalc/compiler/compilation/Static.cpp index 68a9c62403..19de671bda 100644 --- a/goalc/compiler/compilation/Static.cpp +++ b/goalc/compiler/compilation/Static.cpp @@ -265,7 +265,7 @@ StaticResult Compiler::compile_new_static_structure(const goos::Object& form, obj->data.resize(type_info->get_size_in_memory()); compile_static_structure_inline(form, type, _field_defs, obj.get(), 0, env); - auto fie = get_parent_env_of_type(env); + auto fie = env->file_env(); auto result = StaticResult::make_structure_reference(obj.get(), type); fie->add_static(std::move(obj)); return result; @@ -444,7 +444,7 @@ Val* Compiler::compile_bitfield_definition(const goos::Object& form, if (use_128) { auto integer_lo = compile_integer(constant_integer_part.lo, env)->to_gpr(env); auto integer_hi = compile_integer(constant_integer_part.hi, env)->to_gpr(env); - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto rv = fe->make_ireg(type, RegClass::INT_128); auto xmm_temp = fe->make_ireg(TypeSpec("object"), RegClass::INT_128); @@ -529,8 +529,8 @@ Val* Compiler::compile_bitfield_definition(const goos::Object& form, * - Strings */ StaticResult Compiler::compile_static_no_eval_for_pairs(const goos::Object& form, Env* env) { - auto fie = get_parent_env_of_type(env); - auto fe = get_parent_env_of_type(env); + auto fie = env->file_env(); + auto fe = env->function_env(); auto segment = fe->segment; if (segment == TOP_LEVEL_SEGMENT) { segment = MAIN_SEGMENT; @@ -586,8 +586,8 @@ StaticResult Compiler::compile_static_no_eval_for_pairs(const goos::Object& form */ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env* env) { auto form = expand_macro_completely(form_before_macro, env); - auto fie = get_parent_env_of_type(env); - auto fe = get_parent_env_of_type(env); + auto fie = env->file_env(); + auto fe = env->function_env(); auto segment = fe->segment; if (segment == TOP_LEVEL_SEGMENT) { segment = MAIN_SEGMENT; @@ -804,7 +804,7 @@ void Compiler::fill_static_array_inline(const goos::Object& form, StaticResult Compiler::fill_static_array(const goos::Object& form, const goos::Object& rest, Env* env) { - auto fie = get_parent_env_of_type(env); + auto fie = env->file_env(); // (new 'static 'boxed-array ...) // get all arguments now auto args = get_list_as_vector(rest); @@ -843,7 +843,7 @@ StaticResult Compiler::fill_static_array(const goos::Object& form, StaticResult Compiler::fill_static_boxed_array(const goos::Object& form, const goos::Object& rest, Env* env) { - auto fie = get_parent_env_of_type(env); + auto fie = env->file_env(); // (new 'static 'boxed-array ...) // get all arguments now // auto args = get_list_as_vector(rest); @@ -975,7 +975,7 @@ void Compiler::fill_static_inline_array_inline(const goos::Object& form, StaticResult Compiler::fill_static_inline_array(const goos::Object& form, const goos::Object& rest, Env* env) { - auto fie = get_parent_env_of_type(env); + auto fie = env->file_env(); // (new 'static 'inline-array ...) // get all arguments now auto args = get_list_as_vector(rest); @@ -1011,7 +1011,7 @@ Val* Compiler::compile_static_pair(const goos::Object& form, Env* env) { assert(form.is_pair()); // (quote PAIR) auto result = compile_static_no_eval_for_pairs(form, env); assert(result.is_reference()); - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto static_result = fe->alloc_val(result.reference(), result.typespec()); return static_result; } @@ -1020,7 +1020,7 @@ Val* Compiler::compile_new_static_structure_or_basic(const goos::Object& form, const TypeSpec& type, const goos::Object& field_defs, Env* env) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto sr = compile_new_static_structure(form, type, field_defs, env); auto result = fe->alloc_val(sr.reference(), type); return result; diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index dc510d6820..9186b89406 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -33,7 +33,7 @@ RegVal* Compiler::compile_get_method_of_type(const goos::Object& /*form*/, auto offset_of_method = get_offset_of_method(info.id); assert(type->type() == TypeSpec("type")); - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); MemLoadInfo load_info; load_info.sign_extend = false; @@ -87,7 +87,7 @@ RegVal* Compiler::compile_get_method_of_object(const goos::Object& form, } method_info.type = method_info.type.substitute_for_method_call(compile_time_type.base_type()); - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); RegVal* runtime_type = nullptr; if (m_ts.should_use_virtual_methods(compile_time_type, method_info.id)) { @@ -126,8 +126,7 @@ Val* Compiler::compile_format_string(const goos::Object& form, const std::string& out_stream) { // Add first two format args args.insert(args.begin(), - compile_string(fmt_template, env, get_parent_env_of_type(env)->segment) - ->to_gpr(env)); + compile_string(fmt_template, env, env->function_env()->segment)->to_gpr(env)); args.insert(args.begin(), compile_get_sym_obj(out_stream, env)->to_gpr(env)); // generate code in the method_env @@ -268,10 +267,10 @@ Val* Compiler::generate_inspector_for_structure_type(const goos::Object& form, emitter::gRegInfo.get_gpr_ret_reg()); // add this function to the object file - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto method = fe->alloc_val(m_ts.make_typespec("function")); method->func = method_env.get(); - auto obj_env_inspect = get_parent_env_of_type(method_env.get()); + auto obj_env_inspect = method_env->file_env(); obj_env_inspect->add_function(std::move(method_env)); // call method-set! @@ -339,10 +338,10 @@ Val* Compiler::generate_inspector_for_bitfield_type(const goos::Object& form, } // add this function to the object file - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto method = fe->alloc_val(m_ts.make_typespec("function")); method->func = method_env.get(); - auto obj_env_inspect = get_parent_env_of_type(method_env.get()); + auto obj_env_inspect = method_env->file_env(); obj_env_inspect->add_function(std::move(method_env)); // call method-set! @@ -407,7 +406,7 @@ Val* Compiler::compile_deftype(const goos::Object& form, const goos::Object& res * Compile a (defmethod ...) form */ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _rest, Env* env) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto* rest = &_rest; auto& method_name = pair_car(*rest); @@ -576,7 +575,7 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _ new_func_env->emit(std::make_unique()); new_func_env->finish(); - auto obj_env = get_parent_env_of_type(new_func_env.get()); + auto obj_env = new_func_env->file_env(); assert(obj_env); if (new_func_env->settings.save_code) { obj_env->add_function(std::move(new_func_env)); @@ -600,7 +599,7 @@ Val* Compiler::get_field_of_structure(const StructureType* type, Val* object, const std::string& field_name, Env* env) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); Val* result = nullptr; int offset = -type->get_offset(); auto field = m_ts.lookup_field_info(type->get_name(), field_name); @@ -630,7 +629,7 @@ Val* Compiler::get_field_of_bitfield(const BitFieldType* type, Val* object, const std::string& field_name, Env* env) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); Val* result = nullptr; auto bitfield_info = m_ts.lookup_bitfield_info(type->get_name(), field_name); result = fe->alloc_val(bitfield_info.result_type, object, bitfield_info.offset, @@ -653,7 +652,7 @@ Val* Compiler::get_field_of_bitfield(const BitFieldType* type, * location. Otherwise set! or & won't work. */ Val* Compiler::compile_deref(const goos::Object& form, const goos::Object& _rest, Env* env) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); if (_rest.is_empty_list()) { throw_compiler_error(form, "-> must get at least one argument"); } @@ -859,7 +858,7 @@ Val* Compiler::compile_the_as(const goos::Object& form, const goos::Object& rest va_check(form, args, {{}, {}}, {}); auto desired_ts = parse_typespec(args.unnamed.at(0)); auto base = compile_error_guard(args.unnamed.at(1), env); - auto result = get_parent_env_of_type(env)->alloc_val(desired_ts, base); + auto result = env->function_env()->alloc_val(desired_ts, base); if (base->settable()) { result->mark_as_settable(); } @@ -888,7 +887,7 @@ Val* Compiler::compile_the(const goos::Object& form, const goos::Object& rest, E result->set_type(desired_ts); return result; } else { - result = get_parent_env_of_type(env)->alloc_val(desired_ts, base); + result = env->function_env()->alloc_val(desired_ts, base); return result; } } @@ -898,7 +897,7 @@ Val* Compiler::compile_the(const goos::Object& form, const goos::Object& rest, E } } - auto result = get_parent_env_of_type(env)->alloc_val(desired_ts, base); + auto result = env->function_env()->alloc_val(desired_ts, base); if (base->settable()) { result->mark_as_settable(); } @@ -1020,7 +1019,7 @@ Val* Compiler::compile_static_new(const goos::Object& form, if (unquoted.is_symbol() && (unquoted.as_symbol()->name == "boxed-array" || unquoted.as_symbol()->name == "array" || unquoted.as_symbol()->name == "inline-array")) { - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto sr = compile_static(form, env); auto result = fe->alloc_val(sr.reference(), sr.typespec()); return result; @@ -1045,7 +1044,7 @@ Val* Compiler::compile_stack_new(const goos::Object& form, Env* env, bool call_constructor) { auto type_of_object = parse_typespec(unquote(type)); - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); if (type_of_object == TypeSpec("inline-array") || type_of_object == TypeSpec("array")) { if (call_constructor) { throw_compiler_error(form, "Constructing stack arrays is not yet supported"); @@ -1166,7 +1165,7 @@ Val* Compiler::compile_new(const goos::Object& form, const goos::Object& _rest, Val* Compiler::compile_car(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); va_check(form, args, {{}}, {}); - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto pair = compile_error_guard(args.unnamed.at(0), env); if (pair->type() != m_ts.make_typespec("object")) { typecheck(form, m_ts.make_typespec("pair"), pair->type(), "Type of argument to car"); @@ -1179,7 +1178,7 @@ Val* Compiler::compile_car(const goos::Object& form, const goos::Object& rest, E Val* Compiler::compile_cdr(const goos::Object& form, const goos::Object& rest, Env* env) { auto args = get_va(form, rest); va_check(form, args, {{}}, {}); - auto fe = get_parent_env_of_type(env); + auto fe = env->function_env(); auto pair = compile_error_guard(args.unnamed.at(0), env); if (pair->type() != m_ts.make_typespec("object")) { typecheck(form, m_ts.make_typespec("pair"), pair->type(), "Type of argument to cdr"); diff --git a/goalc/make/MakeSystem.cpp b/goalc/make/MakeSystem.cpp index ac5c264d87..c8a9451cc5 100644 --- a/goalc/make/MakeSystem.cpp +++ b/goalc/make/MakeSystem.cpp @@ -65,7 +65,7 @@ void MakeSystem::load_project_file(const std::string& file_path) { // read the file auto data = m_goos.reader.read_from_file({file_path}); // interpret it, which will call various handlers. - m_goos.eval(data, m_goos.global_environment.as_env()); + m_goos.eval(data, m_goos.global_environment.as_env_ptr()); } goos::Object MakeSystem::handle_defstep(const goos::Object& form, diff --git a/goalc/regalloc/IRegSet.h b/goalc/regalloc/IRegSet.h index f7fd61a40b..e808928c79 100644 --- a/goalc/regalloc/IRegSet.h +++ b/goalc/regalloc/IRegSet.h @@ -19,7 +19,7 @@ class IRegSet { public: - IRegSet() = default; + IRegSet() { m_data.reserve(4); } /*! * Add the given ireg to the set. diff --git a/test/test_goos.cpp b/test/test_goos.cpp index 7d363428e6..ff8191da3f 100644 --- a/test/test_goos.cpp +++ b/test/test_goos.cpp @@ -11,7 +11,7 @@ using namespace goos; namespace { // helper to evaluate a string as a goos expression. std::string e(Interpreter& interp, const std::string& in) { - return interp.eval(interp.reader.read_from_string(in), interp.global_environment.as_env()) + return interp.eval(interp.reader.read_from_string(in), interp.global_environment.as_env_ptr()) .print(); } } // namespace diff --git a/test/test_reader.cpp b/test/test_reader.cpp index 58fa4c113f..550f0d8629 100644 --- a/test/test_reader.cpp +++ b/test/test_reader.cpp @@ -349,8 +349,6 @@ TEST(GoosReader, TextDb) { .as_pair() ->cdr.as_pair() ->car; - std::string expected = "text from " + - file_util::get_file_path({"test", "test_data", "test_reader_file0.gc"}) + - ", line: 5\n(1 2 3 4)\n"; + std::string expected = "test/test_data/test_reader_file0.gc, line: 5\n(1 2 3 4)\n ^\n"; EXPECT_EQ(expected, reader.db.get_info_for(result)); }